summaryrefslogtreecommitdiffstats
path: root/sw/source/core/view/viewsh.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/view/viewsh.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/view/viewsh.cxx')
-rw-r--r--sw/source/core/view/viewsh.cxx2849
1 files changed, 2849 insertions, 0 deletions
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
new file mode 100644
index 0000000000..7a322ed7a4
--- /dev/null
+++ b/sw/source/core/view/viewsh.cxx
@@ -0,0 +1,2849 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <officecfg/Office/Common.hxx>
+#include <config_wasm_strip.h>
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/progress.hxx>
+#include <svx/srchdlg.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/ipclient.hxx>
+#include <sal/log.hxx>
+#include <drawdoc.hxx>
+#include <swwait.hxx>
+#include <crsrsh.hxx>
+#include <doc.hxx>
+#include <IDocumentDeviceAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentOutlineNodes.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentState.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <viewimp.hxx>
+#include <frmtool.hxx>
+#include <viewopt.hxx>
+#include <dview.hxx>
+#include <swregion.hxx>
+#include <hints.hxx>
+#include <docufld.hxx>
+#include <txtfrm.hxx>
+#include <layact.hxx>
+#include <mdiexp.hxx>
+#include <fntcache.hxx>
+#include <ptqueue.hxx>
+#include <docsh.hxx>
+#include <bookmark.hxx>
+#include <ndole.hxx>
+#include <ndindex.hxx>
+#include <accmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <accessibilityoptions.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <pagepreviewlayout.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <DocumentSettingManager.hxx>
+#include <DocumentRedlineManager.hxx>
+#include <DocumentLayoutManager.hxx>
+
+#include <unotxdoc.hxx>
+#include <view.hxx>
+#include <PostItMgr.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/svdpagv.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <tools/UnitConversion.hxx>
+
+#if !HAVE_FEATURE_DESKTOP
+#include <vcl/sysdata.hxx>
+#endif
+
+#include <frameformats.hxx>
+#include <fmtcntnt.hxx>
+
+bool SwViewShell::sbLstAct = false;
+ShellResource *SwViewShell::spShellRes = nullptr;
+vcl::DeleteOnDeinit<std::shared_ptr<weld::Window>> SwViewShell::spCareDialog {};
+
+static bool bInSizeNotify = false;
+
+
+using namespace ::com::sun::star;
+
+void SwViewShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow ) {
+
+ //tdf#118621 - Optionally disable floating header/footer menu
+ if ( bShow )
+ bShow = GetViewOptions()->IsUseHeaderFooterMenu();
+
+ if ( eControl == FrameControlType::Header )
+ mbShowHeaderSeparator = bShow;
+ else
+ mbShowFooterSeparator = bShow;
+}
+
+void SwViewShell::ToggleHeaderFooterEdit()
+{
+ mbHeaderFooterEdit = !mbHeaderFooterEdit;
+ if ( !mbHeaderFooterEdit )
+ {
+ SetShowHeaderFooterSeparator( FrameControlType::Header, false );
+ SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
+ }
+
+ // Avoid corner case
+ if ( ( GetViewOptions()->IsUseHeaderFooterMenu() ) &&
+ ( !IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
+ !IsShowHeaderFooterSeparator( FrameControlType::Footer ) ) )
+ {
+ mbHeaderFooterEdit = false;
+ }
+
+ InvalidatePageAndHFSubsidiaryLines();
+}
+
+// Invalidate Subsidiary Lines around headers/footers and page frames to repaint
+void SwViewShell::InvalidatePageAndHFSubsidiaryLines()
+{
+ RectangleVector aInvalidRects;
+ SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
+ while (pPg)
+ {
+ pPg->AddSubsidiaryLinesBounds(*this, aInvalidRects);
+ pPg = static_cast<SwPageFrame*>(pPg->GetNext());
+ }
+
+ for (const auto &rRect : aInvalidRects)
+ GetWin()->Invalidate(rRect);
+}
+
+void SwViewShell::setOutputToWindow(bool bOutputToWindow)
+{
+ mbOutputToWindow = bOutputToWindow;
+}
+
+bool SwViewShell::isOutputToWindow() const
+{
+ return mbOutputToWindow;
+}
+
+void SwViewShell::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwViewShell"));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+static void
+lcl_PaintTransparentFormControls(SwViewShell const & rShell, SwRect const& rRect)
+{
+ // Direct paint has been performed: the background of transparent child
+ // windows has been painted, so need to paint the child windows now.
+ if (rShell.GetWin())
+ {
+ vcl::Window& rWindow = *(rShell.GetWin());
+ const tools::Rectangle aRectanglePixel(rShell.GetOut()->LogicToPixel(rRect.SVRect()));
+ PaintTransparentChildren(rWindow, aRectanglePixel);
+ }
+}
+
+// #i72754# 2nd set of Pre/PostPaints
+// This time it uses the lock counter (mPrePostPaintRegions empty/non-empty) to allow only one activation
+// and deactivation and mpPrePostOutDev to remember the OutDev from the BeginDrawLayers
+// call. That way, all places where paint take place can be handled the same way, even
+// when calling other paint methods. This is the case at the places where SW paints
+// buffered into VDevs to avoid flicker. It is in general problematic and should be
+// solved once using the BufferedOutput functionality of the DrawView.
+
+void SwViewShell::PrePaint()
+{
+ // forward PrePaint event from VCL Window to DrawingLayer
+ if(HasDrawView())
+ {
+ Imp()->GetDrawView()->PrePaint();
+ }
+}
+
+void SwViewShell::DLPrePaint2(const vcl::Region& rRegion)
+{
+ if(mPrePostPaintRegions.empty())
+ {
+ mPrePostPaintRegions.push( rRegion );
+ // #i75172# ensure DrawView to use DrawingLayer bufferings
+ if ( !HasDrawView() )
+ MakeDrawView();
+
+ // Prefer window; if not available, get mpOut (e.g. printer)
+ const bool bWindow = GetWin() && !comphelper::LibreOfficeKit::isActive() && !isOutputToWindow();
+ mpPrePostOutDev = bWindow ? GetWin()->GetOutDev() : GetOut();
+
+ // #i74769# use SdrPaintWindow now direct
+ mpTargetPaintWindow = Imp()->GetDrawView()->BeginDrawLayers(mpPrePostOutDev, rRegion);
+ OSL_ENSURE(mpTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
+
+ // #i74769# if prerender, save OutDev and redirect to PreRenderDevice
+ if(mpTargetPaintWindow->GetPreRenderDevice())
+ {
+ mpBufferedOut = mpOut;
+ mpOut = &(mpTargetPaintWindow->GetTargetOutputDevice());
+ }
+ else if (isOutputToWindow())
+ // In case mpOut is used without buffering and we're not printing, need to set clipping.
+ mpOut->SetClipRegion(rRegion);
+
+ // remember original paint MapMode for wrapped FlyFrame paints
+ maPrePostMapMode = mpOut->GetMapMode();
+ }
+ else
+ {
+ // region needs to be updated to the given one
+ if( mPrePostPaintRegions.top() != rRegion )
+ Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, rRegion);
+ mPrePostPaintRegions.push( rRegion );
+ }
+}
+
+void SwViewShell::DLPostPaint2(bool bPaintFormLayer)
+{
+ OSL_ENSURE(!mPrePostPaintRegions.empty(), "SwViewShell::DLPostPaint2: Pre/PostPaint encapsulation broken (!)");
+
+ if( mPrePostPaintRegions.size() > 1 )
+ {
+ vcl::Region current = std::move(mPrePostPaintRegions.top());
+ mPrePostPaintRegions.pop();
+ if( current != mPrePostPaintRegions.top())
+ Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, mPrePostPaintRegions.top());
+ return;
+ }
+ mPrePostPaintRegions.pop(); // clear
+ if(nullptr != mpTargetPaintWindow)
+ {
+ // #i74769# restore buffered OutDev
+ if(mpTargetPaintWindow->GetPreRenderDevice())
+ {
+ mpOut = mpBufferedOut;
+ }
+
+ // #i74769# use SdrPaintWindow now direct
+ Imp()->GetDrawView()->EndDrawLayers(*mpTargetPaintWindow, bPaintFormLayer);
+ mpTargetPaintWindow = nullptr;
+ }
+}
+// end of Pre/PostPaints
+
+void SwViewShell::ImplEndAction( const bool bIdleEnd )
+{
+ // Nothing to do for the printer?
+ if ( !GetWin() || IsPreview() )
+ {
+ mbPaintWorks = true;
+ UISizeNotify();
+ // tdf#101464 print preview may generate events if another view shell
+ // performs layout...
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (IsPreview() && Imp()->IsAccessible())
+ {
+ Imp()->FireAccessibleEvents();
+ }
+#endif
+ return;
+ }
+
+ mbInEndAction = true;
+ //will this put the EndAction of the last shell in the sequence?
+
+ SwViewShell::sbLstAct = true;
+ for(SwViewShell& rShell : GetRingContainer())
+ {
+ if(&rShell != this && rShell.ActionPend())
+ {
+ SwViewShell::sbLstAct = false;
+ break;
+ }
+ }
+
+ const bool bIsShellForCheckViewLayout = ( this == GetLayout()->GetCurrShell() );
+
+ CurrShell aCurr( this );
+ if ( Imp()->HasDrawView() && !Imp()->GetDrawView()->areMarkHandlesHidden() )
+ Imp()->StartAction();
+
+ if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
+ Imp()->DeletePaintRegion();
+
+ const bool bExtraData = ::IsExtraData( GetDoc() );
+
+ if ( !bIdleEnd )
+ {
+ SwLayAction aAction( GetLayout(), Imp() );
+ aAction.SetComplete( false );
+ if ( mnLockPaint )
+ aAction.SetPaint( false );
+ aAction.SetInputType( VclInputFlags::KEYBOARD );
+ aAction.Action(GetWin()->GetOutDev());
+ }
+
+ if ( bIsShellForCheckViewLayout )
+ GetLayout()->CheckViewLayout( GetViewOptions(), &maVisArea );
+
+ //If we don't call Paints, we wait for the Paint of the system.
+ //Then the clipping is set correctly; e.g. shifting of a Draw object
+ if ( Imp()->HasPaintRegion() ||
+ maInvalidRect.HasArea() ||
+ bExtraData )
+ {
+ if ( !mnLockPaint )
+ {
+ SolarMutexGuard aGuard;
+
+ bool bPaintsFromSystem = maInvalidRect.HasArea();
+ GetWin()->PaintImmediately();
+ if ( maInvalidRect.HasArea() )
+ {
+ if ( bPaintsFromSystem )
+ Imp()->AddPaintRect( maInvalidRect );
+
+ ResetInvalidRect();
+ bPaintsFromSystem = true;
+ }
+ mbPaintWorks = true;
+
+ std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();
+
+ //JP 27.11.97: what hid the selection, must also Show it,
+ // else we get Paint errors!
+ // e.g. additional mode, page half visible vertically, in the
+ // middle a selection and with another cursor jump to left
+ // right border. Without ShowCursor the selection disappears.
+ bool bShowCursor = oRegion && dynamic_cast<const SwCursorShell*>(this) != nullptr;
+ if( bShowCursor )
+ static_cast<SwCursorShell*>(this)->HideCursors();
+
+ if ( oRegion )
+ {
+ SwRootFrame* pCurrentLayout = GetLayout();
+
+ oRegion->LimitToOrigin();
+ oRegion->Compress( SwRegionRects::CompressFuzzy );
+
+ while ( !oRegion->empty() )
+ {
+ SwRect aRect( oRegion->back() );
+ oRegion->pop_back();
+
+ if (GetWin()->SupportsDoubleBuffering())
+ InvalidateWindows(aRect);
+ else
+ {
+ // #i75172# begin DrawingLayer paint
+ // need to do begin/end DrawingLayer preparation for each single rectangle of the
+ // repaint region. I already tried to prepare only once for the whole Region. This
+ // seems to work (and does technically) but fails with transparent objects. Since the
+ // region given to BeginDrawLayers() defines the clip region for DrawingLayer paint,
+ // transparent objects in the single rectangles will indeed be painted multiple times.
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ DLPrePaint2(vcl::Region(aRect.SVRect()));
+ }
+
+ if ( bPaintsFromSystem )
+ PaintDesktop(*GetOut(), aRect);
+ if (!comphelper::LibreOfficeKit::isActive())
+ pCurrentLayout->PaintSwFrame( *mpOut, aRect );
+ else
+ pCurrentLayout->GetCurrShell()->InvalidateWindows(aRect);
+
+ // #i75172# end DrawingLayer paint
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ DLPostPaint2(true);
+ }
+ }
+
+ lcl_PaintTransparentFormControls(*this, aRect); // i#107365
+ }
+ }
+ if( bShowCursor )
+ static_cast<SwCursorShell*>(this)->ShowCursors( true );
+ }
+ else
+ {
+ Imp()->DeletePaintRegion();
+ mbPaintWorks = true;
+ }
+ }
+ else
+ mbPaintWorks = true;
+
+ mbInEndAction = false;
+ SwViewShell::sbLstAct = false;
+ Imp()->EndAction();
+
+ //We artificially end the action here to enable the automatic scrollbars
+ //to adjust themselves correctly
+ //EndAction sends a Notify, and that must call Start-/EndAction to
+ //adjust the scrollbars correctly
+ --mnStartAction;
+ UISizeNotify();
+ ++mnStartAction;
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( Imp()->IsAccessible() )
+ Imp()->FireAccessibleEvents();
+#endif
+}
+
+void SwViewShell::ImplStartAction()
+{
+ mbPaintWorks = false;
+ Imp()->StartAction();
+}
+
+void SwViewShell::ImplLockPaint()
+{
+ if ( GetWin() && GetWin()->IsVisible() && !comphelper::LibreOfficeKit::isActive())
+ GetWin()->EnablePaint( false ); //Also cut off the controls.
+ Imp()->LockPaint();
+}
+
+void SwViewShell::ImplUnlockPaint(std::vector<LockPaintReason>& rReasons, bool bVirDev)
+{
+ CurrShell aCurr( this );
+ if ( GetWin() && GetWin()->IsVisible() )
+ {
+ if ( (bInSizeNotify || bVirDev ) && VisArea().HasArea() && !comphelper::LibreOfficeKit::isActive())
+ {
+ //Refresh with virtual device to avoid flickering.
+ VclPtrInstance<VirtualDevice> pVout( *mpOut );
+ pVout->SetMapMode( mpOut->GetMapMode() );
+ Size aSize( VisArea().SSize() );
+ aSize.AdjustWidth(20 );
+ aSize.AdjustHeight(20 );
+ if( pVout->SetOutputSize( aSize ) )
+ {
+ GetWin()->EnablePaint( true );
+ GetWin()->Validate();
+
+ Imp()->UnlockPaint();
+ pVout->SetLineColor( mpOut->GetLineColor() );
+ pVout->SetFillColor( mpOut->GetFillColor() );
+
+ // #i72754# start Pre/PostPaint encapsulation before mpOut is changed to the buffering VDev
+ const vcl::Region aRepaintRegion(VisArea().SVRect());
+ DLPrePaint2(aRepaintRegion);
+
+ OutputDevice *pOld = mpOut;
+ mpOut = pVout.get();
+ Paint(*mpOut, VisArea().SVRect());
+ mpOut = pOld;
+ mpOut->DrawOutDev( VisArea().Pos(), aSize,
+ VisArea().Pos(), aSize, *pVout );
+
+ // #i72754# end Pre/PostPaint encapsulation when mpOut is back and content is painted
+ DLPostPaint2(true);
+
+ lcl_PaintTransparentFormControls(*this, VisArea()); // fdo#63949
+ }
+ else
+ {
+ Imp()->UnlockPaint();
+ GetWin()->EnablePaint( true );
+ InvalidateAll(rReasons);
+ }
+ pVout.disposeAndClear();
+ }
+ else
+ {
+ Imp()->UnlockPaint();
+ GetWin()->EnablePaint( true );
+ InvalidateAll(rReasons);
+ }
+ }
+ else
+ Imp()->UnlockPaint();
+}
+
+namespace
+{
+ std::string_view to_string(LockPaintReason eReason)
+ {
+ switch(eReason)
+ {
+ case LockPaintReason::ViewLayout:
+ return "ViewLayout";
+ case LockPaintReason::OuterResize:
+ return "OuterResize";
+ case LockPaintReason::Undo:
+ return "Undo";
+ case LockPaintReason::Redo:
+ return "Redo";
+ case LockPaintReason::OutlineFolding:
+ return "OutlineFolding";
+ case LockPaintReason::EndSdrCreate:
+ return "EndSdrCreate";
+ case LockPaintReason::SwLayIdle:
+ return "SwLayIdle";
+ case LockPaintReason::InvalidateLayout:
+ return "InvalidateLayout";
+ case LockPaintReason::StartDrag:
+ return "StartDrag";
+ case LockPaintReason::DataChanged:
+ return "DataChanged";
+ case LockPaintReason::InsertFrame:
+ return "InsertFrame";
+ case LockPaintReason::GotoPage:
+ return "GotoPage";
+ case LockPaintReason::InsertGraphic:
+ return "InsertGraphic";
+ case LockPaintReason::SetZoom:
+ return "SetZoom";
+ case LockPaintReason::ExampleFrame:
+ return "ExampleFram";
+ }
+ return "";
+ };
+}
+
+void SwViewShell::InvalidateAll(std::vector<LockPaintReason>& rReasons)
+{
+ assert(!rReasons.empty() && "there must be a reason to InvalidateAll");
+
+ for (const auto& reason : rReasons)
+ SAL_INFO("sw.core", "InvalidateAll because of: " << to_string(reason));
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // https://github.com/CollaboraOnline/online/issues/6379
+ // ditch OuterResize as a reason to invalidate all in the online case
+ std::erase(rReasons, LockPaintReason::OuterResize);
+ }
+
+ if (!rReasons.empty())
+ GetWin()->Invalidate(InvalidateFlags::Children);
+ rReasons.clear();
+}
+
+bool SwViewShell::AddPaintRect( const SwRect & rRect )
+{
+ bool bRet = false;
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if( rSh.Imp() )
+ {
+ if ( rSh.IsPreview() && rSh.GetWin() )
+ ::RepaintPagePreview( &rSh, rRect );
+ else
+ bRet |= rSh.Imp()->AddPaintRect( rRect );
+ }
+ }
+ return bRet;
+}
+
+void SwViewShell::InvalidateWindows( const SwRect &rRect )
+{
+ if ( Imp()->IsCalcLayoutProgress() )
+ return;
+
+ if(comphelper::LibreOfficeKit::isActive())
+ {
+ // If we are inside tiled painting, invalidations are ignored.
+ // Ignore them right now to save work, but also to avoid the problem
+ // that this state could be reset before FlushPendingLOKInvalidateTiles()
+ // gets called.
+ if(comphelper::LibreOfficeKit::isTiledPainting())
+ return;
+ // First collect all invalidations and perform them only later,
+ // otherwise the number of Invalidate() calls would be at least
+ // O(n^2) if not worse. The problem is that if any change in a document
+ // is made, SwEditShell::EndAllAction() is called, which calls EndAction()
+ // for every view. And every view does it own handling of paint rectangles,
+ // and then calls InvalidateWindows() based on that. On then this code
+ // would call Invalidate() for all views for each rectangle.
+ // So collect the rectangles, avoid duplicates (which there usually will
+ // be many because of the repetitions), FlushPendingLOKInvalidateTiles()
+ // will collect all rectangles from all related views, compress them
+ // and only with those relatively few rectangle it'd call Invalidate()
+ // for all views.
+ Imp()->AddPendingLOKInvalidation(rRect);
+ return;
+ }
+
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if ( rSh.GetWin() )
+ {
+ if ( rSh.IsPreview() )
+ ::RepaintPagePreview( &rSh, rRect );
+ // In case of tiled rendering, invalidation is wanted even if
+ // the rectangle is outside the visual area.
+ else if ( rSh.VisArea().Overlaps( rRect ) || comphelper::LibreOfficeKit::isActive() )
+ rSh.GetWin()->Invalidate( rRect.SVRect() );
+ }
+ }
+}
+
+void SwViewShell::FlushPendingLOKInvalidateTiles()
+{
+ assert(comphelper::LibreOfficeKit::isActive());
+ SwRegionRects rects;
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ std::vector<SwRect> tmpRects = rSh.Imp()->TakePendingLOKInvalidations();
+ rects.insert( rects.end(), tmpRects.begin(), tmpRects.end());
+ }
+ rects.Compress( SwRegionRects::CompressFuzzy );
+ if(rects.empty())
+ return;
+ // This is basically the loop from SwViewShell::InvalidateWindows().
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if ( rSh.GetWin() )
+ {
+ if ( rSh.IsPreview() )
+ {
+ for( const SwRect& rect : rects )
+ ::RepaintPagePreview( &rSh, rect );
+ }
+ else
+ {
+ for( const SwRect& rect : rects )
+ rSh.GetWin()->Invalidate( rect.SVRect() );
+ }
+ }
+ }
+}
+
+const SwRect& SwViewShell::VisArea() const
+{
+ // when using the tiled rendering, consider the entire document as our
+ // visible area
+ return comphelper::LibreOfficeKit::isActive()? GetLayout()->getFrameArea(): maVisArea;
+}
+
+void SwViewShell::MakeVisible( const SwRect &rRect )
+{
+ if ( !(!VisArea().Contains( rRect ) || IsScrollMDI( this, rRect ) || GetCareDialog(*this)) )
+ return;
+
+ if ( IsViewLocked() )
+ return;
+
+ if( mpWin )
+ {
+ const SwFrame* pRoot = GetLayout();
+ int nLoopCnt = 3;
+ tools::Long nOldH;
+ do{
+ nOldH = pRoot->getFrameArea().Height();
+ StartAction();
+ ScrollMDI( this, rRect, USHRT_MAX, USHRT_MAX );
+ EndAction();
+ } while( nOldH != pRoot->getFrameArea().Height() && nLoopCnt-- );
+ }
+#if OSL_DEBUG_LEVEL > 0
+ else
+ {
+ //MA: 04. Nov. 94, no one needs this, does one?
+ OSL_ENSURE( false, "Is MakeVisible still needed for printers?" );
+ }
+
+#endif
+}
+
+weld::Window* SwViewShell::CareChildWin(SwViewShell const & rVSh)
+{
+ if (!rVSh.mpSfxViewShell)
+ return nullptr;
+#if HAVE_FEATURE_DESKTOP
+ const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId();
+ SfxViewFrame& rVFrame = rVSh.mpSfxViewShell->GetViewFrame();
+ SfxChildWindow* pChWin = rVFrame.GetChildWindow( nId );
+ if (!pChWin)
+ return nullptr;
+ weld::DialogController* pController = pChWin->GetController().get();
+ if (!pController)
+ return nullptr;
+ weld::Window* pWin = pController->getDialog();
+ if (pWin && pWin->get_visible())
+ return pWin;
+#endif
+ return nullptr;
+}
+
+Point SwViewShell::GetPagePos( sal_uInt16 nPageNum ) const
+{
+ return GetLayout()->GetPagePos( nPageNum );
+}
+
+sal_uInt16 SwViewShell::GetNumPages() const
+{
+ //It is possible that no layout exists when the method from
+ //root-Ctor is called.
+ return GetLayout() ? GetLayout()->GetPageNum() : 0;
+}
+
+bool SwViewShell::IsDummyPage( sal_uInt16 nPageNum ) const
+{
+ return GetLayout() && GetLayout()->IsDummyPage( nPageNum );
+}
+
+/**
+ * Forces update of each field.
+ * It notifies all fields with pNewHt. If that is 0 (default), the field
+ * type is sent (???).
+ * @param[in] bCloseDB Passed in to GetDoc()->UpdateFields. [TODO] Purpose???
+ */
+void SwViewShell::UpdateFields(bool bCloseDB)
+{
+ CurrShell aCurr( this );
+
+ auto pCursorShell = dynamic_cast<SwCursorShell*>( this );
+ if ( pCursorShell )
+ pCursorShell->StartAction();
+ else
+ StartAction();
+
+ GetDoc()->getIDocumentFieldsAccess().UpdateFields(bCloseDB);
+
+ if ( pCursorShell )
+ pCursorShell->EndAction();
+ else
+ EndAction();
+}
+
+void SwViewShell::UpdateOleObjectPreviews()
+{
+ SwDoc* pDoc = GetDoc();
+ for(sw::SpzFrameFormat* pFormat: *pDoc->GetSpzFrameFormats())
+ {
+ if (pFormat->Which() != RES_FLYFRMFMT)
+ {
+ continue;
+ }
+
+ const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
+ if (!pNodeIndex || !pNodeIndex->GetNodes().IsDocNodes())
+ {
+ continue;
+ }
+
+ SwNode* pNode = pDoc->GetNodes()[pNodeIndex->GetIndex() + 1];
+ SwOLENode* pOleNode = pNode->GetOLENode();
+ if (!pOleNode)
+ {
+ continue;
+ }
+
+ SwOLEObj& rOleObj = pOleNode->GetOLEObj();
+ svt::EmbeddedObjectRef& rObject = rOleObj.GetObject();
+ rObject.UpdateReplacement( true );
+ // Trigger the repaint.
+ pOleNode->SetChanged();
+ }
+}
+
+/** update all charts for which any table exists */
+void SwViewShell::UpdateAllCharts()
+{
+ CurrShell aCurr( this );
+ // Start-/EndAction handled in the SwDoc-Method!
+ GetDoc()->UpdateAllCharts();
+}
+
+bool SwViewShell::HasCharts() const
+{
+ bool bRet = false;
+ SwNodeIndex aIdx( *GetDoc()->GetNodes().GetEndOfAutotext().
+ StartOfSectionNode(), 1 );
+ while (aIdx.GetNode().GetStartNode())
+ {
+ ++aIdx;
+ const SwOLENode *pNd = aIdx.GetNode().GetOLENode();
+ if( pNd && !pNd->GetChartTableName().isEmpty() )
+ {
+ bRet = true;
+ break;
+ }
+ }
+ return bRet;
+}
+
+void SwViewShell::LayoutIdle()
+{
+ if( !mpOpt->IsIdle() || !GetWin() || HasDrawViewDrag() )
+ return;
+
+ //No idle when printing is going on.
+ for(const SwViewShell& rSh : GetRingContainer())
+ {
+ if ( !rSh.GetWin() )
+ return;
+ }
+
+ CurrShell aCurr( this );
+
+#ifdef DBG_UTIL
+ // If Test5 has been set, the IdleFormatter is disabled.
+ if( mpOpt->IsTest5() )
+ return;
+#endif
+
+ {
+ // Preserve top of the text frame cache.
+ SwSaveSetLRUOfst aSaveLRU;
+ // #125243# there are lots of stacktraces indicating that Imp() returns NULL
+ // this SwViewShell seems to be invalid - but it's not clear why
+ // this return is only a workaround!
+ OSL_ENSURE(Imp(), "SwViewShell already deleted?");
+ if(!Imp())
+ return;
+ SwLayIdle aIdle( GetLayout(), Imp() );
+ }
+}
+
+static void lcl_InvalidateAllContent( SwViewShell& rSh, SwInvalidateFlags nInv )
+{
+ auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh);
+ if ( pCursorShell )
+ pCursorShell->StartAction();
+ else
+ rSh.StartAction();
+ rSh.GetLayout()->InvalidateAllContent( nInv );
+ if ( pCursorShell )
+ pCursorShell->EndAction();
+ else
+ rSh.EndAction();
+
+ rSh.GetDoc()->getIDocumentState().SetModified();
+}
+
+/** local method to invalidate/re-calculate positions of floating screen
+ * objects (Writer fly frame and drawing objects), which are anchored
+ * to paragraph or to character. #i11860#
+ */
+static void lcl_InvalidateAllObjPos( SwViewShell &_rSh )
+{
+ auto pCursorShell = dynamic_cast<SwCursorShell*>( &_rSh);
+ if ( pCursorShell )
+ pCursorShell->StartAction();
+ else
+ _rSh.StartAction();
+
+ _rSh.GetLayout()->InvalidateAllObjPos();
+
+ if ( pCursorShell )
+ pCursorShell->EndAction();
+ else
+ _rSh.EndAction();
+
+ _rSh.GetDoc()->getIDocumentState().SetModified();
+}
+
+void SwViewShell::SetParaSpaceMax( bool bNew )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) != bNew )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::PARA_SPACE_MAX, bNew );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+void SwViewShell::SetParaSpaceMaxAtPages( bool bNew )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) != bNew )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, bNew );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+void SwViewShell::SetTabCompat( bool bNew )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if( rIDSA.get(DocumentSettingId::TAB_COMPAT) != bNew )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::TAB_COMPAT, bNew );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+void SwViewShell::SetAddExtLeading( bool bNew )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if ( rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) != bNew )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::ADD_EXT_LEADING, bNew );
+ SwDrawModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
+ if ( pTmpDrawModel )
+ pTmpDrawModel->SetAddExtLeading( bNew );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+/** Sets if paragraph and table spacing is added at bottom of table cells.
+ * #106629#
+ * @param[in] (bool) setting of the new value
+ */
+void SwViewShell::SetAddParaSpacingToTableCells( bool _bAddParaSpacingToTableCells )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if (rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells
+ || rIDSA.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells)
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
+ // note: the dialog can't change the value to indeterminate, so only false/false and true/true
+ rIDSA.set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+/**
+ * Sets if former formatting of text lines with proportional line spacing should used.
+ * #i11859#
+ * @param[in] (bool) setting of the new value
+ */
+void SwViewShell::SetUseFormerLineSpacing( bool _bUseFormerLineSpacing )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if ( rIDSA.get(DocumentSettingId::OLD_LINE_SPACING) != _bUseFormerLineSpacing )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::OLD_LINE_SPACING, _bUseFormerLineSpacing );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+/**
+ * Sets IDocumentSettingAccess if former object positioning should be used.
+ * #i11860#
+ * @param[in] (bool) setting the new value
+ */
+void SwViewShell::SetUseFormerObjectPositioning( bool _bUseFormerObjPos )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if ( rIDSA.get(DocumentSettingId::USE_FORMER_OBJECT_POS) != _bUseFormerObjPos )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::USE_FORMER_OBJECT_POS, _bUseFormerObjPos );
+ lcl_InvalidateAllObjPos( *this );
+ }
+}
+
+// #i28701#
+void SwViewShell::SetConsiderWrapOnObjPos( bool _bConsiderWrapOnObjPos )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if ( rIDSA.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) != _bConsiderWrapOnObjPos )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, _bConsiderWrapOnObjPos );
+ lcl_InvalidateAllObjPos( *this );
+ }
+}
+
+void SwViewShell::SetUseFormerTextWrapping( bool _bUseFormerTextWrapping )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if ( rIDSA.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) != _bUseFormerTextWrapping )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, _bUseFormerTextWrapping );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+// #i45491#
+void SwViewShell::SetDoNotJustifyLinesWithManualBreak( bool _bDoNotJustifyLinesWithManualBreak )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if ( rIDSA.get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK) != _bDoNotJustifyLinesWithManualBreak )
+ {
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+ rIDSA.set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, _bDoNotJustifyLinesWithManualBreak );
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent( *this, nInv );
+ }
+}
+
+void SwViewShell::SetProtectForm( bool _bProtectForm )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ rIDSA.set(DocumentSettingId::PROTECT_FORM, _bProtectForm );
+}
+
+void SwViewShell::SetMsWordCompTrailingBlanks( bool _bMsWordCompTrailingBlanks )
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if (rIDSA.get(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS) != _bMsWordCompTrailingBlanks)
+ {
+ SwWait aWait(*GetDoc()->GetDocShell(), true);
+ rIDSA.set(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS, _bMsWordCompTrailingBlanks);
+ const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
+ lcl_InvalidateAllContent(*this, nInv);
+ }
+}
+
+void SwViewShell::SetSubtractFlysAnchoredAtFlys(bool bSubtractFlysAnchoredAtFlys)
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ rIDSA.set(DocumentSettingId::SUBTRACT_FLYS, bSubtractFlysAnchoredAtFlys);
+}
+
+void SwViewShell::SetEmptyDbFieldHidesPara(bool bEmptyDbFieldHidesPara)
+{
+ IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
+ if (rIDSA.get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA) == bEmptyDbFieldHidesPara)
+ return;
+
+ SwWait aWait(*GetDoc()->GetDocShell(), true);
+ rIDSA.set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, bEmptyDbFieldHidesPara);
+ StartAction();
+ GetDoc()->getIDocumentState().SetModified();
+ for (auto const & pFieldType : *GetDoc()->getIDocumentFieldsAccess().GetFieldTypes())
+ {
+ if(pFieldType->Which() == SwFieldIds::Database)
+ pFieldType->UpdateFields();
+ }
+ EndAction();
+}
+
+void SwViewShell::Reformat()
+{
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+
+ // we go for safe: get rid of the old font information,
+ // when the printer resolution or zoom factor changes.
+ // Init() and Reformat() are the safest locations.
+ pFntCache->Flush( );
+
+ if( GetLayout()->IsCallbackActionEnabled() )
+ {
+ StartAction();
+ GetLayout()->InvalidateAllContent( SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea );
+ EndAction();
+ }
+}
+
+void SwViewShell::ChgNumberDigits()
+{
+ SdrModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
+ if ( pTmpDrawModel )
+ pTmpDrawModel->ReformatAllTextObjects();
+ Reformat();
+}
+
+void SwViewShell::CalcLayout()
+{
+ // extremely likely to be a Bad Idea to call this without StartAction
+ // (except the Page Preview apparently only has a non-subclassed ViewShell)
+ assert((typeid(*this) == typeid(SwViewShell)) || mnStartAction);
+
+ CurrShell aCurr( this );
+ SwWait aWait( *GetDoc()->GetDocShell(), true );
+
+ // Preserve top of the text frame cache.
+ SwSaveSetLRUOfst aSaveLRU;
+
+ //switch on Progress when none is running yet.
+ const bool bEndProgress = SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) == nullptr;
+ if ( bEndProgress )
+ {
+ tools::Long nEndPage = GetLayout()->GetPageNum();
+ nEndPage += nEndPage * 10 / 100;
+ ::StartProgress( STR_STATSTR_REFORMAT, 0, nEndPage, GetDoc()->GetDocShell() );
+ }
+
+ SwLayAction aAction( GetLayout(), Imp() );
+ aAction.SetPaint( false );
+ aAction.SetStatBar( true );
+ aAction.SetCalcLayout( true );
+ aAction.SetReschedule( true );
+ GetDoc()->getIDocumentFieldsAccess().LockExpFields();
+ aAction.Action(GetOut());
+ GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
+
+ //the SetNewFieldLst() on the Doc was cut off and must be fetched again
+ //(see flowfrm.cxx, txtfld.cxx)
+ if ( aAction.IsExpFields() )
+ {
+ aAction.Reset();
+ aAction.SetPaint( false );
+ aAction.SetStatBar( true );
+ aAction.SetReschedule( true );
+
+ GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(0);
+ GetDoc()->getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
+
+ aAction.Action(GetOut());
+ }
+
+ if ( VisArea().HasArea() )
+ InvalidateWindows( VisArea() );
+ if ( bEndProgress )
+ ::EndProgress( GetDoc()->GetDocShell() );
+}
+
+void SwViewShell::SetFirstVisPageInvalid()
+{
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if ( rSh.Imp() )
+ rSh.Imp()->SetFirstVisPageInvalid();
+ }
+}
+
+void SwViewShell::SizeChgNotify()
+{
+ if ( !mpWin )
+ mbDocSizeChgd = true;
+ else if( ActionPend() || Imp()->IsCalcLayoutProgress() || mbPaintInProgress )
+ {
+ mbDocSizeChgd = true;
+
+ if ( !Imp()->IsCalcLayoutProgress() && dynamic_cast<const SwCursorShell*>( this ) != nullptr )
+ {
+ PageNumNotify(this);
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ Size aDocSize = GetDocSize();
+ OString sPayload = OString::number(aDocSize.Width() + 2 * DOCUMENTBORDER) +
+ ", " + OString::number(aDocSize.Height() + 2 * DOCUMENTBORDER);
+
+ SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(GetSfxViewShell()->GetCurrentDocument());
+ SfxLokHelper::notifyDocumentSizeChanged(GetSfxViewShell(), sPayload, pModel);
+ }
+ }
+ }
+ else
+ {
+ mbDocSizeChgd = false;
+ ::SizeNotify( this, GetDocSize() );
+ }
+}
+
+void SwViewShell::VisPortChgd( const SwRect &rRect)
+{
+ OSL_ENSURE( GetWin(), "VisPortChgd without Window." );
+
+ if ( rRect == VisArea() )
+ return;
+
+ // Is someone spuriously rescheduling again?
+ SAL_WARN_IF(mbInEndAction, "sw.core", "Scrolling during EndAction");
+
+ //First get the old visible page, so we don't have to look
+ //for it afterwards.
+ const SwFrame *pOldPage = Imp()->GetFirstVisPage(GetWin()->GetOutDev());
+
+ const SwRect aPrevArea( VisArea() );
+ const bool bFull = aPrevArea.IsEmpty();
+ maVisArea = rRect;
+ SetFirstVisPageInvalid();
+
+ //When there a PaintRegion still exists and the VisArea has changed,
+ //the PaintRegion is at least by now obsolete. The PaintRegion can
+ //have been created by RootFrame::PaintSwFrame.
+ if ( !mbInEndAction &&
+ Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
+ Imp()->DeletePaintRegion();
+
+ CurrShell aCurr( this );
+
+ bool bScrolled = false;
+
+ SwPostItMgr* pPostItMgr = GetPostItMgr();
+
+ if ( bFull )
+ GetWin()->Invalidate();
+ else
+ {
+ //Calculate amount to be scrolled.
+ const tools::Long nXDiff = aPrevArea.Left() - VisArea().Left();
+ const tools::Long nYDiff = aPrevArea.Top() - VisArea().Top();
+
+ if( !nXDiff && !GetViewOptions()->getBrowseMode() &&
+ (!Imp()->HasDrawView() || !Imp()->GetDrawView()->IsGridVisible() ) )
+ {
+ // If possible, don't scroll the application background
+ // (PaintDesktop). Also limit the left and right side of
+ // the scroll range to the pages.
+ const SwPageFrame *pPage = static_cast<SwPageFrame*>(GetLayout()->Lower());
+ if ( pPage->getFrameArea().Top() > pOldPage->getFrameArea().Top() )
+ pPage = static_cast<const SwPageFrame*>(pOldPage);
+ SwRect aBoth( VisArea() );
+ aBoth.Union( aPrevArea );
+ const SwTwips nBottom = aBoth.Bottom();
+ SwTwips nMinLeft = SAL_MAX_INT32;
+ SwTwips nMaxRight= 0;
+
+ const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();
+
+ while ( pPage && pPage->getFrameArea().Top() <= nBottom )
+ {
+ SwRect aPageRect( pPage->GetBoundRect(GetWin()->GetOutDev()) );
+ if ( bBookMode )
+ {
+ const SwPageFrame& rFormatPage = pPage->GetFormatPage();
+ aPageRect.SSize( rFormatPage.GetBoundRect(GetWin()->GetOutDev()).SSize() );
+ }
+
+ // #i9719# - consider new border and shadow width
+ if ( aPageRect.Overlaps( aBoth ) )
+ {
+ SwTwips nPageLeft = 0;
+ SwTwips nPageRight = 0;
+ const sw::sidebarwindows::SidebarPosition aSidebarPos = pPage->SidebarPosition();
+
+ if( aSidebarPos != sw::sidebarwindows::SidebarPosition::NONE )
+ {
+ nPageLeft = aPageRect.Left();
+ nPageRight = aPageRect.Right();
+ }
+
+ if( nPageLeft < nMinLeft )
+ nMinLeft = nPageLeft;
+ if( nPageRight > nMaxRight )
+ nMaxRight = nPageRight;
+ //match with the draw objects
+ //take nOfst into account as the objects have been
+ //selected and have handles attached.
+ if ( pPage->GetSortedObjs() )
+ {
+ const tools::Long nOfst = GetOut()->PixelToLogic(
+ Size(Imp()->GetDrawView()->GetMarkHdlSizePixel()/2,0)).Width();
+ for (SwAnchoredObject* pObj : *pPage->GetSortedObjs())
+ {
+ // ignore objects that are not actually placed on the page
+ if (pObj->IsFormatPossible())
+ {
+ const tools::Rectangle &rBound = pObj->GetObjRect().SVRect();
+ if (rBound.Left() != FAR_AWAY) {
+ // OD 03.03.2003 #107927# - use correct datatype
+ const SwTwips nL = std::max( SwTwips(0), SwTwips(rBound.Left() - nOfst) );
+ if ( nL < nMinLeft )
+ nMinLeft = nL;
+ if( rBound.Right() + nOfst > nMaxRight )
+ nMaxRight = rBound.Right() + nOfst;
+ }
+ }
+ }
+ }
+ }
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ }
+ tools::Rectangle aRect( aPrevArea.SVRect() );
+ aRect.SetLeft( nMinLeft );
+ aRect.SetRight( nMaxRight );
+ if( VisArea().Overlaps( aPrevArea ) && !mnLockPaint )
+ {
+ bScrolled = true;
+ maVisArea.Pos() = aPrevArea.Pos();
+ if ( SmoothScroll( nXDiff, nYDiff, &aRect ) )
+ return;
+ maVisArea.Pos() = rRect.Pos();
+ }
+ else if (!comphelper::LibreOfficeKit::isActive())
+ GetWin()->Invalidate( aRect );
+ }
+ else if ( !mnLockPaint ) //will be released in Unlock
+ {
+ if( VisArea().Overlaps( aPrevArea ) )
+ {
+ bScrolled = true;
+ maVisArea.Pos() = aPrevArea.Pos();
+ if ( SmoothScroll( nXDiff, nYDiff, nullptr ) )
+ return;
+ maVisArea.Pos() = rRect.Pos();
+ }
+ else
+ GetWin()->Invalidate();
+ }
+ }
+
+ // When tiled rendering, the map mode of the window is disabled, avoid
+ // enabling it here.
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ Point aPt( VisArea().Pos() );
+ aPt.setX( -aPt.X() ); aPt.setY( -aPt.Y() );
+ MapMode aMapMode( GetWin()->GetMapMode() );
+ aMapMode.SetOrigin( aPt );
+ GetWin()->SetMapMode( aMapMode );
+ }
+
+ if ( HasDrawView() )
+ {
+ Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
+ Imp()->GetDrawView()->SetActualWin( GetWin()->GetOutDev() );
+ }
+ GetWin()->PaintImmediately();
+
+ if ( pPostItMgr ) // #i88070#
+ {
+ pPostItMgr->Rescale();
+ pPostItMgr->CalcRects();
+ pPostItMgr->LayoutPostIts();
+ }
+
+ if ( !bScrolled && pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
+ pPostItMgr->CorrectPositions();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( Imp()->IsAccessible() )
+ Imp()->UpdateAccessible();
+#endif
+}
+
+bool SwViewShell::SmoothScroll( tools::Long lXDiff, tools::Long lYDiff, const tools::Rectangle *pRect )
+{
+#if !defined(MACOSX) && !defined(ANDROID) && !defined(IOS)
+ // #i98766# - disable smooth scrolling for Mac
+
+ const sal_uLong nBitCnt = mpOut->GetBitCount();
+ tools::Long lMult = 1, lMax = LONG_MAX;
+ if ( nBitCnt == 16 )
+ {
+ lMax = 7000;
+ lMult = 2;
+ }
+ if ( nBitCnt == 24 )
+ {
+ lMax = 5000;
+ lMult = 6;
+ }
+ else if ( nBitCnt == 1 )
+ {
+ lMax = 3000;
+ lMult = 12;
+ }
+
+ // #i75172# isolated static conditions
+ const bool bOnlyYScroll(!lXDiff && std::abs(lYDiff) != 0 && std::abs(lYDiff) < lMax);
+ const bool bAllowedWithChildWindows(GetWin()->GetWindowClipRegionPixel().IsNull());
+ const bool bSmoothScrollAllowed(bOnlyYScroll && mbEnableSmooth && GetViewOptions()->IsSmoothScroll() && bAllowedWithChildWindows);
+
+ if(bSmoothScrollAllowed)
+ {
+ Imp()->m_bStopSmooth = false;
+
+ const SwRect aOldVis( VisArea() );
+
+ //create virtual device and set.
+ const Size aPixSz = GetWin()->PixelToLogic(Size(1,1));
+ VclPtrInstance<VirtualDevice> pVout( *GetWin()->GetOutDev() );
+ pVout->SetLineColor( GetWin()->GetOutDev()->GetLineColor() );
+ pVout->SetFillColor( GetWin()->GetOutDev()->GetFillColor() );
+ MapMode aMapMode( GetWin()->GetMapMode() );
+ pVout->SetMapMode( aMapMode );
+ Size aSize( maVisArea.Width()+2*aPixSz.Width(), std::abs(lYDiff)+(2*aPixSz.Height()) );
+ if ( pRect )
+ aSize.setWidth( std::min(aSize.Width(), pRect->GetWidth()+2*aPixSz.Width()) );
+ if ( pVout->SetOutputSize( aSize ) )
+ {
+ mnLockPaint++;
+
+ //First Paint everything in the virtual device.
+ SwRect aRect( VisArea() );
+ aRect.Height( aSize.Height() );
+ if ( pRect )
+ {
+ aRect.Pos().setX( std::max(aRect.Left(),pRect->Left()-aPixSz.Width()) );
+ aRect.Right( std::min(aRect.Right()+2*aPixSz.Width(), pRect->Right()+aPixSz.Width()));
+ }
+ else
+ aRect.AddWidth(2*aPixSz.Width() );
+ aRect.Pos().setY( lYDiff < 0 ? aOldVis.Bottom() - aPixSz.Height()
+ : aRect.Top() - aSize.Height() + aPixSz.Height() );
+ aRect.Pos().setX( std::max( tools::Long(0), aRect.Left()-aPixSz.Width() ) );
+ aRect.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.Pos()));
+ aRect.SSize( GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.SSize())) );
+ maVisArea = aRect;
+ const Point aPt( -aRect.Left(), -aRect.Top() );
+ aMapMode.SetOrigin( aPt );
+ pVout->SetMapMode( aMapMode );
+ OutputDevice *pOld = mpOut;
+ mpOut = pVout.get();
+
+ {
+ // #i75172# To get a clean repaint, a new ObjectContact is needed here. Without, the
+ // repaint would not be correct since it would use the wrong DrawPage visible region.
+ // This repaint IS about painting something currently outside the visible part (!).
+ // For that purpose, AddDeviceToPaintView is used which creates a new SdrPageViewWindow
+ // and all the necessary stuff. It's not cheap, but necessary here. Alone because repaint
+ // target really is NOT the current window.
+ // Also will automatically NOT use PreRendering and overlay (since target is VirtualDevice)
+ if(!HasDrawView())
+ MakeDrawView();
+ SdrView* pDrawView = GetDrawView();
+ pDrawView->AddDeviceToPaintView(*pVout, nullptr);
+
+ // clear mpWin during DLPrePaint2 to get paint preparation for mpOut, but set it again
+ // immediately afterwards. There are many decisions in SW which imply that Printing
+ // is used when mpWin == 0 (wrong but widely used).
+ vcl::Window* pOldWin = mpWin;
+ mpWin = nullptr;
+ DLPrePaint2(vcl::Region(aRect.SVRect()));
+ mpWin = pOldWin;
+
+ // SW paint stuff
+ PaintDesktop(*GetOut(), aRect);
+ SwViewShell::sbLstAct = true;
+ GetLayout()->PaintSwFrame( *GetOut(), aRect );
+ SwViewShell::sbLstAct = false;
+
+ // end paint and destroy ObjectContact again
+ DLPostPaint2(true);
+ pDrawView->DeleteDeviceFromPaintView(*pVout);
+ }
+
+ mpOut = pOld;
+ maVisArea = aOldVis;
+
+ //Now shift in parts and copy the new Pixel from the virtual device.
+
+ // ??????????????????????
+ // or is it better to get the scrollfactor from the User
+ // as option?
+ // ??????????????????????
+ tools::Long lMaDelta = aPixSz.Height();
+ if ( std::abs(lYDiff) > ( maVisArea.Height() / 3 ) )
+ lMaDelta *= 6;
+ else
+ lMaDelta *= 2;
+
+ lMaDelta *= lMult;
+
+ if ( lYDiff < 0 )
+ lMaDelta = -lMaDelta;
+
+ tools::Long lDiff = lYDiff;
+ while ( lDiff )
+ {
+ tools::Long lScroll;
+ if ( Imp()->m_bStopSmooth || std::abs(lDiff) <= std::abs(lMaDelta) )
+ {
+ lScroll = lDiff;
+ lDiff = 0;
+ }
+ else
+ {
+ lScroll = lMaDelta;
+ lDiff -= lMaDelta;
+ }
+
+ const SwRect aTmpOldVis = VisArea();
+ maVisArea.Pos().AdjustY( -lScroll );
+ maVisArea.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( VisArea().Pos()));
+ lScroll = aTmpOldVis.Top() - VisArea().Top();
+ if ( pRect )
+ {
+ tools::Rectangle aTmp( aTmpOldVis.SVRect() );
+ aTmp.SetLeft( pRect->Left() );
+ aTmp.SetRight( pRect->Right() );
+ GetWin()->Scroll( 0, lScroll, aTmp, ScrollFlags::Children);
+ }
+ else
+ GetWin()->Scroll( 0, lScroll, ScrollFlags::Children );
+
+ const Point aTmpPt( -VisArea().Left(), -VisArea().Top() );
+ MapMode aTmpMapMode( GetWin()->GetMapMode() );
+ aTmpMapMode.SetOrigin( aTmpPt );
+ GetWin()->SetMapMode( aTmpMapMode );
+
+ if ( Imp()->HasDrawView() )
+ Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
+
+ SetFirstVisPageInvalid();
+ if ( !Imp()->m_bStopSmooth )
+ {
+ const bool bScrollDirectionIsUp(lScroll > 0);
+ Imp()->m_aSmoothRect = VisArea();
+
+ if(bScrollDirectionIsUp)
+ {
+ Imp()->m_aSmoothRect.Bottom( VisArea().Top() + lScroll + aPixSz.Height());
+ }
+ else
+ {
+ Imp()->m_aSmoothRect.Top( VisArea().Bottom() + lScroll - aPixSz.Height());
+ }
+
+ Imp()->m_bSmoothUpdate = true;
+ GetWin()->PaintImmediately();
+ Imp()->m_bSmoothUpdate = false;
+
+ if(!Imp()->m_bStopSmooth)
+ {
+ // start paint on logic base
+ const tools::Rectangle aTargetLogic(Imp()->m_aSmoothRect.SVRect());
+ DLPrePaint2(vcl::Region(aTargetLogic));
+
+ // get target rectangle in discrete pixels
+ OutputDevice& rTargetDevice = mpTargetPaintWindow->GetTargetOutputDevice();
+ const tools::Rectangle aTargetPixel(rTargetDevice.LogicToPixel(aTargetLogic));
+
+ // get source top-left in discrete pixels
+ const Point aSourceTopLeft(pVout->LogicToPixel(aTargetLogic.TopLeft()));
+
+ // switch off MapModes
+ const bool bMapModeWasEnabledDest(rTargetDevice.IsMapModeEnabled());
+ const bool bMapModeWasEnabledSource(pVout->IsMapModeEnabled());
+ rTargetDevice.EnableMapMode(false);
+ pVout->EnableMapMode(false);
+
+ rTargetDevice.DrawOutDev(
+ aTargetPixel.TopLeft(), aTargetPixel.GetSize(), // dest
+ aSourceTopLeft, aTargetPixel.GetSize(), // source
+ *pVout);
+
+ // restore MapModes
+ rTargetDevice.EnableMapMode(bMapModeWasEnabledDest);
+ pVout->EnableMapMode(bMapModeWasEnabledSource);
+
+ // end paint on logoc base
+ DLPostPaint2(true);
+ }
+ else
+ --mnLockPaint;
+ }
+ }
+ pVout.disposeAndClear();
+ GetWin()->PaintImmediately();
+ if ( !Imp()->m_bStopSmooth )
+ --mnLockPaint;
+ SetFirstVisPageInvalid();
+ return true;
+ }
+ pVout.disposeAndClear();
+ }
+#endif
+
+ maVisArea.Pos().AdjustX( -lXDiff );
+ maVisArea.Pos().AdjustY( -lYDiff );
+ if ( pRect )
+ GetWin()->Scroll( lXDiff, lYDiff, *pRect, ScrollFlags::Children);
+ else
+ GetWin()->Scroll( lXDiff, lYDiff, ScrollFlags::Children);
+ return false;
+}
+
+void SwViewShell::PaintDesktop(const vcl::RenderContext& rRenderContext, const SwRect &rRect)
+{
+ if ( !GetWin() && !GetOut()->GetConnectMetaFile() )
+ return; //for the printer we don't do anything here.
+
+ if(comphelper::LibreOfficeKit::isActive())
+ return;
+
+ //Catch exceptions, so that it doesn't look so surprising.
+ //Can e.g. happen during Idle.
+ //Unfortunately we must at any rate Paint the rectangles next to the pages,
+ //as these are not painted at VisPortChgd.
+ bool bBorderOnly = false;
+ const SwRootFrame *pRoot = GetLayout();
+ if ( rRect.Top() > pRoot->getFrameArea().Bottom() )
+ {
+ const SwFrame *pPg = pRoot->Lower();
+ while ( pPg && pPg->GetNext() )
+ pPg = pPg->GetNext();
+ if ( !pPg || !pPg->getFrameArea().Overlaps( VisArea() ) )
+ bBorderOnly = true;
+ }
+
+ const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();
+
+ SwRegionRects aRegion( rRect );
+
+ //mod #i6193: remove sidebar area to avoid flickering
+ const SwPostItMgr* pPostItMgr = GetPostItMgr();
+ const SwTwips nSidebarWidth = pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ?
+ pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() :
+ 0;
+
+ if ( bBorderOnly )
+ {
+ const SwFrame *pPage =pRoot->Lower();
+ SwRect aLeft( rRect ), aRight( rRect );
+ while ( pPage )
+ {
+ tools::Long nTmp = pPage->getFrameArea().Left();
+ if ( nTmp < aLeft.Right() )
+ aLeft.Right( nTmp );
+ nTmp = pPage->getFrameArea().Right();
+ if ( nTmp > aRight.Left() )
+ {
+ aRight.Left( nTmp + nSidebarWidth );
+ }
+ pPage = pPage->GetNext();
+ }
+ aRegion.clear();
+ if ( aLeft.HasArea() )
+ aRegion.push_back( aLeft );
+ if ( aRight.HasArea() )
+ aRegion.push_back( aRight );
+ }
+ else
+ {
+ const SwFrame *pPage = Imp()->GetFirstVisPage(&rRenderContext);
+ const SwTwips nBottom = rRect.Bottom();
+ while ( pPage && !aRegion.empty() &&
+ (pPage->getFrameArea().Top() <= nBottom) )
+ {
+ SwRect aPageRect( pPage->getFrameArea() );
+ if ( bBookMode )
+ {
+ const SwPageFrame& rFormatPage = static_cast<const SwPageFrame*>(pPage)->GetFormatPage();
+ aPageRect.SSize( rFormatPage.getFrameArea().SSize() );
+ }
+
+ const bool bSidebarRight =
+ static_cast<const SwPageFrame*>(pPage)->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
+ aPageRect.Pos().AdjustX( -(bSidebarRight ? 0 : nSidebarWidth) );
+ aPageRect.AddWidth(nSidebarWidth );
+
+ if ( aPageRect.Overlaps( rRect ) )
+ aRegion -= aPageRect;
+
+ pPage = pPage->GetNext();
+ }
+ }
+ if ( !aRegion.empty() )
+ PaintDesktop_(aRegion);
+}
+
+// PaintDesktop is split in two, this part is also used by PreviewPage
+void SwViewShell::PaintDesktop_(const SwRegionRects &rRegion)
+{
+ // OD 2004-04-23 #116347#
+ GetOut()->Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
+ GetOut()->SetLineColor();
+
+ for ( auto &rRgn : rRegion )
+ {
+ const tools::Rectangle aRectangle(rRgn.SVRect());
+
+ // #i93170#
+ // Here we have a real Problem. On the one hand we have the buffering for paint
+ // and overlay which needs an embracing pair of DLPrePaint2/DLPostPaint2 calls,
+ // on the other hand the MapMode is not set correctly when this code is executed.
+ // This is done in the users of this method, for each SWpage before painting it.
+ // Since the MapMode is not correct here, the call to DLPostPaint2 will paint
+ // existing FormControls due to the current MapMode.
+
+ // There are basically three solutions for this:
+
+ // (1) Set the MapMode correct, move the background painting to the users of
+ // this code
+
+ // (2) Do no DLPrePaint2/DLPostPaint2 here; no SdrObjects are allowed to lie in
+ // the desktop region. Disadvantage: the desktop will not be part of the
+ // buffers, e.g. overlay. Thus, as soon as overlay will be used over the
+ // desktop, it will not work.
+
+ // (3) expand DLPostPaint2 with a flag to signal if FormControl paints shall
+ // be done or not
+
+ // Currently, (3) will be the best possible solution. It will keep overlay and
+ // buffering intact and work without MapMode for single pages. In the medium
+ // to long run, (1) will need to be used and the bool bPaintFormLayer needs
+ // to be removed again
+
+ // #i68597# inform Drawinglayer about display change
+ DLPrePaint2(vcl::Region(aRectangle));
+
+ // #i75172# needed to move line/Fill color setters into loop since DLPrePaint2
+ // may exchange GetOut(), that's it's purpose. This happens e.g. at print preview.
+ GetOut()->SetFillColor( GetViewOptions()->GetAppBackgroundColor());
+ GetOut()->SetLineColor();
+ GetOut()->DrawRect(aRectangle);
+
+ DLPostPaint2(false);
+ }
+
+ GetOut()->Pop();
+}
+
+bool SwViewShell::CheckInvalidForPaint( const SwRect &rRect )
+{
+ if ( !GetWin() )
+ return false;
+
+ const SwPageFrame *pPage = Imp()->GetFirstVisPage(GetOut());
+ const SwTwips nBottom = VisArea().Bottom();
+ const SwTwips nRight = VisArea().Right();
+ bool bRet = false;
+ while ( !bRet && pPage && ((pPage->getFrameArea().Top() <= nBottom) &&
+ (pPage->getFrameArea().Left() <= nRight)))
+ {
+ if ( pPage->IsInvalid() || pPage->IsInvalidFly() )
+ bRet = true;
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ }
+
+ if ( bRet )
+ {
+ //Unfortunately Start/EndAction won't help here, as the Paint originated
+ //from GUI and so Clipping has been set against getting through.
+ //Ergo: do it all yourself (see ImplEndAction())
+ if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea())
+ Imp()->DeletePaintRegion();
+
+ SwLayAction aAction( GetLayout(), Imp() );
+ aAction.SetComplete( false );
+ // We increment the action counter to avoid a recursive call of actions
+ // e.g. from a SwFEShell::RequestObjectResize(..) in bug 95829.
+ // A recursive call of actions is no good idea because the inner action
+ // can't format frames which are locked by the outer action. This may
+ // cause and endless loop.
+ ++mnStartAction;
+ aAction.Action(GetWin()->GetOutDev());
+ --mnStartAction;
+
+ std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();
+ if ( oRegion && aAction.IsBrowseActionStop() )
+ {
+ //only of interest when something has changed in the visible range
+ bool bStop = true;
+ for ( size_t i = 0; i < oRegion->size(); ++i )
+ {
+ const SwRect &rTmp = (*oRegion)[i];
+ bStop = rTmp.Overlaps( VisArea() );
+ if ( !bStop )
+ break;
+ }
+ if ( bStop )
+ oRegion.reset();
+ }
+
+ if ( oRegion )
+ {
+ oRegion->LimitToOrigin();
+ oRegion->Compress( SwRegionRects::CompressFuzzy );
+ bRet = false;
+ if ( !oRegion->empty() )
+ {
+ SwRegionRects aRegion( rRect );
+ for ( size_t i = 0; i < oRegion->size(); ++i )
+ { const SwRect &rTmp = (*oRegion)[i];
+ if ( !rRect.Contains( rTmp ) )
+ {
+ InvalidateWindows( rTmp );
+ if ( rTmp.Overlaps( VisArea() ) )
+ { aRegion -= rTmp;
+ bRet = true;
+ }
+ }
+ }
+ if ( bRet )
+ {
+ for ( size_t i = 0; i < aRegion.size(); ++i )
+ GetWin()->Invalidate( aRegion[i].SVRect() );
+
+ if ( rRect != VisArea() )
+ {
+ //rRect == VisArea is the special case for new or
+ //Shift-Ctrl-R, when it shouldn't be necessary to
+ //hold the rRect again in Document coordinates.
+ if ( maInvalidRect.IsEmpty() )
+ maInvalidRect = rRect;
+ else
+ maInvalidRect.Union( rRect );
+ }
+ }
+ }
+ else
+ bRet = false;
+ }
+ else
+ bRet = false;
+ }
+ return bRet;
+}
+
+namespace
+{
+/// Similar to comphelper::FlagRestorationGuard, but for vcl::RenderContext.
+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)
+ : m_pPatchedPageWindow(nullptr)
+ {
+ pRef = pValue;
+
+ if (pValue == pShell->GetWin()->GetOutDev())
+ return;
+
+ SdrView* pDrawView(pShell->Imp()->GetDrawView());
+
+ if (nullptr == pDrawView)
+ return;
+
+ SdrPageView* pSdrPageView(pDrawView->GetSdrPageView());
+
+ if (nullptr != pSdrPageView)
+ {
+ m_pPatchedPageWindow = pSdrPageView->FindPageWindow(*pShell->GetWin()->GetOutDev());
+
+ if (nullptr != m_pPatchedPageWindow)
+ {
+ m_TemporaryPaintWindow.reset(new SdrPaintWindow(*pDrawView, *pValue));
+ m_pPreviousPaintWindow = m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
+ }
+ }
+ }
+
+ ~RenderContextGuard()
+ {
+ if(nullptr != m_pPatchedPageWindow)
+ {
+ m_pPatchedPageWindow->unpatchPaintWindow(m_pPreviousPaintWindow);
+ }
+ }
+};
+}
+
+void SwViewShell::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect)
+{
+ RenderContextGuard aGuard(mpOut, &rRenderContext, this);
+ if ( mnLockPaint )
+ {
+ if ( Imp()->m_bSmoothUpdate )
+ {
+ SwRect aTmp( rRect );
+ if ( !Imp()->m_aSmoothRect.Contains( aTmp ) )
+ Imp()->m_bStopSmooth = true;
+ else
+ {
+ Imp()->m_aSmoothRect = aTmp;
+ return;
+ }
+ }
+ else
+ return;
+ }
+
+ if ( SwRootFrame::IsInPaint() )
+ {
+ //During the publication of a page at printing the Paint is buffered.
+ SwPaintQueue::Add( this, SwRect( rRect ) );
+ return;
+ }
+
+ //With !nStartAction I try to protect me against erroneous code at other places.
+ //Hopefully it will not lead to problems!?
+ if ( mbPaintWorks && !mnStartAction )
+ {
+ if( GetWin() && GetWin()->IsVisible() )
+ {
+ SwRect aRect( rRect );
+ if ( mbPaintInProgress ) //Guard against double Paints!
+ {
+ GetWin()->Invalidate( rRect );
+ return;
+ }
+
+ mbPaintInProgress = true;
+ CurrShell aCurr( this );
+ SwRootFrame::SetNoVirDev( true );
+
+ //We don't want to Clip to and from, we trust that all are limited
+ //to the rectangle and only need to calculate the clipping once.
+ //The ClipRect is removed here once and not recovered, as externally
+ //no one needs it anymore anyway.
+ //Not when we paint a Metafile.
+ if( !GetOut()->GetConnectMetaFile() && GetOut()->IsClipRegion())
+ GetOut()->SetClipRegion();
+
+ if ( IsPreview() )
+ {
+ //When useful, process or destroy the old InvalidRect.
+ if ( aRect.Contains( maInvalidRect ) )
+ ResetInvalidRect();
+ SwViewShell::sbLstAct = true;
+ GetLayout()->PaintSwFrame( rRenderContext, aRect );
+ SwViewShell::sbLstAct = false;
+ }
+ else
+ {
+ //When one of the visible pages still has anything entered for
+ //Repaint, Repaint must be triggered.
+ if ( !CheckInvalidForPaint( aRect ) )
+ {
+ // --> OD 2009-08-12 #i101192#
+ // start Pre/PostPaint encapsulation to avoid screen blinking
+ const vcl::Region aRepaintRegion(aRect.SVRect());
+ DLPrePaint2(aRepaintRegion);
+
+ // <--
+ PaintDesktop(rRenderContext, aRect);
+
+ //When useful, process or destroy the old InvalidRect.
+ if ( aRect.Contains( maInvalidRect ) )
+ ResetInvalidRect();
+ SwViewShell::sbLstAct = true;
+ GetLayout()->PaintSwFrame( rRenderContext, aRect );
+ SwViewShell::sbLstAct = false;
+ // --> OD 2009-08-12 #i101192#
+ // end Pre/PostPaint encapsulation
+ DLPostPaint2(true);
+ // <--
+ }
+ }
+ SwRootFrame::SetNoVirDev( false );
+ mbPaintInProgress = false;
+ UISizeNotify();
+ }
+ }
+ else
+ {
+ if ( maInvalidRect.IsEmpty() )
+ maInvalidRect = SwRect( rRect );
+ else
+ maInvalidRect.Union( SwRect( rRect ) );
+
+ if ( mbInEndAction && GetWin() )
+ {
+ const vcl::Region aRegion(GetWin()->GetPaintRegion());
+ RectangleVector aRectangles;
+ aRegion.GetRegionRectangles(aRectangles);
+
+ for(const auto& rRectangle : aRectangles)
+ {
+ Imp()->AddPaintRect(SwRect(rRectangle));
+ }
+
+ //RegionHandle hHdl( aRegion.BeginEnumRects() );
+ //Rectangle aRect;
+ //while ( aRegion.GetEnumRects( hHdl, aRect ) )
+ // Imp()->AddPaintRect( aRect );
+ //aRegion.EndEnumRects( hHdl );
+ }
+ else if ( SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) &&
+ GetOut() == GetWin()->GetOutDev() )
+ {
+ // #i68597#
+ const vcl::Region aDLRegion(rRect);
+ DLPrePaint2(aDLRegion);
+
+ rRenderContext.Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
+ rRenderContext.SetFillColor( Imp()->GetRetoucheColor() );
+ rRenderContext.SetLineColor();
+ rRenderContext.DrawRect( rRect );
+ rRenderContext.Pop();
+ // #i68597#
+ DLPostPaint2(true);
+ }
+ }
+}
+
+void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contextHeight, int tilePosX, int tilePosY, tools::Long tileWidth, tools::Long tileHeight)
+{
+ // SwViewShell's output device setup
+ // TODO clean up SwViewShell's approach to output devices (the many of
+ // them - mpBufferedOut, mpOut, mpWin, ...)
+ OutputDevice *pSaveOut = mpOut;
+ comphelper::LibreOfficeKit::setTiledPainting(true);
+ mpOut = &rDevice;
+
+ // resizes the virtual device so to contain the entries context
+ rDevice.SetOutputSizePixel(Size(contextWidth, contextHeight));
+
+ // setup the output device to draw the tile
+ MapMode aMapMode(rDevice.GetMapMode());
+ aMapMode.SetMapUnit(MapUnit::MapTwip);
+ aMapMode.SetOrigin(Point(-tilePosX, -tilePosY));
+
+ // Scaling. Must convert from pixels to twips. We know
+ // that VirtualDevices use a DPI of 96.
+ const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
+ Fraction scaleX = Fraction(contextWidth, tileWidth) * scale;
+ Fraction scaleY = Fraction(contextHeight, tileHeight) * scale;
+ aMapMode.SetScaleX(scaleX);
+ aMapMode.SetScaleY(scaleY);
+ rDevice.SetMapMode(aMapMode);
+
+ // Update scaling of SwEditWin and its sub-widgets, needed for comments.
+ sal_uInt16 nOldZoomValue = 0;
+ if (GetWin() && GetWin()->GetMapMode().GetScaleX() != scaleX)
+ {
+ double fScale = double(scaleX);
+ SwViewOption aOption(*GetViewOptions());
+ nOldZoomValue = aOption.GetZoom();
+ aOption.SetZoom(fScale * 100);
+ ApplyViewOptions(aOption);
+ // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
+ GetWin()->EnableMapMode(false);
+ }
+
+ tools::Rectangle aOutRect(Point(tilePosX, tilePosY),
+ rDevice.PixelToLogic(Size(contextWidth, contextHeight)));
+
+ // Make the requested area visible -- we can't use MakeVisible as that will
+ // only scroll the contents, but won't zoom/resize if needed.
+ // Without this, items/text that are outside the visible area (in the SwView)
+ // won't be painted when rendering tiles (at least when using either the
+ // tiledrendering app, or the gtktiledviewer) -- although ultimately we
+ // probably want to fix things so that the SwView's area doesn't affect
+ // tiled rendering?
+ VisPortChgd(SwRect(aOutRect));
+
+ // Invoke SwLayAction if layout is not yet ready.
+ CheckInvalidForPaint(SwRect(aOutRect));
+
+ // draw - works in logic coordinates
+ Paint(rDevice, aOutRect);
+
+ SwPostItMgr* pPostItMgr = GetPostItMgr();
+ if (GetViewOptions()->IsPostIts() && pPostItMgr)
+ pPostItMgr->PaintTile(rDevice);
+
+ // SwViewShell's output device tear down
+
+ // A view shell can get a PaintTile call for a tile at a zoom level
+ // different from the one, the related client really is.
+ // In such a case it is better to reset the current scale value to
+ // the original one, since such a value should be in synchronous with
+ // the zoom level in the client (see setClientZoom).
+ // At present the zoom value returned by GetViewOptions()->GetZoom() is
+ // used in SwXTextDocument methods (postMouseEvent and setGraphicSelection)
+ // for passing the correct mouse position to an edited chart (if any).
+ if (nOldZoomValue !=0)
+ {
+ SwViewOption aOption(*GetViewOptions());
+ aOption.SetZoom(nOldZoomValue);
+ ApplyViewOptions(aOption);
+
+ // Changing the zoom value doesn't always trigger the updating of
+ // the client ole object area, so we call it directly.
+ SfxInPlaceClient* pIPClient = GetSfxViewShell()->GetIPClient();
+ if (pIPClient)
+ {
+ pIPClient->VisAreaChanged();
+ }
+ // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
+ GetWin()->EnableMapMode(false);
+ }
+
+ mpOut = pSaveOut;
+ comphelper::LibreOfficeKit::setTiledPainting(false);
+}
+
+void SwViewShell::SetBrowseBorder( const Size& rNew )
+{
+ if( rNew != maBrowseBorder )
+ {
+ maBrowseBorder = rNew;
+ if ( maVisArea.HasArea() )
+ InvalidateLayout( false );
+ }
+}
+
+const Size& SwViewShell::GetBrowseBorder() const
+{
+ return maBrowseBorder;
+}
+
+sal_Int32 SwViewShell::GetBrowseWidth() const
+{
+ const SwPostItMgr* pPostItMgr = GetPostItMgr();
+ if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
+ {
+ Size aBorder( maBrowseBorder );
+ aBorder.AdjustWidth(maBrowseBorder.Width() );
+ aBorder.AdjustWidth(pPostItMgr->GetSidebarWidth(true) + pPostItMgr->GetSidebarBorderWidth(true) );
+ return maVisArea.Width() - GetOut()->PixelToLogic(aBorder).Width();
+ }
+ else
+ return maVisArea.Width() - 2 * GetOut()->PixelToLogic(maBrowseBorder).Width();
+}
+
+void SwViewShell::InvalidateLayout( bool bSizeChanged )
+{
+ if ( !bSizeChanged && !GetViewOptions()->getBrowseMode() &&
+ !GetViewOptions()->IsWhitespaceHidden() )
+ return;
+
+ CurrShell aCurr( this );
+
+ OSL_ENSURE( GetLayout(), "Layout not ready" );
+
+ // When the Layout doesn't have a height yet, nothing is formatted.
+ // That leads to problems with Invalidate, e.g. when setting up a new View
+ // the content is inserted and formatted (regardless of empty VisArea).
+ // Therefore the pages must be roused for formatting.
+ if( !GetLayout()->getFrameArea().Height() )
+ {
+ SwFrame* pPage = GetLayout()->Lower();
+ while( pPage )
+ {
+ pPage->InvalidateSize_();
+ pPage = pPage->GetNext();
+ }
+ return;
+ }
+
+ LockPaint(LockPaintReason::InvalidateLayout);
+ StartAction();
+
+ SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
+ do
+ { pPg->InvalidateSize();
+ pPg->InvalidatePrt_();
+ pPg->InvaPercentLowers();
+ if ( bSizeChanged )
+ {
+ pPg->PrepareHeader();
+ pPg->PrepareFooter();
+ }
+ pPg = static_cast<SwPageFrame*>(pPg->GetNext());
+ } while ( pPg );
+
+ // When the size ratios in browse mode change,
+ // the Position and PrtArea of the Content and Tab frames must be Invalidated.
+ SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
+ // In case of layout or mode change, the ContentFrames need a size-Invalidate
+ // because of printer/screen formatting.
+ if ( bSizeChanged )
+ nInv |= SwInvalidateFlags::Size | SwInvalidateFlags::Direction;
+
+ GetLayout()->InvalidateAllContent( nInv );
+
+ SwFrame::CheckPageDescs( static_cast<SwPageFrame*>(GetLayout()->Lower()) );
+
+ EndAction();
+ UnlockPaint();
+}
+
+SwRootFrame *SwViewShell::GetLayout() const
+{
+ return mpLayout.get();
+}
+
+vcl::RenderContext& SwViewShell::GetRefDev() const
+{
+ OutputDevice* pTmpOut = nullptr;
+ if ( GetWin() &&
+ GetViewOptions()->getBrowseMode() &&
+ !GetViewOptions()->IsPrtFormat() )
+ pTmpOut = GetWin()->GetOutDev();
+ else
+ pTmpOut = GetDoc()->getIDocumentDeviceAccess().getReferenceDevice( true );
+
+ return *pTmpOut;
+}
+
+const SwNodes& SwViewShell::GetNodes() const
+{
+ return mxDoc->GetNodes();
+}
+
+void SwViewShell::DrawSelChanged()
+{
+}
+
+Size SwViewShell::GetDocSize() const
+{
+ Size aSz;
+ const SwRootFrame* pRoot = GetLayout();
+ if( pRoot )
+ aSz = pRoot->getFrameArea().SSize();
+
+ return aSz;
+}
+
+SfxItemPool& SwViewShell::GetAttrPool()
+{
+ return GetDoc()->GetAttrPool();
+}
+
+void SwViewShell::ApplyViewOptions( const SwViewOption &rOpt )
+{
+ for(SwViewShell& rSh : GetRingContainer())
+ rSh.StartAction();
+
+ ImplApplyViewOptions( rOpt );
+
+ // With one layout per view it is no longer necessary
+ // to sync these "layout related" view options
+ // But as long as we have to disable "multiple layout"
+
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if(&rSh == this)
+ continue;
+ SwViewOption aOpt( *rSh.GetViewOptions() );
+ aOpt.SetFieldName( rOpt.IsFieldName() );
+ aOpt.SetShowHiddenField( rOpt.IsShowHiddenField() );
+ aOpt.SetShowHiddenPara( rOpt.IsShowHiddenPara() );
+ aOpt.SetShowHiddenChar( rOpt.IsShowHiddenChar() );
+ aOpt.SetViewLayoutBookMode( rOpt.IsViewLayoutBookMode() );
+ aOpt.SetHideWhitespaceMode(rOpt.IsHideWhitespaceMode());
+ aOpt.SetViewLayoutColumns(rOpt.GetViewLayoutColumns());
+ aOpt.SetPostIts(rOpt.IsPostIts());
+ if ( !(aOpt == *rSh.GetViewOptions()) )
+ rSh.ImplApplyViewOptions( aOpt );
+ }
+ // End of disabled multiple window
+
+ for(SwViewShell& rSh : GetRingContainer())
+ rSh.EndAction();
+}
+
+static bool
+IsCursorInFieldmarkHidden(SwPaM const& rCursor, sw::FieldmarkMode const eMode)
+{
+ if (eMode == sw::FieldmarkMode::ShowBoth)
+ {
+ return false;
+ }
+ IDocumentMarkAccess const& rIDMA(*rCursor.GetDoc().getIDocumentMarkAccess());
+ // iterate, for nested fieldmarks
+ for (auto iter = rIDMA.getFieldmarksBegin(); iter != rIDMA.getFieldmarksEnd(); ++iter)
+ {
+ if (*rCursor.GetPoint() <= (**iter).GetMarkStart())
+ {
+ return false;
+ }
+ if (*rCursor.GetPoint() < (**iter).GetMarkEnd())
+ {
+ SwPosition const sepPos(sw::mark::FindFieldSep(
+ dynamic_cast<sw::mark::IFieldmark&>(**iter)));
+ if (eMode == sw::FieldmarkMode::ShowResult)
+ {
+ if (*rCursor.GetPoint() <= sepPos
+ && *rCursor.GetPoint() != (**iter).GetMarkStart())
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (sepPos < *rCursor.GetPoint())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
+{
+ if (*mpOpt == rOpt)
+ return;
+
+ vcl::Window *pMyWin = GetWin();
+ if( !pMyWin )
+ {
+ OSL_ENSURE( pMyWin, "SwViewShell::ApplyViewOptions: no window" );
+ return;
+ }
+
+ CurrShell aCurr( this );
+
+ bool bReformat = false;
+
+ if( mpOpt->IsShowHiddenField() != rOpt.IsShowHiddenField() )
+ {
+ static_cast<SwHiddenTextFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenText ))->
+ SetHiddenFlag( !rOpt.IsShowHiddenField() );
+ bReformat = true;
+ }
+ if ( mpOpt->IsShowHiddenPara() != rOpt.IsShowHiddenPara() )
+ {
+ SwHiddenParaFieldType* pFieldType = static_cast<SwHiddenParaFieldType*>(GetDoc()->
+ getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenPara));
+ if( pFieldType && pFieldType->HasWriterListeners() )
+ pFieldType->PrintHiddenPara();
+ bReformat = true;
+ }
+ if ( !bReformat && mpOpt->IsShowHiddenChar() != rOpt.IsShowHiddenChar() )
+ {
+ bReformat = GetDoc()->ContainsHiddenChars();
+ }
+ if ( mpOpt->IsShowChangesInMargin() != rOpt.IsShowChangesInMargin() ||
+ mpOpt->IsShowChangesInMargin2() != rOpt.IsShowChangesInMargin2() )
+ {
+ if (rOpt.IsShowChangesInMargin())
+ GetDoc()->GetDocumentRedlineManager().HideAll(
+ /*bDeletion=*/!rOpt.IsShowChangesInMargin2() );
+ else
+ GetDoc()->GetDocumentRedlineManager().ShowAll();
+ GetLayout()->SetHideRedlines( false );
+ }
+
+ // bReformat becomes true, if ...
+ // - fieldnames apply or not ...
+ // ( - SwEndPortion must _no_ longer be generated. )
+ // - Of course, the screen is something completely different than the printer ...
+ bool const isToggleFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName());
+
+ if (mpOpt->IsFieldName() != rOpt.IsFieldName()
+ || mpOpt->IsParagraph() != rOpt.IsParagraph())
+ {
+ GetLayout()->SetFieldmarkMode( rOpt.IsFieldName()
+ ? sw::FieldmarkMode::ShowCommand
+ : sw::FieldmarkMode::ShowResult,
+ rOpt.IsParagraph()
+ ? sw::ParagraphBreakMode::Shown
+ : sw::ParagraphBreakMode::Hidden);
+ bReformat = true;
+ }
+
+ // The map mode is changed, minima/maxima will be attended by UI
+ if( mpOpt->GetZoom() != rOpt.GetZoom() && !IsPreview() )
+ {
+ MapMode aMode( pMyWin->GetMapMode() );
+ Fraction aNewFactor( rOpt.GetZoom(), 100 );
+ aMode.SetScaleX( aNewFactor );
+ aMode.SetScaleY( aNewFactor );
+ pMyWin->SetMapMode( aMode );
+ // if not a reference device (printer) is used for formatting,
+ // but the screen, new formatting is needed for zoomfactor changes.
+ if (mpOpt->getBrowseMode() || mpOpt->IsWhitespaceHidden())
+ bReformat = true;
+ }
+
+ bool bBrowseModeChanged = false;
+ if( mpOpt->getBrowseMode() != rOpt.getBrowseMode() )
+ {
+ bBrowseModeChanged = true;
+ bReformat = true;
+ }
+ else if( mpOpt->getBrowseMode() && mpOpt->IsPrtFormat() != rOpt.IsPrtFormat() )
+ bReformat = true;
+
+ bool bHideWhitespaceModeChanged = false;
+ if (mpOpt->IsWhitespaceHidden() != rOpt.IsWhitespaceHidden())
+ {
+ // When whitespace is hidden, view change needs reformatting.
+ bHideWhitespaceModeChanged = true;
+ bReformat = true;
+ }
+
+ if ( HasDrawView() || rOpt.IsGridVisible() )
+ {
+ if ( !HasDrawView() )
+ MakeDrawView();
+
+ SwDrawView *pDView = Imp()->GetDrawView();
+ if ( pDView->IsDragStripes() != rOpt.IsCrossHair() )
+ pDView->SetDragStripes( rOpt.IsCrossHair() );
+
+ if ( pDView->IsGridSnap() != rOpt.IsSnap() )
+ pDView->SetGridSnap( rOpt.IsSnap() );
+
+ if ( pDView->IsGridVisible() != rOpt.IsGridVisible() )
+ pDView->SetGridVisible( rOpt.IsGridVisible() );
+
+ const Size &rSz = rOpt.GetSnapSize();
+ pDView->SetGridCoarse( rSz );
+
+ const Size aFSize
+ ( rSz.Width() ? rSz.Width() / (rOpt.GetDivisionX()+1) : 0,
+ rSz.Height()? rSz.Height()/ (rOpt.GetDivisionY()+1) : 0);
+ pDView->SetGridFine( aFSize );
+ Fraction aSnGrWdtX(rSz.Width(), rOpt.GetDivisionX() + 1);
+ Fraction aSnGrWdtY(rSz.Height(), rOpt.GetDivisionY() + 1);
+ pDView->SetSnapGridWidth( aSnGrWdtX, aSnGrWdtY );
+
+ // set handle size to 9 pixels, always
+ pDView->SetMarkHdlSizePixel(9);
+ }
+
+ bool bOnlineSpellChgd = mpOpt->IsOnlineSpell() != rOpt.IsOnlineSpell();
+
+ *mpOpt = rOpt; // First the options are taken.
+ mpOpt->SetUIOptions(rOpt);
+
+ mxDoc->GetDocumentSettingManager().set(DocumentSettingId::HTML_MODE, 0 != ::GetHtmlMode(mxDoc->GetDocShell()));
+
+ if( bBrowseModeChanged || bHideWhitespaceModeChanged )
+ {
+ // #i44963# Good occasion to check if page sizes in
+ // page descriptions are still set to (LONG_MAX, LONG_MAX) (html import)
+ mxDoc->CheckDefaultPageFormat();
+ InvalidateLayout( true );
+ }
+
+ SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(GetSfxViewShell()->GetCurrentDocument());
+ SfxLokHelper::notifyViewRenderState(GetSfxViewShell(), pModel);
+
+ pMyWin->Invalidate();
+ if ( bReformat )
+ {
+ // Nothing helps, we need to send all ContentFrames a
+ // Prepare, we format anew:
+ StartAction();
+ Reformat();
+ EndAction();
+ }
+
+ if (isToggleFieldNames)
+ {
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if (SwCursorShell *const pSh = dynamic_cast<SwCursorShell *>(&rSh))
+ {
+ if ((mpOpt->IsFieldName() && pSh->CursorInsideInputField())
+ || IsCursorInFieldmarkHidden(*pSh->GetCursor(),
+ pSh->GetLayout()->GetFieldmarkMode()))
+ { // move cursor out of field
+ pSh->Left(1, SwCursorSkipMode::Chars);
+ }
+ }
+ }
+ // the layout changes but SetModified() wasn't called so do it here:
+ mxDoc->GetDocumentLayoutManager().ClearSwLayouterEntries();
+ }
+
+ if( !bOnlineSpellChgd )
+ return;
+
+ if ( !comphelper::LibreOfficeKit::isActive() )
+ {
+ bool bOnlineSpl = rOpt.IsOnlineSpell();
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if(&rSh == this)
+ continue;
+ rSh.mpOpt->SetOnlineSpell( bOnlineSpl );
+ vcl::Window *pTmpWin = rSh.GetWin();
+ if( pTmpWin )
+ pTmpWin->Invalidate();
+ }
+ }
+}
+
+void SwViewShell::SetUIOptions( const SwViewOption &rOpt )
+{
+ mpOpt->SetUIOptions(rOpt);
+ //the API-Flag of the view options is set but never reset
+ //it is required to set scroll bars in readonly documents
+ if(rOpt.IsStarOneSetting())
+ mpOpt->SetStarOneSetting(true);
+
+ mpOpt->SetSymbolFont(rOpt.GetSymbolFont());
+}
+
+void SwViewShell::SetReadonlyOption(bool bSet)
+{
+ //JP 01.02.99: at readonly flag query properly
+ // and if need be format; Bug 61335
+
+ // Are we switching from readonly to edit?
+ if( bSet == mpOpt->IsReadonly() )
+ return;
+
+ // so that the flags can be queried properly.
+ mpOpt->SetReadonly( false );
+
+ bool bReformat = mpOpt->IsFieldName();
+
+ mpOpt->SetReadonly( bSet );
+
+ if( bReformat )
+ {
+ StartAction();
+ Reformat();
+ if ( GetWin() )
+ GetWin()->Invalidate();
+ EndAction();
+ }
+ else if ( GetWin() )
+ GetWin()->Invalidate();
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( Imp()->IsAccessible() )
+ Imp()->InvalidateAccessibleEditableState( false );
+#endif
+}
+
+void SwViewShell::SetPDFExportOption(bool bSet)
+{
+ if( bSet != mpOpt->IsPDFExport() )
+ {
+ if( bSet && mpOpt->getBrowseMode() )
+ mpOpt->SetPrtFormat( true );
+ mpOpt->SetPDFExport(bSet);
+ }
+}
+
+void SwViewShell::SetReadonlySelectionOption(bool bSet)
+{
+ if( bSet != mpOpt->IsSelectionInReadonly() )
+ {
+ mpOpt->SetSelectionInReadonly(bSet);
+ }
+}
+
+void SwViewShell::SetPrtFormatOption( bool bSet )
+{
+ mpOpt->SetPrtFormat( bSet );
+}
+
+void SwViewShell::UISizeNotify()
+{
+ if ( mbDocSizeChgd )
+ {
+ mbDocSizeChgd = false;
+ bool bOld = bInSizeNotify;
+ bInSizeNotify = true;
+ ::SizeNotify( this, GetDocSize() );
+ bInSizeNotify = bOld;
+ }
+}
+
+void SwViewShell::SetRestoreActions(sal_uInt16 nSet)
+{
+ OSL_ENSURE(!GetRestoreActions()||!nSet, "multiple restore of the Actions ?");
+ Imp()->SetRestoreActions(nSet);
+}
+sal_uInt16 SwViewShell::GetRestoreActions() const
+{
+ return Imp()->GetRestoreActions();
+}
+
+bool SwViewShell::IsNewLayout() const
+{
+ return GetLayout()->IsNewLayout();
+}
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+uno::Reference< css::accessibility::XAccessible > SwViewShell::CreateAccessible()
+{
+ uno::Reference< css::accessibility::XAccessible > xAcc;
+
+ // We require a layout and an XModel to be accessible.
+ OSL_ENSURE( mpLayout, "no layout, no access" );
+ OSL_ENSURE( GetWin(), "no window, no access" );
+
+ if( mxDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && GetWin() )
+ xAcc = Imp()->GetAccessibleMap().GetDocumentView();
+
+ return xAcc;
+}
+
+uno::Reference< css::accessibility::XAccessible > SwViewShell::CreateAccessiblePreview()
+{
+ OSL_ENSURE( IsPreview(),
+ "Can't create accessible preview for non-preview SwViewShell" );
+
+ // We require a layout and an XModel to be accessible.
+ OSL_ENSURE( mpLayout, "no layout, no access" );
+ OSL_ENSURE( GetWin(), "no window, no access" );
+
+ if ( IsPreview() && GetLayout()&& GetWin() )
+ {
+ return Imp()->GetAccessibleMap().GetDocumentPreview(
+ PagePreviewLayout()->maPreviewPages,
+ GetWin()->GetMapMode().GetScaleX(),
+ GetLayout()->GetPageByPageNum( PagePreviewLayout()->mnSelectedPageNum ),
+ PagePreviewLayout()->maWinSize );
+ }
+ return nullptr;
+}
+
+void SwViewShell::InvalidateAccessibleFocus()
+{
+ if( Imp() && Imp()->IsAccessible() )
+ Imp()->GetAccessibleMap().InvalidateFocus();
+}
+
+/**
+ * invalidate CONTENT_FLOWS_FROM/_TO relation for paragraphs #i27138#
+ */
+void SwViewShell::InvalidateAccessibleParaFlowRelation( const SwTextFrame* _pFromTextFrame,
+ const SwTextFrame* _pToTextFrame )
+{
+ if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
+ {
+ Imp()->InvalidateAccessibleParaFlowRelation_( _pFromTextFrame, _pToTextFrame );
+ }
+}
+
+/**
+ * invalidate text selection for paragraphs #i27301#
+ */
+void SwViewShell::InvalidateAccessibleParaTextSelection()
+{
+ if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
+ {
+ Imp()->InvalidateAccessibleParaTextSelection_();
+ }
+}
+
+/**
+ * invalidate attributes for paragraphs #i88069#
+ */
+void SwViewShell::InvalidateAccessibleParaAttrs( const SwTextFrame& rTextFrame )
+{
+ if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
+ {
+ Imp()->InvalidateAccessibleParaAttrs_( rTextFrame );
+ }
+}
+
+SwAccessibleMap* SwViewShell::GetAccessibleMap()
+{
+ if ( Imp()->IsAccessible() )
+ {
+ return &(Imp()->GetAccessibleMap());
+ }
+
+ return nullptr;
+}
+
+void SwViewShell::ApplyAccessibilityOptions()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+ if (mpOpt->IsPagePreview() && !officecfg::Office::Common::Accessibility::IsForPagePreviews::get())
+ {
+ mpAccOptions->SetAlwaysAutoColor(false);
+ mpAccOptions->SetStopAnimatedGraphics(false);
+ }
+ else
+ {
+ mpAccOptions->SetAlwaysAutoColor(SvtAccessibilityOptions::GetIsAutomaticFontColor());
+ mpAccOptions->SetStopAnimatedGraphics(! SvtAccessibilityOptions::GetIsAllowAnimatedGraphics());
+
+ // Form view
+ // Always set this option, not only if document is read-only:
+ mpOpt->SetSelectionInReadonly(SvtAccessibilityOptions::IsSelectionInReadonly());
+ }
+}
+#endif // ENABLE_WASM_STRIP_ACCESSIBILITY
+
+ShellResource* SwViewShell::GetShellRes()
+{
+ return spShellRes;
+}
+
+void SwViewShell::SetCareDialog(const std::shared_ptr<weld::Window>& rNew)
+{
+ (*spCareDialog.get()) = rNew;
+}
+
+sal_uInt16 SwViewShell::GetPageCount() const
+{
+ return GetLayout() ? GetLayout()->GetPageNum() : 1;
+}
+
+Size SwViewShell::GetPageSize( sal_uInt16 nPageNum, bool bSkipEmptyPages ) const
+{
+ Size aSize;
+ const SwRootFrame* pTmpRoot = GetLayout();
+ if( pTmpRoot && nPageNum )
+ {
+ const SwPageFrame* pPage = static_cast<const SwPageFrame*>
+ (pTmpRoot->Lower());
+
+ while( --nPageNum && pPage->GetNext() )
+ pPage = static_cast<const SwPageFrame*>( pPage->GetNext() );
+
+ if( !bSkipEmptyPages && pPage->IsEmptyPage() && pPage->GetNext() )
+ pPage = static_cast<const SwPageFrame*>( pPage->GetNext() );
+
+ aSize = pPage->getFrameArea().SSize();
+ }
+ return aSize;
+}
+
+void SwViewShell::OnGraphicArrived(const SwRect& rRect)
+{
+ for(SwViewShell& rShell : GetRingContainer())
+ {
+ CurrShell aCurr(&rShell);
+ if(rShell.IsPreview())
+ {
+ if(rShell.GetWin())
+ ::RepaintPagePreview(&rShell, rRect);
+ }
+ else if(rShell.VisArea().Overlaps(rRect) && OUTDEV_WINDOW == rShell.GetOut()->GetOutDevType())
+ {
+ // invalidate instead of painting
+ rShell.GetWin()->Invalidate(rRect.SVRect());
+ }
+ }
+}
+// #i12836# enhanced pdf export
+sal_Int32 SwViewShell::GetPageNumAndSetOffsetForPDF( OutputDevice& rOut, const SwRect& rRect ) const
+{
+ OSL_ENSURE( GetLayout(), "GetPageNumAndSetOffsetForPDF assumes presence of layout" );
+
+ sal_Int32 nRet = -1;
+
+ // #i40059# Position out of bounds:
+ SwRect aRect( rRect );
+ aRect.Pos().setX( std::max( aRect.Left(), GetLayout()->getFrameArea().Left() ) );
+
+ const SwPageFrame* pPage = GetLayout()->GetPageAtPos( aRect.Center() );
+ if ( pPage )
+ {
+ OSL_ENSURE( pPage, "GetPageNumAndSetOffsetForPDF: No page found" );
+
+ Point aOffset( pPage->getFrameArea().Pos() );
+ aOffset.setX( -aOffset.X() );
+ aOffset.setY( -aOffset.Y() );
+
+ MapMode aMapMode( rOut.GetMapMode() );
+ aMapMode.SetOrigin( aOffset );
+ rOut.SetMapMode( aMapMode );
+
+ nRet = pPage->GetPhyPageNum() - 1;
+ }
+
+ return nRet;
+}
+
+// --> PB 2007-05-30 #146850#
+const BitmapEx& SwViewShell::GetReplacementBitmap( bool bIsErrorState )
+{
+ if (bIsErrorState)
+ {
+ if (!m_xErrorBmp)
+ m_xErrorBmp.reset(new BitmapEx(RID_GRAPHIC_ERRORBMP));
+ return *m_xErrorBmp;
+ }
+
+ if (!m_xReplaceBmp)
+ m_xReplaceBmp.reset(new BitmapEx(RID_GRAPHIC_REPLACEBMP));
+ return *m_xReplaceBmp;
+}
+
+void SwViewShell::DeleteReplacementBitmaps()
+{
+ m_xErrorBmp.reset();
+ m_xReplaceBmp.reset();
+}
+
+SwPostItMgr* SwViewShell::GetPostItMgr()
+{
+ SwView* pView = GetDoc()->GetDocShell() ? GetDoc()->GetDocShell()->GetView() : nullptr;
+ if ( pView )
+ return pView->GetPostItMgr();
+
+ return nullptr;
+}
+
+void SwViewShell::GetFirstLastVisPageNumbers(SwVisiblePageNumbers& rVisiblePageNumbers)
+{
+ SwView* pView = GetDoc()->GetDocShell() ? GetDoc()->GetDocShell()->GetView() : nullptr;
+ if (!pView)
+ return;
+ SwRect rViewVisArea(pView->GetVisArea());
+ vcl::RenderContext* pRenderContext = GetOut();
+ const SwPageFrame* pPageFrame = Imp()->GetFirstVisPage(pRenderContext);
+ SwRect rPageRect = pPageFrame->getFrameArea();
+ rPageRect.AddBottom(-pPageFrame->GetBottomMargin());
+ while (!rPageRect.Overlaps(rViewVisArea) && pPageFrame->GetNext())
+ {
+ pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
+ rPageRect = pPageFrame->getFrameArea();
+ if (rPageRect.Top() > 0)
+ rPageRect.AddBottom(-pPageFrame->GetBottomMargin());
+ }
+ rVisiblePageNumbers.nFirstPhy = pPageFrame->GetPhyPageNum();
+ rVisiblePageNumbers.nFirstVirt = pPageFrame->GetVirtPageNum();
+ const SvxNumberType& rFirstVisNum = pPageFrame->GetPageDesc()->GetNumType();
+ rVisiblePageNumbers.sFirstCustomPhy = rFirstVisNum.GetNumStr(rVisiblePageNumbers.nFirstPhy);
+ rVisiblePageNumbers.sFirstCustomVirt = rFirstVisNum.GetNumStr(rVisiblePageNumbers.nFirstVirt);
+ pPageFrame = Imp()->GetLastVisPage(pRenderContext);
+ rPageRect = pPageFrame->getFrameArea();
+ rPageRect.AddTop(pPageFrame->GetTopMargin());
+ while (!rPageRect.Overlaps(rViewVisArea) && pPageFrame->GetPrev())
+ {
+ pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetPrev());
+ rPageRect = pPageFrame->getFrameArea();
+ rPageRect.AddTop(pPageFrame->GetTopMargin());
+ }
+ rVisiblePageNumbers.nLastPhy = pPageFrame->GetPhyPageNum();
+ rVisiblePageNumbers.nLastVirt = pPageFrame->GetVirtPageNum();
+ const SvxNumberType& rLastVisNum = pPageFrame->GetPageDesc()->GetNumType();
+ rVisiblePageNumbers.sLastCustomPhy = rLastVisNum.GetNumStr(rVisiblePageNumbers.nLastPhy);
+ rVisiblePageNumbers.sLastCustomVirt = rLastVisNum.GetNumStr(rVisiblePageNumbers.nLastVirt);
+}
+
+/*
+ * Document Interface Access
+ */
+const IDocumentSettingAccess& SwViewShell::getIDocumentSettingAccess() const { return mxDoc->GetDocumentSettingManager(); }
+IDocumentSettingAccess& SwViewShell::getIDocumentSettingAccess() { return mxDoc->GetDocumentSettingManager(); }
+const IDocumentDeviceAccess& SwViewShell::getIDocumentDeviceAccess() const { return mxDoc->getIDocumentDeviceAccess(); }
+IDocumentDeviceAccess& SwViewShell::getIDocumentDeviceAccess() { return mxDoc->getIDocumentDeviceAccess(); }
+const IDocumentMarkAccess* SwViewShell::getIDocumentMarkAccess() const { return mxDoc->getIDocumentMarkAccess(); }
+IDocumentMarkAccess* SwViewShell::getIDocumentMarkAccess() { return mxDoc->getIDocumentMarkAccess(); }
+const IDocumentDrawModelAccess& SwViewShell::getIDocumentDrawModelAccess() const { return mxDoc->getIDocumentDrawModelAccess(); }
+IDocumentDrawModelAccess& SwViewShell::getIDocumentDrawModelAccess() { return mxDoc->getIDocumentDrawModelAccess(); }
+const IDocumentRedlineAccess& SwViewShell::getIDocumentRedlineAccess() const { return mxDoc->getIDocumentRedlineAccess(); }
+IDocumentRedlineAccess& SwViewShell::getIDocumentRedlineAccess() { return mxDoc->getIDocumentRedlineAccess(); }
+const IDocumentLayoutAccess& SwViewShell::getIDocumentLayoutAccess() const { return mxDoc->getIDocumentLayoutAccess(); }
+IDocumentLayoutAccess& SwViewShell::getIDocumentLayoutAccess() { return mxDoc->getIDocumentLayoutAccess(); }
+IDocumentContentOperations& SwViewShell::getIDocumentContentOperations() { return mxDoc->getIDocumentContentOperations(); }
+IDocumentStylePoolAccess& SwViewShell::getIDocumentStylePoolAccess() { return mxDoc->getIDocumentStylePoolAccess(); }
+const IDocumentStatistics& SwViewShell::getIDocumentStatistics() const { return mxDoc->getIDocumentStatistics(); }
+
+IDocumentUndoRedo & SwViewShell::GetIDocumentUndoRedo()
+{ return mxDoc->GetIDocumentUndoRedo(); }
+IDocumentUndoRedo const& SwViewShell::GetIDocumentUndoRedo() const
+{ return mxDoc->GetIDocumentUndoRedo(); }
+
+// --> OD 2007-11-14 #i83479#
+const IDocumentListItems* SwViewShell::getIDocumentListItemsAccess() const
+{
+ return &mxDoc->getIDocumentListItems();
+}
+
+const IDocumentOutlineNodes* SwViewShell::getIDocumentOutlineNodesAccess() const
+{
+ return &mxDoc->getIDocumentOutlineNodes();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */