summaryrefslogtreecommitdiffstats
path: root/sw/source/core/view
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
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')
-rw-r--r--sw/source/core/view/dialoghelp.cxx47
-rw-r--r--sw/source/core/view/pagepreviewlayout.cxx1465
-rw-r--r--sw/source/core/view/printdata.cxx447
-rw-r--r--sw/source/core/view/vdraw.cxx280
-rw-r--r--sw/source/core/view/viewimp.cxx528
-rw-r--r--sw/source/core/view/viewpg.cxx216
-rw-r--r--sw/source/core/view/viewsh.cxx2849
-rw-r--r--sw/source/core/view/vnew.cxx383
-rw-r--r--sw/source/core/view/vprint.cxx676
9 files changed, 6891 insertions, 0 deletions
diff --git a/sw/source/core/view/dialoghelp.cxx b/sw/source/core/view/dialoghelp.cxx
new file mode 100644
index 0000000000..88d12484d2
--- /dev/null
+++ b/sw/source/core/view/dialoghelp.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/frame.hxx>
+#include <vcl/weld.hxx>
+
+#include <dialoghelp.hxx>
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <view.hxx>
+
+weld::Window* GetFrameWeld(const SfxFrame* pFrame)
+{
+ return pFrame ? pFrame->GetWindow().GetFrameWeld() : nullptr;
+}
+
+weld::Window* GetFrameWeld(const SfxMedium* pMedium)
+{
+ return GetFrameWeld(pMedium ? pMedium->GetLoadTargetFrame() : nullptr);
+}
+
+weld::Window* GetFrameWeld(SwDocShell* pDocShell)
+{
+ if (!pDocShell)
+ return nullptr;
+ weld::Window* pRet = GetFrameWeld(pDocShell->GetMedium());
+ if (!pRet)
+ {
+ if (SwView* pView = pDocShell->GetView())
+ pRet = pView->GetFrameWeld();
+ }
+ return pRet;
+}
+
+weld::Window* GetFrameWeld(SwDoc* pDoc)
+{
+ return GetFrameWeld(pDoc ? pDoc->GetDocShell() : nullptr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/source/core/view/pagepreviewlayout.cxx b/sw/source/core/view/pagepreviewlayout.cxx
new file mode 100644
index 0000000000..5fc740ebfd
--- /dev/null
+++ b/sw/source/core/view/pagepreviewlayout.cxx
@@ -0,0 +1,1465 @@
+/* -*- 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 <config_wasm_strip.h>
+
+#include <pagepreviewlayout.hxx>
+#include <prevwpage.hxx>
+
+#include <algorithm>
+#include <osl/diagnose.h>
+#include <tools/fract.hxx>
+#include <vcl/settings.hxx>
+
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <viewsh.hxx>
+#include <viewimp.hxx>
+#include <viewopt.hxx>
+#include <swregion.hxx>
+#include <strings.hrc>
+#include <frmtool.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <printdata.hxx>
+#include <paintfrm.hxx>
+
+#include <IDocumentDeviceAccess.hxx>
+
+// methods to initialize page preview layout
+
+SwPagePreviewLayout::SwPagePreviewLayout( SwViewShell& _rParentViewShell,
+ const SwRootFrame& _rLayoutRootFrame )
+ : mrParentViewShell( _rParentViewShell ),
+ mrLayoutRootFrame ( _rLayoutRootFrame )
+{
+ Clear_();
+
+ mbBookPreview = false;
+ mbBookPreviewModeToggled = false;
+
+ mbPrintEmptyPages = mrParentViewShell.getIDocumentDeviceAccess().getPrintData().IsPrintEmptyPages();
+}
+
+void SwPagePreviewLayout::Clear_()
+{
+ mbLayoutInfoValid = mbLayoutSizesValid = mbPaintInfoValid = false;
+
+ maWinSize.setWidth( 0 );
+ maWinSize.setHeight( 0 );
+ mnCols = mnRows = 0;
+
+ ClearPreviewLayoutSizes();
+
+ mbDoesLayoutRowsFitIntoWindow = false;
+ mbDoesLayoutColsFitIntoWindow = false;
+
+ mnPaintPhyStartPageNum = 0;
+ mnPaintStartCol = mnPaintStartRow = 0;
+ mbNoPageVisible = false;
+ maPaintStartPageOffset.setX( 0 );
+ maPaintStartPageOffset.setY( 0 );
+ maPaintPreviewDocOffset.setX( 0 );
+ maPaintPreviewDocOffset.setY( 0 );
+ maAdditionalPaintOffset.setX( 0 );
+ maAdditionalPaintOffset.setY( 0 );
+ maPaintedPreviewDocRect.SetLeft( 0 );
+ maPaintedPreviewDocRect.SetTop( 0 );
+ maPaintedPreviewDocRect.SetRight( 0 );
+ maPaintedPreviewDocRect.SetBottom( 0 );
+ mnSelectedPageNum = 0;
+ ClearPreviewPageData();
+
+ mbInPaint = false;
+ mbNewLayoutDuringPaint = false;
+}
+
+void SwPagePreviewLayout::ClearPreviewLayoutSizes()
+{
+ mnPages = 0;
+
+ maMaxPageSize.setWidth( 0 );
+ maMaxPageSize.setHeight( 0 );
+ maPreviewDocRect.SetLeft( 0 );
+ maPreviewDocRect.SetTop( 0 );
+ maPreviewDocRect.SetRight( 0 );
+ maPreviewDocRect.SetBottom( 0 );
+ mnColWidth = mnRowHeight = 0;
+ mnPreviewLayoutWidth = mnPreviewLayoutHeight = 0;
+}
+
+void SwPagePreviewLayout::ClearPreviewPageData()
+{
+ maPreviewPages.clear();
+}
+
+/** calculate page preview layout sizes
+
+*/
+void SwPagePreviewLayout::CalcPreviewLayoutSizes()
+{
+ vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut();
+ // calculate maximal page size; calculate also number of pages
+
+ const SwPageFrame* pPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
+ while ( pPage )
+ {
+ if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() )
+ {
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ continue;
+ }
+
+ ++mnPages;
+ pPage->Calc(pRenderContext);
+ const Size& rPageSize = pPage->getFrameArea().SSize();
+ if ( rPageSize.Width() > maMaxPageSize.Width() )
+ maMaxPageSize.setWidth( rPageSize.Width() );
+ if ( rPageSize.Height() > maMaxPageSize.Height() )
+ maMaxPageSize.setHeight( rPageSize.Height() );
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ }
+ // calculate and set column width and row height
+ mnColWidth = maMaxPageSize.Width() + gnXFree;
+ mnRowHeight = maMaxPageSize.Height() + gnYFree;
+
+ // calculate and set preview layout width and height
+ mnPreviewLayoutWidth = mnCols * mnColWidth + gnXFree;
+ mnPreviewLayoutHeight = mnRows * mnRowHeight + gnYFree;
+
+ // calculate document rectangle in preview layout
+ {
+ Size aDocSize;
+ // document width
+ aDocSize.setWidth( mnPreviewLayoutWidth );
+
+ // document height
+ // determine number of rows needed for <nPages> in preview layout
+ // use method <GetRowOfPage(..)>.
+ const sal_uInt16 nDocRows = GetRowOfPage( mnPages );
+ aDocSize.setHeight( nDocRows * maMaxPageSize.Height() +
+ (nDocRows+1) * gnYFree );
+ maPreviewDocRect.SetPos( Point( 0, 0 ) );
+ maPreviewDocRect.SetSize( aDocSize );
+ }
+}
+
+/** init page preview layout
+
+ initialize the page preview settings for a given layout.
+
+ side effects:
+ (1) If parameter <_bCalcScale> is true, mapping mode with calculated
+ scaling is set at the output device and the zoom at the view options of
+ the given view shell is set with the calculated scaling.
+*/
+void SwPagePreviewLayout::Init( const sal_uInt16 _nCols,
+ const sal_uInt16 _nRows,
+ const Size& _rPxWinSize
+ )
+{
+ // check environment and parameters
+ {
+ bool bColsRowsValid = (_nCols != 0) && (_nRows != 0);
+ OSL_ENSURE( bColsRowsValid, "preview layout parameters not correct - preview layout can *not* be initialized" );
+ if ( !bColsRowsValid )
+ return;
+
+ bool bPxWinSizeValid = (_rPxWinSize.Width() >= 0) &&
+ (_rPxWinSize.Height() >= 0);
+ OSL_ENSURE( bPxWinSizeValid, "no window size - preview layout can *not* be initialized" );
+ if ( !bPxWinSizeValid )
+ return;
+ }
+
+ // environment and parameters ok
+
+ // clear existing preview settings
+ Clear_();
+
+ // set layout information columns and rows
+ mnCols = _nCols;
+ mnRows = _nRows;
+
+ CalcPreviewLayoutSizes();
+
+ // validate layout information
+ mbLayoutInfoValid = true;
+
+ // calculate scaling
+ MapMode aMapMode( MapUnit::MapTwip );
+ Size aWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize, aMapMode );
+ Fraction aXScale( aWinSize.Width(), mnPreviewLayoutWidth );
+ Fraction aYScale( aWinSize.Height(), mnPreviewLayoutHeight );
+ if( aXScale < aYScale )
+ aYScale = aXScale;
+ {
+ // adjust scaling for Drawing layer.
+ aYScale *= Fraction( 1000, 1 );
+ tools::Long nNewNuminator = aYScale.operator long();
+ if( nNewNuminator < 1 )
+ nNewNuminator = 1;
+ aYScale = Fraction( nNewNuminator, 1000 );
+ // propagate scaling as zoom percentage to view options for font cache
+ ApplyNewZoomAtViewShell( static_cast<sal_uInt8>(nNewNuminator/10) );
+
+ aMapMode.SetScaleY( aYScale );
+ aMapMode.SetScaleX( aYScale );
+ // set created mapping mode with calculated scaling at output device.
+ mrParentViewShell.GetOut()->SetMapMode( aMapMode );
+ // update statics for paint.
+ ::SwCalcPixStatics( mrParentViewShell.GetOut() );
+ }
+
+ // set window size in twips
+ maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize );
+ // validate layout sizes
+ mbLayoutSizesValid = true;
+}
+
+/** apply new zoom at given view shell */
+void SwPagePreviewLayout::ApplyNewZoomAtViewShell( sal_uInt8 _aNewZoom )
+{
+ SwViewOption aNewViewOptions = *(mrParentViewShell.GetViewOptions());
+ if ( aNewViewOptions.GetZoom() != _aNewZoom )
+ {
+ aNewViewOptions.SetZoom( _aNewZoom );
+ //#i19975# - consider zoom type.
+ aNewViewOptions.SetZoomType( SvxZoomType::PERCENT );
+ mrParentViewShell.ApplyViewOptions( aNewViewOptions );
+ }
+}
+
+/** method to adjust page preview layout to document changes
+
+*/
+void SwPagePreviewLayout::ReInit()
+{
+ // check environment and parameters
+ {
+ bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid;
+ OSL_ENSURE( bLayoutSettingsValid,
+ "no valid preview layout info/sizes - no re-init of page preview layout");
+ if ( !bLayoutSettingsValid )
+ return;
+ }
+
+ ClearPreviewLayoutSizes();
+ CalcPreviewLayoutSizes();
+}
+
+// methods to prepare paint of page preview
+
+/** prepare paint of page preview
+
+ delete parameter _onStartPageVirtNum
+
+ @note _nProposedStartPageNum, _onStartPageNum are absolute
+*/
+bool SwPagePreviewLayout::Prepare( const sal_uInt16 _nProposedStartPageNum,
+ const Point& rProposedStartPos,
+ const Size& _rPxWinSize,
+ sal_uInt16& _onStartPageNum,
+ tools::Rectangle& _orDocPreviewPaintRect,
+ const bool _bStartWithPageAtFirstCol
+ )
+{
+ sal_uInt16 nProposedStartPageNum = ConvertAbsoluteToRelativePageNum( _nProposedStartPageNum );
+ // check environment and parameters
+ {
+ bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid;
+ OSL_ENSURE( bLayoutSettingsValid,
+ "no valid preview layout info/sizes - no prepare of preview paint");
+ if ( !bLayoutSettingsValid )
+ return false;
+
+ bool bStartPageRangeValid = nProposedStartPageNum <= mnPages;
+ OSL_ENSURE( bStartPageRangeValid,
+ "proposed start page not existing - no prepare of preview paint");
+ if ( !bStartPageRangeValid )
+ return false;
+
+ bool bStartPosRangeValid =
+ rProposedStartPos.X() >= 0 && rProposedStartPos.Y() >= 0 &&
+ rProposedStartPos.X() <= maPreviewDocRect.Right() &&
+ rProposedStartPos.Y() <= maPreviewDocRect.Bottom();
+ OSL_ENSURE( bStartPosRangeValid,
+ "proposed start position out of range - no prepare of preview paint");
+ if ( !bStartPosRangeValid )
+ return false;
+
+ bool bWinSizeValid = !_rPxWinSize.IsEmpty();
+ OSL_ENSURE( bWinSizeValid, "no window size - no prepare of preview paint");
+ if ( !bWinSizeValid )
+ return false;
+
+ bool bStartInfoValid = _nProposedStartPageNum > 0 ||
+ rProposedStartPos != Point(0,0);
+ if ( !bStartInfoValid )
+ nProposedStartPageNum = 1;
+ }
+
+ // environment and parameter ok
+
+ // update window size at preview setting data
+ maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize );
+
+ mbNoPageVisible = false;
+ if ( nProposedStartPageNum > 0 )
+ {
+ // determine column and row of proposed start page in virtual preview layout
+ const sal_uInt16 nColOfProposed = GetColOfPage( nProposedStartPageNum );
+ const sal_uInt16 nRowOfProposed = GetRowOfPage( nProposedStartPageNum );
+ // determine start page
+ if ( _bStartWithPageAtFirstCol )
+ {
+ // leaving left-top-corner blank is
+ // controlled by <mbBookPreview>.
+ if ( mbBookPreview &&
+ ( nProposedStartPageNum == 1 || nRowOfProposed == 1 )
+ )
+ mnPaintPhyStartPageNum = 1;
+ else
+ mnPaintPhyStartPageNum = nProposedStartPageNum - (nColOfProposed-1);
+ }
+ else
+ mnPaintPhyStartPageNum = nProposedStartPageNum;
+
+ mnPaintPhyStartPageNum = ConvertRelativeToAbsolutePageNum( mnPaintPhyStartPageNum );
+
+ // set starting column
+ if ( _bStartWithPageAtFirstCol )
+ mnPaintStartCol = 1;
+ else
+ mnPaintStartCol = nColOfProposed;
+ // set starting row
+ mnPaintStartRow = nRowOfProposed;
+ // page offset == (-1,-1), indicating no offset and paint of free space.
+ maPaintStartPageOffset.setX( -1 );
+ maPaintStartPageOffset.setY( -1 );
+ // virtual preview document offset.
+ if ( _bStartWithPageAtFirstCol )
+ maPaintPreviewDocOffset.setX( 0 );
+ else
+ maPaintPreviewDocOffset.setX( (nColOfProposed-1) * mnColWidth );
+ maPaintPreviewDocOffset.setY( (nRowOfProposed-1) * mnRowHeight );
+ }
+ else
+ {
+ // determine column and row of proposed start position.
+ // Note: paint starts at point (0,0)
+ const sal_uInt16 nColOfProposed =
+ o3tl::narrowing<sal_uInt16>(rProposedStartPos.X() / mnColWidth) + 1;
+ const sal_uInt16 nRowOfProposed =
+ o3tl::narrowing<sal_uInt16>(rProposedStartPos.Y() / mnRowHeight) + 1;
+ // determine start page == page at proposed start position
+ // leaving left-top-corner blank is
+ // controlled by <mbBookPreview>.
+ if ( mbBookPreview &&
+ ( nRowOfProposed == 1 && nColOfProposed == 1 )
+ )
+ mnPaintPhyStartPageNum = 1;
+ else
+ {
+ // leaving left-top-corner blank is
+ // controlled by <mbBookPreview>.
+ mnPaintPhyStartPageNum = (nRowOfProposed-1) * mnCols + nColOfProposed;
+ if ( mbBookPreview )
+ --mnPaintPhyStartPageNum;
+ if ( mnPaintPhyStartPageNum > mnPages )
+ {
+ // no page will be visible, because shown part of document
+ // preview is the last row to the right of the last page
+ mnPaintPhyStartPageNum = mnPages;
+ mbNoPageVisible = true;
+ }
+ }
+ // set starting column and starting row
+ mnPaintStartCol = nColOfProposed;
+ mnPaintStartRow = nRowOfProposed;
+ // page offset
+ maPaintStartPageOffset.setX(
+ (rProposedStartPos.X() % mnColWidth) - gnXFree );
+ maPaintStartPageOffset.setY(
+ (rProposedStartPos.Y() % mnRowHeight) - gnYFree );
+ // virtual preview document offset.
+ maPaintPreviewDocOffset = rProposedStartPos;
+ }
+
+ // determine additional paint offset, if preview layout fits into window.
+ CalcAdditionalPaintOffset();
+
+ // determine rectangle to be painted from document preview
+ CalcDocPreviewPaintRect();
+ _orDocPreviewPaintRect = maPaintedPreviewDocRect;
+
+ // shift visible preview document area to the left,
+ // if on the right is an area left blank.
+ if ( !mbDoesLayoutColsFitIntoWindow &&
+ maPaintedPreviewDocRect.GetWidth() < maWinSize.Width() )
+ {
+ maPaintedPreviewDocRect.Move(
+ -(maWinSize.Width() - maPaintedPreviewDocRect.GetWidth()), 0 );
+ Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
+ _rPxWinSize, _onStartPageNum,
+ _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
+ }
+
+ // shift visible preview document area to the top,
+ // if on the bottom is an area left blank.
+ if ( mbBookPreviewModeToggled &&
+ maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom() &&
+ maPaintedPreviewDocRect.GetHeight() < maWinSize.Height() )
+ {
+ if ( mbDoesLayoutRowsFitIntoWindow )
+ {
+ if ( maPaintedPreviewDocRect.GetHeight() < mnPreviewLayoutHeight)
+ {
+ maPaintedPreviewDocRect.Move(
+ 0, -(mnPreviewLayoutHeight - maPaintedPreviewDocRect.GetHeight()) );
+ Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
+ _rPxWinSize, _onStartPageNum,
+ _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
+ }
+ }
+ else
+ {
+ maPaintedPreviewDocRect.Move(
+ 0, -(maWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) );
+ Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
+ _rPxWinSize, _onStartPageNum,
+ _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
+ }
+ }
+
+ // determine preview pages - visible pages with needed data for paint and
+ // accessible pages with needed data.
+ CalcPreviewPages();
+
+ // OD 07.11.2003 #i22014# - indicate new layout, if print preview is in paint
+ if ( mbInPaint )
+ {
+ mbNewLayoutDuringPaint = true;
+ }
+
+ // validate paint data
+ mbPaintInfoValid = true;
+
+ // return start page
+ _onStartPageNum = mnPaintPhyStartPageNum;
+
+ return true;
+}
+
+/** calculate additional paint offset
+
+*/
+void SwPagePreviewLayout::CalcAdditionalPaintOffset()
+{
+ if ( mnPreviewLayoutWidth <= maWinSize.Width() &&
+ maPaintStartPageOffset.X() <= 0 )
+ {
+ mbDoesLayoutColsFitIntoWindow = true;
+ maAdditionalPaintOffset.setX( (maWinSize.Width() - mnPreviewLayoutWidth) / 2 );
+ }
+ else
+ {
+ mbDoesLayoutColsFitIntoWindow = false;
+ maAdditionalPaintOffset.setX( 0 );
+ }
+
+ if ( mnPreviewLayoutHeight <= maWinSize.Height() &&
+ maPaintStartPageOffset.Y() <= 0 )
+ {
+ mbDoesLayoutRowsFitIntoWindow = true;
+ maAdditionalPaintOffset.setY( (maWinSize.Height() - mnPreviewLayoutHeight) / 2 );
+ }
+ else
+ {
+ mbDoesLayoutRowsFitIntoWindow = false;
+ maAdditionalPaintOffset.setY( 0 );
+ }
+}
+
+/** calculate painted preview document rectangle
+
+*/
+void SwPagePreviewLayout::CalcDocPreviewPaintRect()
+{
+ Point aTopLeftPos = maPaintPreviewDocOffset;
+ maPaintedPreviewDocRect.SetPos( aTopLeftPos );
+
+ Size aSize;
+ if ( mbDoesLayoutColsFitIntoWindow )
+ aSize.setWidth( std::min( tools::Long(mnPreviewLayoutWidth),
+ maPreviewDocRect.GetWidth() - aTopLeftPos.X() ) );
+ else
+ aSize.setWidth( std::min( maPreviewDocRect.GetWidth() - aTopLeftPos.X(),
+ maWinSize.Width() - maAdditionalPaintOffset.X() ) );
+ if ( mbDoesLayoutRowsFitIntoWindow )
+ aSize.setHeight( std::min( tools::Long(mnPreviewLayoutHeight),
+ maPreviewDocRect.GetHeight() - aTopLeftPos.Y() ) );
+ else
+ aSize.setHeight( std::min( maPreviewDocRect.GetHeight() - aTopLeftPos.Y(),
+ maWinSize.Height() - maAdditionalPaintOffset.Y() ) );
+ maPaintedPreviewDocRect.SetSize( aSize );
+}
+
+/** calculate preview pages
+
+*/
+void SwPagePreviewLayout::CalcPreviewPages()
+{
+ vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut();
+ ClearPreviewPageData();
+
+ if ( mbNoPageVisible )
+ return;
+
+ // determine start page frame
+ const SwPageFrame* pStartPage = mrLayoutRootFrame.GetPageByPageNum( mnPaintPhyStartPageNum );
+
+ // calculate initial paint offset
+ Point aInitialPaintOffset;
+ /// check whether RTL interface or not
+ if(!AllSettings::GetLayoutRTL()){
+ if ( maPaintStartPageOffset != Point( -1, -1 ) )
+ aInitialPaintOffset = Point(0,0) - maPaintStartPageOffset;
+ else
+ aInitialPaintOffset = Point( gnXFree, gnYFree );
+ }
+ else {
+ if ( maPaintStartPageOffset != Point( -1, -1 ) )
+ aInitialPaintOffset = Point(0 + ((SwPagePreviewLayout::mnCols-1)*mnColWidth),0) - maPaintStartPageOffset;
+ else
+ aInitialPaintOffset = Point( gnXFree + ((SwPagePreviewLayout::mnCols-1)*mnColWidth), gnYFree );
+ }
+ aInitialPaintOffset += maAdditionalPaintOffset;
+
+ // prepare loop data
+ const SwPageFrame* pPage = pStartPage;
+ sal_uInt16 nCurrCol = mnPaintStartCol;
+ sal_uInt16 nConsideredRows = 0;
+ Point aCurrPaintOffset = aInitialPaintOffset;
+ // loop on pages to determine preview background rectangles
+ while ( pPage &&
+ (!mbDoesLayoutRowsFitIntoWindow || nConsideredRows < mnRows) &&
+ aCurrPaintOffset.Y() < maWinSize.Height()
+ )
+ {
+ if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() )
+ {
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ continue;
+ }
+
+ pPage->Calc(pRenderContext);
+
+ // consider only pages, which have to be painted.
+ if ( nCurrCol < mnPaintStartCol )
+ {
+ // calculate data of unvisible page needed for accessibility
+ std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
+ Point aCurrAccOffset = aCurrPaintOffset -
+ Point( (mnPaintStartCol-nCurrCol) * mnColWidth, 0 );
+ CalcPreviewDataForPage( *pPage, aCurrAccOffset, pPreviewPage.get() );
+ pPreviewPage->bVisible = false;
+ maPreviewPages.push_back( std::move(pPreviewPage) );
+ // continue with next page and next column
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ ++nCurrCol;
+ continue;
+ }
+ if ( aCurrPaintOffset.X() < maWinSize.Width() )
+ {
+ // leaving left-top-corner blank is
+ // controlled by <mbBookPreview>.
+ if ( mbBookPreview && pPage->GetPhyPageNum() == 1 && mnCols != 1 && nCurrCol == 1
+ )
+ {
+ // first page in 2nd column
+ // --> continue with increased paint offset and next column
+ /// check whether RTL interface or not
+ if(!AllSettings::GetLayoutRTL())
+ aCurrPaintOffset.AdjustX(mnColWidth );
+ else aCurrPaintOffset.AdjustX( -mnColWidth );
+ ++nCurrCol;
+ continue;
+ }
+
+ // calculate data of visible page
+ std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
+ CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() );
+ pPreviewPage->bVisible = true;
+ maPreviewPages.push_back( std::move(pPreviewPage) );
+ }
+ else
+ {
+ // calculate data of unvisible page needed for accessibility
+ std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
+ CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() );
+ pPreviewPage->bVisible = false;
+ maPreviewPages.push_back( std::move(pPreviewPage) );
+ }
+
+ // prepare data for next loop
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+
+ /// check whether RTL interface or not
+ if(!AllSettings::GetLayoutRTL())
+ aCurrPaintOffset.AdjustX(mnColWidth );
+ else aCurrPaintOffset.AdjustX( -mnColWidth );
+ ++nCurrCol;
+ if ( nCurrCol > mnCols )
+ {
+ ++nConsideredRows;
+ aCurrPaintOffset.setX( aInitialPaintOffset.X() );
+ nCurrCol = 1;
+ aCurrPaintOffset.AdjustY(mnRowHeight );
+ }
+ }
+}
+
+/** determines preview data for a given page and a given preview offset
+
+ OD 13.12.2002 #103492#
+*/
+void SwPagePreviewLayout::CalcPreviewDataForPage( const SwPageFrame& _rPage,
+ const Point& _rPreviewOffset,
+ PreviewPage* _opPreviewPage )
+{
+ // page frame
+ _opPreviewPage->pPage = &_rPage;
+ // size of page frame
+ if ( _rPage.IsEmptyPage() )
+ {
+ if ( _rPage.GetPhyPageNum() % 2 == 0 )
+ _opPreviewPage->aPageSize = _rPage.GetPrev()->getFrameArea().SSize();
+ else
+ _opPreviewPage->aPageSize = _rPage.GetNext()->getFrameArea().SSize();
+ }
+ else
+ _opPreviewPage->aPageSize = _rPage.getFrameArea().SSize();
+ // position of page in preview window
+ Point aPreviewWinOffset( _rPreviewOffset );
+ if ( _opPreviewPage->aPageSize.Width() < maMaxPageSize.Width() )
+ aPreviewWinOffset.AdjustX(( maMaxPageSize.Width() - _opPreviewPage->aPageSize.Width() ) / 2 );
+ if ( _opPreviewPage->aPageSize.Height() < maMaxPageSize.Height() )
+ aPreviewWinOffset.AdjustY(( maMaxPageSize.Height() - _opPreviewPage->aPageSize.Height() ) / 2 );
+ _opPreviewPage->aPreviewWinPos = aPreviewWinOffset;
+ // logic position of page and mapping offset for paint
+ if ( _rPage.IsEmptyPage() )
+ {
+ _opPreviewPage->aLogicPos = _opPreviewPage->aPreviewWinPos;
+ _opPreviewPage->aMapOffset = Point( 0, 0 );
+ }
+ else
+ {
+ _opPreviewPage->aLogicPos = _rPage.getFrameArea().Pos();
+ _opPreviewPage->aMapOffset = _opPreviewPage->aPreviewWinPos - _opPreviewPage->aLogicPos;
+ }
+}
+
+/** enable/disable book preview
+
+ OD 2004-03-04 #i18143#
+*/
+bool SwPagePreviewLayout::SetBookPreviewMode( const bool _bEnableBookPreview,
+ sal_uInt16& _onStartPageNum,
+ tools::Rectangle& _orDocPreviewPaintRect )
+{
+ if ( mbBookPreview != _bEnableBookPreview)
+ {
+ mbBookPreview = _bEnableBookPreview;
+ // re-initialize page preview layout
+ ReInit();
+ // re-prepare page preview layout
+ {
+ mbBookPreviewModeToggled = true;
+ Point aProposedStartPos( maPaintPreviewDocOffset );
+ // if proposed start position is below virtual preview document
+ // bottom, adjust it to the virtual preview document bottom
+ if ( aProposedStartPos.Y() > maPreviewDocRect.Bottom() )
+ {
+ aProposedStartPos.setY( maPreviewDocRect.Bottom() );
+ }
+ Prepare( 0, aProposedStartPos,
+ mrParentViewShell.GetOut()->LogicToPixel( maWinSize ),
+ _onStartPageNum, _orDocPreviewPaintRect );
+ mbBookPreviewModeToggled = false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+// methods to determine new data for changing the current shown part of the
+// document preview.
+
+/** calculate start position for new scale
+
+*/
+Point SwPagePreviewLayout::GetPreviewStartPosForNewScale(
+ const Fraction& _aNewScale,
+ const Fraction& _aOldScale,
+ const Size& _aNewWinSize ) const
+{
+ Point aNewPaintStartPos = maPaintedPreviewDocRect.TopLeft();
+ if ( _aNewScale < _aOldScale )
+ {
+ // increase paint width by moving start point to left.
+ if ( mnPreviewLayoutWidth < _aNewWinSize.Width() )
+ aNewPaintStartPos.setX( 0 );
+ else if ( maPaintedPreviewDocRect.GetWidth() < _aNewWinSize.Width() )
+ {
+ aNewPaintStartPos.AdjustX( -(
+ (_aNewWinSize.Width() - maPaintedPreviewDocRect.GetWidth()) / 2) );
+ if ( aNewPaintStartPos.X() < 0)
+ aNewPaintStartPos.setX( 0 );
+ }
+
+ if ( !mbDoesLayoutRowsFitIntoWindow )
+ {
+ // increase paint height by moving start point to top.
+ if ( mnPreviewLayoutHeight < _aNewWinSize.Height() )
+ {
+ aNewPaintStartPos.setY(
+ (mnPaintStartRow - 1) * mnRowHeight );
+ }
+ else if ( maPaintedPreviewDocRect.GetHeight() < _aNewWinSize.Height() )
+ {
+ aNewPaintStartPos.AdjustY( -(
+ (_aNewWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) / 2) );
+ if ( aNewPaintStartPos.Y() < 0)
+ aNewPaintStartPos.setY( 0 );
+ }
+ }
+ }
+ else
+ {
+ // decrease paint width by moving start point to right
+ if ( maPaintedPreviewDocRect.GetWidth() > _aNewWinSize.Width() )
+ aNewPaintStartPos.AdjustX(
+ (maPaintedPreviewDocRect.GetWidth() - _aNewWinSize.Width()) / 2 );
+ // decrease paint height by moving start point to bottom
+ if ( maPaintedPreviewDocRect.GetHeight() > _aNewWinSize.Height() )
+ {
+ aNewPaintStartPos.AdjustY(
+ (maPaintedPreviewDocRect.GetHeight() - _aNewWinSize.Height()) / 2 );
+ // check, if new y-position is outside document preview
+ if ( aNewPaintStartPos.Y() > maPreviewDocRect.Bottom() )
+ aNewPaintStartPos.setY(
+ std::max( tools::Long(0), maPreviewDocRect.Bottom() - mnPreviewLayoutHeight ) );
+ }
+ }
+
+ return aNewPaintStartPos;
+}
+
+/** determines, if page with given page number is visible in preview
+
+ @note _nPageNum is absolute
+*/
+bool SwPagePreviewLayout::IsPageVisible( const sal_uInt16 _nPageNum ) const
+{
+ const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
+ return pPreviewPage && pPreviewPage->bVisible;
+}
+
+/** calculate data to bring new selected page into view.
+
+ @note IN/OUT parameters are absolute page numbers!!!
+*/
+void SwPagePreviewLayout::CalcStartValuesForSelectedPageMove(
+ const sal_Int16 _nHoriMove,
+ const sal_Int16 _nVertMove,
+ sal_uInt16& _orNewSelectedPage,
+ sal_uInt16& _orNewStartPage,
+ Point& _orNewStartPos ) const
+{
+ // determine position of current selected page
+ sal_uInt16 nTmpRelSelPageNum = ConvertAbsoluteToRelativePageNum( mnSelectedPageNum );
+ sal_uInt16 nNewRelSelectedPageNum = nTmpRelSelPageNum;
+
+ const sal_uInt16 nCurrRow = GetRowOfPage(nTmpRelSelPageNum);
+
+ // determine new selected page number
+ {
+ if ( _nHoriMove != 0 )
+ {
+ if ( (nNewRelSelectedPageNum + _nHoriMove) < 1 )
+ nNewRelSelectedPageNum = 1;
+ else if ( (nNewRelSelectedPageNum + _nHoriMove) > mnPages )
+ nNewRelSelectedPageNum = mnPages;
+ else
+ nNewRelSelectedPageNum = nNewRelSelectedPageNum + _nHoriMove;
+ }
+ if ( _nVertMove != 0 )
+ {
+ if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) < 1 )
+ nNewRelSelectedPageNum = 1;
+ else if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) > mnPages )
+ nNewRelSelectedPageNum = mnPages;
+ else
+ nNewRelSelectedPageNum += ( _nVertMove * mnCols );
+ }
+ }
+
+ sal_uInt16 nNewStartPage = mnPaintPhyStartPageNum;
+ Point aNewStartPos(0,0);
+
+ const sal_uInt16 nNewAbsSelectedPageNum = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum );
+ if ( !IsPageVisible( nNewAbsSelectedPageNum ) )
+ {
+ if ( _nHoriMove != 0 && _nVertMove != 0 )
+ {
+ OSL_FAIL( "missing implementation for moving preview selected page horizontal AND vertical");
+ return;
+ }
+
+ // new selected page has to be brought into view considering current
+ // visible preview.
+ const sal_uInt16 nTotalRows = GetRowOfPage( mnPages );
+ if ( (_nHoriMove > 0 || _nVertMove > 0) &&
+ mbDoesLayoutRowsFitIntoWindow &&
+ mbDoesLayoutColsFitIntoWindow &&
+ nCurrRow > nTotalRows - mnRows )
+ {
+ // new proposed start page = left-top-corner of last possible
+ // preview page.
+ nNewStartPage = (nTotalRows - mnRows) * mnCols + 1;
+ // leaving left-top-corner blank is controlled
+ // by <mbBookPreview>.
+ if ( mbBookPreview )
+ {
+ // Note: decrease new proposed start page number by one,
+ // because of blank left-top-corner
+ --nNewStartPage;
+ }
+ nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewStartPage );
+ }
+ else
+ {
+ // new proposed start page = new selected page.
+ nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum );
+ }
+ }
+
+ _orNewSelectedPage = nNewAbsSelectedPageNum;
+ _orNewStartPage = nNewStartPage;
+ _orNewStartPos = aNewStartPos;
+}
+
+namespace {
+
+/** checks, if given position is inside a shown document page */
+struct PreviewPosInsidePagePred
+{
+ const Point mnPreviewPos;
+ explicit PreviewPosInsidePagePred(const Point& rPreviewPos)
+ : mnPreviewPos( rPreviewPos )
+ {}
+ bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage )
+ {
+ if ( _pPreviewPage->bVisible )
+ {
+ tools::Rectangle aPreviewPageRect( _pPreviewPage->aPreviewWinPos, _pPreviewPage->aPageSize );
+ return aPreviewPageRect.Contains( mnPreviewPos );
+ }
+ return false;
+ }
+};
+
+}
+
+bool SwPagePreviewLayout::IsPreviewPosInDocPreviewPage( const Point& rPreviewPos,
+ Point& _orDocPos,
+ bool& _obPosInEmptyPage,
+ sal_uInt16& _onPageNum ) const
+{
+ // initialize variable parameter values.
+ _orDocPos.setX( 0 );
+ _orDocPos.setY( 0 );
+ _obPosInEmptyPage = false;
+ _onPageNum = 0;
+
+ auto aFoundPreviewPageIter =
+ std::find_if( maPreviewPages.begin(), maPreviewPages.end(),
+ PreviewPosInsidePagePred( rPreviewPos ) );
+
+ if ( aFoundPreviewPageIter != maPreviewPages.end() )
+ {
+ // given preview position is inside a document page.
+ _onPageNum = (*aFoundPreviewPageIter)->pPage->GetPhyPageNum();
+ _obPosInEmptyPage = (*aFoundPreviewPageIter)->pPage->IsEmptyPage();
+ if ( !_obPosInEmptyPage )
+ {
+ // given preview position inside a normal page
+ _orDocPos = rPreviewPos -
+ (*aFoundPreviewPageIter)->aPreviewWinPos +
+ (*aFoundPreviewPageIter)->aLogicPos;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** determine window page scroll amount */
+SwTwips SwPagePreviewLayout::GetWinPagesScrollAmount(
+ const sal_Int16 _nWinPagesToScroll ) const
+{
+ SwTwips nScrollAmount;
+ if ( mbDoesLayoutRowsFitIntoWindow )
+ {
+ nScrollAmount = (mnPreviewLayoutHeight - gnYFree) * _nWinPagesToScroll;
+ }
+ else
+ nScrollAmount = _nWinPagesToScroll * maPaintedPreviewDocRect.GetHeight();
+
+ // check, if preview layout size values are valid.
+ // If not, the checks for an adjustment of the scroll amount aren't useful.
+ if ( mbLayoutSizesValid )
+ {
+ if ( (maPaintedPreviewDocRect.Top() + nScrollAmount) <= 0 )
+ nScrollAmount = -maPaintedPreviewDocRect.Top();
+
+ // correct scroll amount
+ if ( nScrollAmount > 0 &&
+ maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom()
+ )
+ {
+ nScrollAmount = 0;
+ }
+ else
+ {
+ while ( (maPaintedPreviewDocRect.Top() + nScrollAmount + gnYFree) >= maPreviewDocRect.GetHeight() )
+ {
+ nScrollAmount -= mnRowHeight;
+ }
+ }
+ }
+
+ return nScrollAmount;
+}
+
+// methods to paint page preview layout
+
+namespace
+{
+/// Similar to RenderContextGuard, but does not touch the draw view.
+class PreviewRenderContextGuard
+{
+ VclPtr<vcl::RenderContext> m_pOriginalValue;
+ SwViewShell& m_rShell;
+
+public:
+ PreviewRenderContextGuard(SwViewShell& rShell, vcl::RenderContext* pValue)
+ : m_pOriginalValue(rShell.GetOut()),
+ m_rShell(rShell)
+ {
+ m_rShell.SetOut(pValue);
+ }
+
+ ~PreviewRenderContextGuard()
+ {
+ m_rShell.SetOut(m_pOriginalValue);
+ }
+};
+}
+
+/** paint prepared preview
+
+*/
+bool SwPagePreviewLayout::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rOutRect) const
+{
+ PreviewRenderContextGuard aGuard(mrParentViewShell, &rRenderContext);
+ // check environment and parameters
+ {
+ if (!mrParentViewShell.GetWin() && !mrParentViewShell.GetOut()->GetConnectMetaFile())
+ {
+ return false;
+ }
+
+ OSL_ENSURE(mbPaintInfoValid, "invalid preview settings - no paint of preview");
+ if (!mbPaintInfoValid)
+ return false;
+ }
+
+ // OD 17.11.2003 #i22014# - no paint, if <superfluous> flag is set at layout
+ if (mrLayoutRootFrame.IsSuperfluous())
+ {
+ return true;
+ }
+
+ // environment and parameter ok
+
+ if (mbInPaint)
+ {
+ return false;
+ }
+ mbInPaint = true;
+
+ OutputDevice* pOutputDev = &rRenderContext;
+
+ // prepare paint
+ if ( !maPreviewPages.empty() )
+ {
+ mrParentViewShell.Imp()->m_bFirstPageInvalid = false;
+ mrParentViewShell.Imp()->m_pFirstVisiblePage =
+ const_cast<SwPageFrame*>(maPreviewPages[0]->pPage);
+ }
+
+ // paint preview background
+ {
+ SwRegionRects aPreviewBackgrdRegion((SwRect(rOutRect)));
+ // calculate preview background rectangles
+ for ( auto & rpPreviewPage : maPreviewPages )
+ {
+ if ( rpPreviewPage->bVisible )
+ {
+ aPreviewBackgrdRegion -=
+ SwRect( rpPreviewPage->aPreviewWinPos, rpPreviewPage->aPageSize );
+ }
+ }
+ // paint preview background rectangles
+ mrParentViewShell.PaintDesktop_(aPreviewBackgrdRegion);
+ }
+
+ // prepare data for paint of pages
+ const tools::Rectangle aPxOutRect( pOutputDev->LogicToPixel(rOutRect) );
+
+ MapMode aMapMode( pOutputDev->GetMapMode() );
+ MapMode aSavedMapMode = aMapMode;
+
+ const vcl::Font& rEmptyPgFont = SwPageFrame::GetEmptyPageFont();
+
+ for ( auto & rpPreviewPage : maPreviewPages )
+ {
+ if ( !rpPreviewPage->bVisible )
+ continue;
+
+ tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize );
+ aMapMode.SetOrigin( rpPreviewPage->aMapOffset );
+ pOutputDev->SetMapMode( aMapMode );
+ tools::Rectangle aPxPaintRect = pOutputDev->LogicToPixel( aPageRect );
+ if ( aPxOutRect.Overlaps( aPxPaintRect) )
+ {
+ const SwPageFrame* pPage = rpPreviewPage->pPage;
+
+ if (pPage->IsEmptyPage())
+ {
+ const Color aRetouche( mrParentViewShell.Imp()->GetRetoucheColor() );
+ if( pOutputDev->GetFillColor() != aRetouche )
+ pOutputDev->SetFillColor( aRetouche );
+ pOutputDev->SetLineColor(); // no line color
+ // use aligned page rectangle
+ {
+ SwRect aTmpPageRect( aPageRect );
+ ::SwAlignRect( aTmpPageRect, &mrParentViewShell, &rRenderContext );
+ aPageRect = aTmpPageRect.SVRect();
+ }
+ pOutputDev->DrawRect( aPageRect );
+
+ // paint empty page text
+ vcl::Font aOldFont( pOutputDev->GetFont() );
+ pOutputDev->SetFont( rEmptyPgFont );
+ pOutputDev->DrawText( aPageRect, SwResId( STR_EMPTYPAGE ),
+ DrawTextFlags::VCenter |
+ DrawTextFlags::Center |
+ DrawTextFlags::Clip );
+ pOutputDev->SetFont( aOldFont );
+ // paint shadow and border for empty page
+ // use new method to paint page border and shadow
+ SwPageFrame::PaintBorderAndShadow( SwRect(aPageRect), &mrParentViewShell, true, false, true );
+ }
+ else
+ {
+ const bool bIsLeftShadowed = pPage->IsLeftShadowNeeded();
+ const bool bIsRightShadowed = pPage->IsRightShadowNeeded();
+
+ mrParentViewShell.maVisArea = SwRect(aPageRect);
+ aPxPaintRect.Intersection( aPxOutRect );
+ tools::Rectangle aPaintRect = pOutputDev->PixelToLogic( aPxPaintRect );
+ mrParentViewShell.Paint(rRenderContext, aPaintRect);
+
+ // --> OD 2007-08-15 #i80691#
+ // paint page border and shadow
+ {
+ SwRect aPageBorderRect;
+ SwPageFrame::GetBorderAndShadowBoundRect( SwRect( aPageRect ), &mrParentViewShell, &rRenderContext, aPageBorderRect,
+ bIsLeftShadowed, bIsRightShadowed, true );
+ const vcl::Region aDLRegion(aPageBorderRect.SVRect());
+ mrParentViewShell.DLPrePaint2(aDLRegion);
+ SwPageFrame::PaintBorderAndShadow( SwRect(aPageRect), &mrParentViewShell, true, false, true );
+ mrParentViewShell.DLPostPaint2(true);
+ }
+ // <--
+ }
+ // OD 07.11.2003 #i22014# - stop painting, because new print
+ // preview layout is created during paint.
+ if ( mbNewLayoutDuringPaint )
+ {
+ break;
+ }
+
+ if (pPage->GetPhyPageNum() == mnSelectedPageNum)
+ {
+ PaintSelectMarkAtPage(rRenderContext, rpPreviewPage.get());
+ }
+ }
+ }
+
+ // OD 17.11.2003 #i22014# - no update of accessible preview, if a new
+ // print preview layout is created during paint.
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if ( !mbNewLayoutDuringPaint )
+ {
+ // update at accessibility interface
+ mrParentViewShell.Imp()->UpdateAccessiblePreview(
+ maPreviewPages,
+ aMapMode.GetScaleX(),
+ mrLayoutRootFrame.GetPageByPageNum( mnSelectedPageNum ),
+ maWinSize );
+ }
+#endif
+
+ pOutputDev->SetMapMode( aSavedMapMode );
+ mrParentViewShell.maVisArea.Clear();
+
+ // OD 07.11.2003 #i22014#
+ mbInPaint = false;
+ mbNewLayoutDuringPaint = false;
+
+ return true;
+}
+
+/** repaint pages on page preview
+
+ OD 18.12.2002 #103492#
+*/
+void SwPagePreviewLayout::Repaint( const tools::Rectangle& rInvalidCoreRect ) const
+{
+ // check environment and parameters
+ {
+ if ( !mrParentViewShell.GetWin() &&
+ !mrParentViewShell.GetOut()->GetConnectMetaFile() )
+ return;
+
+ OSL_ENSURE( mbPaintInfoValid,
+ "invalid preview settings - no paint of preview" );
+ if ( !mbPaintInfoValid )
+ return;
+ }
+
+ // environment and parameter ok
+
+ // prepare paint
+ if ( !maPreviewPages.empty() )
+ {
+ mrParentViewShell.Imp()->m_bFirstPageInvalid = false;
+ mrParentViewShell.Imp()->m_pFirstVisiblePage =
+ const_cast<SwPageFrame*>(maPreviewPages[0]->pPage);
+ }
+
+ // invalidate visible pages, which overlap the invalid core rectangle
+ for ( auto & rpPreviewPage : maPreviewPages )
+ {
+ if ( !rpPreviewPage->bVisible )
+ continue;
+
+ tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize );
+ if ( rInvalidCoreRect.Overlaps( aPageRect ) )
+ {
+ aPageRect.Intersection(rInvalidCoreRect);
+ tools::Rectangle aInvalidPreviewRect = aPageRect;
+ aInvalidPreviewRect.SetPos( aInvalidPreviewRect.TopLeft() -
+ rpPreviewPage->aLogicPos +
+ rpPreviewPage->aPreviewWinPos );
+ mrParentViewShell.GetWin()->Invalidate( aInvalidPreviewRect );
+ }
+ }
+}
+
+/** paint selection mark at page
+
+ OD 17.12.2002 #103492#
+*/
+void SwPagePreviewLayout::PaintSelectMarkAtPage(vcl::RenderContext& rRenderContext,
+ const PreviewPage* _aSelectedPreviewPage ) const
+{
+ OutputDevice* pOutputDev = &rRenderContext;
+ MapMode aMapMode( pOutputDev->GetMapMode() );
+ // save mapping mode of output device
+ MapMode aSavedMapMode = aMapMode;
+ // save fill and line color of output device
+ Color aFill( pOutputDev->GetFillColor() );
+ Color aLine( pOutputDev->GetLineColor() );
+
+ // determine selection mark color
+ Color aSelPgLineColor(117, 114, 106);
+ const StyleSettings& rSettings =
+ mrParentViewShell.GetWin()->GetSettings().GetStyleSettings();
+ if ( rSettings.GetHighContrastMode() )
+ aSelPgLineColor = rSettings.GetHighlightTextColor();
+
+ // set needed mapping mode at output device
+ aMapMode.SetOrigin( _aSelectedPreviewPage->aMapOffset );
+ pOutputDev->SetMapMode( aMapMode );
+
+ // calculate page rectangle in pixel coordinates
+ SwRect aPageRect( _aSelectedPreviewPage->aLogicPos,
+ _aSelectedPreviewPage->aPageSize );
+ // OD 19.02.2003 #107369# - use aligned page rectangle, as it is used for
+ // page border and shadow paint - see <SwPageFrame::PaintBorderAndShadow(..)>
+ ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev );
+ tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
+
+ // draw two rectangle
+ // OD 19.02.2003 #107369# - adjust position of select mark rectangle
+ tools::Rectangle aRect( aPxPageRect.Left(), aPxPageRect.Top(),
+ aPxPageRect.Right(), aPxPageRect.Bottom() );
+ aRect = pOutputDev->PixelToLogic( aRect );
+ pOutputDev->SetFillColor(); // OD 20.02.2003 #107369# - no fill color
+ pOutputDev->SetLineColor( aSelPgLineColor );
+ pOutputDev->DrawRect( aRect );
+ // OD 19.02.2003 #107369# - adjust position of select mark rectangle
+ aRect = tools::Rectangle( aPxPageRect.Left()+1, aPxPageRect.Top()+1,
+ aPxPageRect.Right()-1, aPxPageRect.Bottom()-1 );
+ aRect = pOutputDev->PixelToLogic( aRect );
+ pOutputDev->DrawRect( aRect );
+
+ // reset fill and line color of output device
+ pOutputDev->SetFillColor( aFill );
+ pOutputDev->SetLineColor( aLine );
+
+ // reset mapping mode of output device
+ pOutputDev->SetMapMode( aSavedMapMode );
+}
+
+/** paint to mark new selected page
+
+ OD 17.12.2002 #103492#
+ Perform paint for current selected page in order to unmark it.
+ Set new selected page and perform paint to mark this page.
+
+ @note _nSelectedPage, mnSelectedPage are absolute
+*/
+void SwPagePreviewLayout::MarkNewSelectedPage( const sal_uInt16 _nSelectedPage )
+{
+ const sal_uInt16 nOldSelectedPageNum = mnSelectedPageNum;
+ mnSelectedPageNum = _nSelectedPage;
+
+ // re-paint for current selected page in order to unmark it.
+ const PreviewPage* pOldSelectedPreviewPage = GetPreviewPageByPageNum( nOldSelectedPageNum );
+ OutputDevice* pOutputDev = mrParentViewShell.GetOut();
+ if ( pOldSelectedPreviewPage && pOldSelectedPreviewPage->bVisible )
+ {
+ // OD 20.02.2003 #107369# - invalidate only areas of selection mark.
+ SwRect aPageRect( pOldSelectedPreviewPage->aPreviewWinPos,
+ pOldSelectedPreviewPage->aPageSize );
+ ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev );
+ tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
+ // invalidate top mark line
+ tools::Rectangle aInvalPxRect( aPxPageRect.Left(), aPxPageRect.Top(),
+ aPxPageRect.Right(), aPxPageRect.Top()+1 );
+ mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
+ // invalidate right mark line
+ aInvalPxRect = tools::Rectangle( aPxPageRect.Right()-1, aPxPageRect.Top(),
+ aPxPageRect.Right(), aPxPageRect.Bottom() );
+ mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
+ // invalidate bottom mark line
+ aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Bottom()-1,
+ aPxPageRect.Right(), aPxPageRect.Bottom() );
+ mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
+ // invalidate left mark line
+ aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Top(),
+ aPxPageRect.Left()+1, aPxPageRect.Bottom() );
+ mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
+ }
+
+ // re-paint for new selected page in order to mark it.
+ const PreviewPage* pNewSelectedPreviewPage = GetPreviewPageByPageNum( _nSelectedPage );
+ if ( pNewSelectedPreviewPage && pNewSelectedPreviewPage->bVisible )
+ {
+ const PreviewPage* pSelectedPreviewPage = GetPreviewPageByPageNum(mnSelectedPageNum);
+ SwRect aPageRect(pSelectedPreviewPage->aPreviewWinPos, pSelectedPreviewPage->aPageSize);
+ ::SwAlignRect(aPageRect, &mrParentViewShell, pOutputDev);
+ mrParentViewShell.GetWin()->Invalidate(aPageRect.SVRect());
+ }
+}
+
+// helper methods
+
+namespace {
+
+/** get preview page by physical page number
+
+ OD 17.12.2002 #103492#
+*/
+struct EqualsPageNumPred
+{
+ const sal_uInt16 mnPageNum;
+ explicit EqualsPageNumPred(const sal_uInt16 _nPageNum)
+ : mnPageNum( _nPageNum )
+ {}
+ bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage )
+ {
+ return _pPreviewPage->pPage->GetPhyPageNum() == mnPageNum;
+ }
+};
+
+}
+
+const PreviewPage* SwPagePreviewLayout::GetPreviewPageByPageNum( const sal_uInt16 _nPageNum ) const
+{
+ auto aFoundPreviewPageIter =
+ std::find_if( maPreviewPages.begin(), maPreviewPages.end(),
+ EqualsPageNumPred( _nPageNum ) );
+
+ if ( aFoundPreviewPageIter == maPreviewPages.end() )
+ return nullptr;
+
+ return aFoundPreviewPageIter->get();
+}
+
+/** determine row the page with the given number is in
+
+ OD 17.01.2003 #103492#
+
+ @note _nPageNum is relative
+*/
+sal_uInt16 SwPagePreviewLayout::GetRowOfPage( sal_uInt16 _nPageNum ) const
+{
+ // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
+ // by <mbBookPreview>.
+ if ( mbBookPreview )
+ {
+ // Note: increase given physical page number by one, because left-top-corner
+ // in the preview layout is left blank.
+ ++_nPageNum;
+ }
+
+ return _nPageNum / mnCols + ((_nPageNum % mnCols)>0 ? 1 : 0);
+}
+
+/** determine column the page with the given number is in
+
+ OD 17.01.2003 #103492#
+
+ @note _nPageNum is relative
+*/
+sal_uInt16 SwPagePreviewLayout::GetColOfPage( sal_uInt16 _nPageNum ) const
+{
+ // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
+ // by <mbBookPreview>.
+ if ( mbBookPreview )
+ {
+ // Note: increase given physical page number by one, because left-top-corner
+ // in the preview layout is left blank.
+ ++_nPageNum;
+ }
+
+ const sal_uInt16 nCol = _nPageNum % mnCols;
+ return nCol ? nCol : mnCols;
+}
+
+Size SwPagePreviewLayout::GetPreviewDocSize() const
+{
+ OSL_ENSURE( PreviewLayoutValid(), "PagePreviewLayout not valid" );
+ return maPreviewDocRect.GetSize();
+}
+
+/** get size of a preview page by its physical page number
+
+ OD 15.01.2003 #103492#
+*/
+Size SwPagePreviewLayout::GetPreviewPageSizeByPageNum( sal_uInt16 _nPageNum ) const
+{
+ const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
+ if ( pPreviewPage )
+ {
+ return pPreviewPage->aPageSize;
+ }
+ return Size( 0, 0 );
+}
+
+/** get virtual page number by its physical page number
+
+ OD 21.03.2003 #108282#
+*/
+sal_uInt16 SwPagePreviewLayout::GetVirtPageNumByPageNum( sal_uInt16 _nPageNum ) const
+{
+ const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
+ if ( pPreviewPage )
+ {
+ return pPreviewPage->pPage->GetVirtPageNum();
+ }
+ return 0;
+}
+
+/** Convert absolute to relative page numbers (see PrintEmptyPages) */
+sal_uInt16 SwPagePreviewLayout::ConvertAbsoluteToRelativePageNum( sal_uInt16 _nAbsPageNum ) const
+{
+ if ( mbBookPreview || mbPrintEmptyPages || !_nAbsPageNum )
+ {
+ return _nAbsPageNum;
+ }
+
+ const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
+
+ sal_uInt16 nRet = 1;
+
+ while ( pTmpPage && pTmpPage->GetPhyPageNum() != _nAbsPageNum )
+ {
+ if ( !pTmpPage->IsEmptyPage() )
+ ++nRet;
+
+ pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() );
+ }
+
+ return nRet;
+}
+
+/** Convert relative to absolute page numbers (see PrintEmptyPages) */
+sal_uInt16 SwPagePreviewLayout::ConvertRelativeToAbsolutePageNum( sal_uInt16 _nRelPageNum ) const
+{
+ if ( mbBookPreview || mbPrintEmptyPages || !_nRelPageNum )
+ {
+ return _nRelPageNum;
+ }
+
+ const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
+ const SwPageFrame* pRet = nullptr;
+
+ sal_uInt16 i = 0;
+ while( pTmpPage && i != _nRelPageNum )
+ {
+ if ( !pTmpPage->IsEmptyPage() )
+ ++i;
+
+ pRet = pTmpPage;
+ pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() );
+ }
+
+ return pRet->GetPhyPageNum();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/view/printdata.cxx b/sw/source/core/view/printdata.cxx
new file mode 100644
index 0000000000..478e553aaf
--- /dev/null
+++ b/sw/source/core/view/printdata.cxx
@@ -0,0 +1,447 @@
+/* -*- 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 <printdata.hxx>
+
+#include <strings.hrc>
+#include <doc.hxx>
+#include <IDocumentDeviceAccess.hxx>
+#include <unotxdoc.hxx>
+#include <wdocsh.hxx>
+#include <viewsh.hxx>
+#include <docfld.hxx>
+
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <vcl/outdev.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+
+SwRenderData::SwRenderData()
+{
+}
+
+SwRenderData::~SwRenderData()
+{
+ OSL_ENSURE( !m_pPostItShell, "m_pPostItShell should already have been deleted" );
+ OSL_ENSURE( !m_pPostItFields, " should already have been deleted" );
+}
+
+void SwRenderData::CreatePostItData( SwDoc& rDoc, const SwViewOption *pViewOpt, OutputDevice *pOutDev )
+{
+ DeletePostItData();
+ m_pPostItFields.reset(new SetGetExpFields);
+ sw_GetPostIts( rDoc.getIDocumentFieldsAccess(), m_pPostItFields.get() );
+
+ //!! Disable spell and grammar checking in the temporary document.
+ //!! Otherwise the grammar checker might process it and crash if we later on
+ //!! simply delete this document while he is still at it.
+ SwViewOption aViewOpt( *pViewOpt );
+ aViewOpt.SetOnlineSpell( false );
+
+ m_pPostItShell.reset(new SwViewShell(*new SwDoc, nullptr, &aViewOpt, pOutDev));
+}
+
+void SwRenderData::DeletePostItData()
+{
+ if (HasPostItData())
+ {
+ // printer needs to remain at the real document
+ m_pPostItShell->GetDoc()->getIDocumentDeviceAccess().setPrinter( nullptr, false, false );
+ { // avoid destroying layout from SwDoc dtor
+ rtl::Reference<SwDoc> const xKeepAlive(m_pPostItShell->GetDoc());
+ m_pPostItShell.reset();
+ }
+ m_pPostItFields.reset();
+ }
+}
+
+void SwRenderData::SetTempDocShell(SfxObjectShellLock const& xShell)
+{
+ m_xTempDocShell = xShell;
+}
+
+bool SwRenderData::NeedNewViewOptionAdjust( const SwViewShell& rCompare ) const
+{
+ return !(m_pViewOptionAdjust && m_pViewOptionAdjust->checkShell( rCompare ));
+}
+
+void SwRenderData::ViewOptionAdjustStart(
+ SwViewShell &rSh, const SwViewOption &rViewOptions)
+{
+ if (m_pViewOptionAdjust)
+ {
+ OSL_FAIL("error: there should be no ViewOptionAdjust active when calling this function" );
+ }
+ m_pViewOptionAdjust.reset(
+ new SwViewOptionAdjust_Impl( rSh, rViewOptions ));
+}
+
+void SwRenderData::ViewOptionAdjust(SwPrintData const*const pPrtOptions, bool setShowPlaceHoldersInPDF)
+{
+ m_pViewOptionAdjust->AdjustViewOptions( pPrtOptions, setShowPlaceHoldersInPDF );
+}
+
+void SwRenderData::ViewOptionAdjustStop()
+{
+ m_pViewOptionAdjust.reset();
+}
+
+void SwRenderData::ViewOptionAdjustCrashPreventionKludge()
+{
+ m_pViewOptionAdjust->DontTouchThatViewShellItSmellsFunny();
+}
+
+void SwRenderData::MakeSwPrtOptions(
+ SwDocShell const*const pDocShell,
+ SwPrintUIOptions const*const pOpt,
+ bool const bIsPDFExport)
+{
+ if (!pDocShell || !pOpt)
+ return;
+
+ m_pPrtOptions.reset(new SwPrintData);
+ SwPrintData & rOptions(*m_pPrtOptions);
+
+ // get default print options
+ bool bWeb = dynamic_cast<const SwWebDocShell*>( pDocShell) != nullptr;
+ ::sw::InitPrintOptionsFromApplication(rOptions, bWeb);
+
+ // get print options to use from provided properties
+ rOptions.m_bPrintGraphic = pOpt->IsPrintGraphics();
+ rOptions.m_bPrintTable = true; // for now it was decided that tables should always be printed
+ rOptions.m_bPrintDraw = pOpt->IsPrintDrawings();
+ rOptions.m_bPrintControl = pOpt->IsPrintFormControls();
+ rOptions.m_bPrintLeftPages = pOpt->IsPrintLeftPages();
+ rOptions.m_bPrintRightPages = pOpt->IsPrintRightPages();
+ rOptions.m_bPrintPageBackground = pOpt->IsPrintPageBackground();
+ rOptions.m_bPrintEmptyPages = pOpt->IsPrintEmptyPages( bIsPDFExport );
+ // bUpdateFieldsInPrinting <-- not set here; mail merge only
+ rOptions.m_bPaperFromSetup = pOpt->IsPaperFromSetup();
+ rOptions.m_bPrintReverse = false; /*handled by print dialog now*/
+ rOptions.m_bPrintProspect = pOpt->IsPrintProspect();
+ rOptions.m_bPrintProspectRTL = pOpt->IsPrintProspectRTL();
+ // bPrintSingleJobs <-- not set here; mail merge and or configuration
+ // bModified <-- not set here; mail merge only
+ rOptions.m_bPrintBlackFont = pOpt->IsPrintWithBlackTextColor();
+ rOptions.m_bPrintHiddenText = pOpt->IsPrintHiddenText();
+ rOptions.m_bPrintTextPlaceholder = pOpt->IsPrintTextPlaceholders();
+ rOptions.m_nPrintPostIts = pOpt->GetPrintPostItsType();
+
+ //! needs to be set after MakeOptions since the assignment operation in that
+ //! function will destroy the pointers
+ rOptions.SetRenderData( this );
+}
+
+SwPrintUIOptions::SwPrintUIOptions(
+ sal_uInt16 nCurrentPage,
+ bool bWeb,
+ bool bSwSrcView,
+ bool bHasSelection,
+ bool bHasPostIts,
+ const SwPrintData &rDefaultPrintData ) :
+ m_rDefaultPrintData( rDefaultPrintData )
+{
+ // printing HTML sources does not have any valid UI options.
+ // It's just the source code that gets printed...
+ if (bSwSrcView || utl::ConfigManager::IsFuzzing())
+ {
+ m_aUIProperties.clear();
+ return;
+ }
+
+ // check if either CJK or CTL is enabled
+ bool bRTL = SvtCJKOptions::IsCJKFontEnabled() || SvtCTLOptions::IsCTLFontEnabled();
+
+ // create sequence of print UI options
+ // (5 options are not available for Writer-Web)
+ const int nRTLOpts = bRTL ? 1 : 0;
+ const int nNumProps = nRTLOpts + (bWeb ? 15 : 19);
+ m_aUIProperties.resize( nNumProps);
+ int nIdx = 0;
+
+ // load the writer PrinterOptions into the custom tab
+ m_aUIProperties[nIdx].Name = "OptionsUIFile";
+ m_aUIProperties[nIdx++].Value <<= OUString("modules/swriter/ui/printeroptions.ui");
+
+ // create "writer" section (new tab page in dialog)
+ SvtModuleOptions aModOpt;
+ OUString aAppGroupname( SwResId( STR_PRINTOPTUI_PRODUCTNAME) );
+ aAppGroupname = aAppGroupname.replaceFirst( "%s", aModOpt.GetModuleName( SvtModuleOptions::EModule::WRITER ) );
+ m_aUIProperties[ nIdx++ ].Value = setGroupControlOpt("tabcontrol-page2", aAppGroupname, ".HelpID:vcl:PrintDialog:TabPage:AppPage");
+
+ // create sub section for Contents
+ m_aUIProperties[ nIdx++ ].Value = setSubgroupControlOpt("contents", SwResId( STR_PRINTOPTUI_CONTENTS), OUString());
+
+ // create a bool option for background
+ bool bDefaultVal = rDefaultPrintData.IsPrintPageBackground();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("pagebackground", SwResId( STR_PRINTOPTUI_PAGE_BACKGROUND),
+ ".HelpID:vcl:PrintDialog:PrintPageBackground:CheckBox",
+ "PrintPageBackground",
+ bDefaultVal);
+
+ // create a bool option for pictures/graphics AND OLE and drawing objects as well
+ bDefaultVal = rDefaultPrintData.IsPrintGraphic() || rDefaultPrintData.IsPrintDraw();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("pictures", SwResId( STR_PRINTOPTUI_PICTURES),
+ ".HelpID:vcl:PrintDialog:PrintPicturesAndObjects:CheckBox",
+ "PrintPicturesAndObjects",
+ bDefaultVal);
+ if (!bWeb)
+ {
+ // create a bool option for hidden text
+ bDefaultVal = rDefaultPrintData.IsPrintHiddenText();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("hiddentext", SwResId( STR_PRINTOPTUI_HIDDEN),
+ ".HelpID:vcl:PrintDialog:PrintHiddenText:CheckBox",
+ "PrintHiddenText",
+ bDefaultVal);
+
+ // create a bool option for place holder
+ bDefaultVal = rDefaultPrintData.IsPrintTextPlaceholder();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("placeholders", SwResId( STR_PRINTOPTUI_TEXT_PLACEHOLDERS),
+ ".HelpID:vcl:PrintDialog:PrintTextPlaceholder:CheckBox",
+ "PrintTextPlaceholder",
+ bDefaultVal);
+ }
+
+ // create a bool option for controls
+ bDefaultVal = rDefaultPrintData.IsPrintControl();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("formcontrols", SwResId( STR_PRINTOPTUI_FORM_CONTROLS),
+ ".HelpID:vcl:PrintDialog:PrintControls:CheckBox",
+ "PrintControls",
+ bDefaultVal);
+
+ // create sub section for Color
+ m_aUIProperties[ nIdx++ ].Value = setSubgroupControlOpt("color", SwResId( STR_PRINTOPTUI_COLOR), OUString());
+
+ // create a bool option for printing text with black font color
+ bDefaultVal = rDefaultPrintData.IsPrintBlackFont();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("textinblack", SwResId( STR_PRINTOPTUI_PRINT_BLACK),
+ ".HelpID:vcl:PrintDialog:PrintBlackFonts:CheckBox",
+ "PrintBlackFonts",
+ bDefaultVal);
+
+ if (!bWeb)
+ {
+ // create subgroup for misc options
+ m_aUIProperties[ nIdx++ ].Value = setSubgroupControlOpt("pages", SwResId( STR_PRINTOPTUI_PAGES_TEXT), OUString());
+
+ // create a bool option for printing automatically inserted blank pages
+ bDefaultVal = rDefaultPrintData.IsPrintEmptyPages();
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("autoblankpages", SwResId( STR_PRINTOPTUI_PRINT_BLANK),
+ ".HelpID:vcl:PrintDialog:PrintEmptyPages:CheckBox",
+ "PrintEmptyPages",
+ bDefaultVal);
+ }
+
+ // create a bool option for paper tray
+ bDefaultVal = rDefaultPrintData.IsPaperFromSetup();
+ vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt;
+ aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup";
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("printpaperfromsetup", SwResId( STR_PRINTOPTUI_ONLY_PAPER),
+ ".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox",
+ "PrintPaperFromSetup",
+ bDefaultVal,
+ aPaperTrayOpt);
+
+ // print range selection
+ vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
+ aPrintRangeOpt.maGroupHint = "PrintRange";
+ aPrintRangeOpt.mbInternalOnly = true;
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt( "printrange",
+ SwResId( STR_PRINTOPTUI_PAGES_TEXT ),
+ OUString(),
+ aPrintRangeOpt );
+
+ // create a choice for the content to create
+ static constexpr OUString aPrintRangeName( u"PrintContent"_ustr );
+ uno::Sequence< OUString > aChoices{ SwResId( STR_PRINTOPTUI_PRINTALLPAGES ),
+ SwResId( STR_PRINTOPTUI_PRINTPAGES ),
+ SwResId( STR_PRINTOPTUI_PRINTSELECTION ) };
+ uno::Sequence< sal_Bool > aChoicesDisabled{ false, false, !bHasSelection };
+ uno::Sequence< OUString > aHelpIds{ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2" };
+ uno::Sequence< OUString > aWidgetIds{ "rbAllPages", "rbRangePages", "rbRangeSelection" };
+ m_aUIProperties[nIdx++].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(),
+ aHelpIds, aPrintRangeName,
+ aChoices, 0 /* always default to 'All pages' */,
+ aChoicesDisabled);
+
+ // show an Edit dependent on "Pages" selected
+ vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
+ m_aUIProperties[nIdx++].Value = setEditControlOpt("pagerange", OUString(),
+ ".HelpID:vcl:PrintDialog:PageRange:Edit",
+ "PageRange",
+ OUString::number( nCurrentPage ) /* set text box to current page number */,
+ aPageRangeOpt);
+
+ vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true);
+ m_aUIProperties[ nIdx++ ].Value = setChoiceListControlOpt("evenoddbox",
+ OUString(),
+ uno::Sequence<OUString>(),
+ "EvenOdd",
+ uno::Sequence<OUString>(),
+ 0,
+ uno::Sequence< sal_Bool >(),
+ aEvenOddOpt);
+
+ // create a list box for notes content
+ const SwPostItMode nPrintPostIts = rDefaultPrintData.GetPrintPostIts();
+ aChoices = { SwResId( STR_PRINTOPTUI_NONE),
+ SwResId( STR_PRINTOPTUI_COMMENTS_ONLY),
+ SwResId( STR_PRINTOPTUI_PLACE_END),
+ SwResId( STR_PRINTOPTUI_PLACE_PAGE),
+ SwResId( STR_PRINTOPTUI_PLACE_MARGINS) };
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintAnnotationMode:FixedText",
+ ".HelpID:vcl:PrintDialog:PrintAnnotationMode:ListBox" };
+ vcl::PrinterOptionsHelper::UIControlOptions aAnnotOpt( "PrintProspect", 0, false );
+ aAnnotOpt.mbEnabled = bHasPostIts;
+ m_aUIProperties[ nIdx++ ].Value = setChoiceListControlOpt("writercomments",
+ SwResId( STR_PRINTOPTUI_COMMENTS),
+ aHelpIds,
+ "PrintAnnotationMode",
+ aChoices,
+ bHasPostIts ? static_cast<sal_uInt16>(nPrintPostIts) : 0,
+ uno::Sequence< sal_Bool >(),
+ aAnnotOpt);
+
+ // create subsection for Page settings
+ vcl::PrinterOptionsHelper::UIControlOptions aPageSetOpt;
+ aPageSetOpt.maGroupHint = "LayoutPage";
+
+ // create a bool option for brochure
+ bDefaultVal = rDefaultPrintData.IsPrintProspect();
+ static constexpr OUString aBrochurePropertyName( u"PrintProspect"_ustr );
+ m_aUIProperties[ nIdx++ ].Value = setBoolControlOpt("brochure", SwResId( STR_PRINTOPTUI_BROCHURE),
+ ".HelpID:vcl:PrintDialog:PrintProspect:CheckBox",
+ aBrochurePropertyName,
+ bDefaultVal,
+ aPageSetOpt);
+
+ if (bRTL)
+ {
+ // create a bool option for brochure RTL dependent on brochure
+ uno::Sequence< OUString > aBRTLChoices{ SwResId( STR_PRINTOPTUI_LEFT_SCRIPT),
+ SwResId( STR_PRINTOPTUI_RIGHT_SCRIPT) };
+ vcl::PrinterOptionsHelper::UIControlOptions aBrochureRTLOpt( aBrochurePropertyName, -1, true );
+ uno::Sequence<OUString> aBRTLHelpIds { ".HelpID:vcl:PrintDialog:PrintProspectRTL:ListBox" };
+ aBrochureRTLOpt.maGroupHint = "LayoutPage";
+ // RTL brochure choices
+ // 0 : left-to-right
+ // 1 : right-to-left
+ const sal_Int16 nBRTLChoice = rDefaultPrintData.IsPrintProspectRTL() ? 1 : 0;
+ m_aUIProperties[ nIdx++ ].Value = setChoiceListControlOpt("scriptdirection",
+ OUString(),
+ aBRTLHelpIds,
+ "PrintProspectRTL",
+ aBRTLChoices,
+ nBRTLChoice,
+ uno::Sequence< sal_Bool >(),
+ aBrochureRTLOpt);
+ }
+
+ assert(nIdx == nNumProps);
+}
+
+SwPrintUIOptions::~SwPrintUIOptions()
+{
+}
+
+bool SwPrintUIOptions::IsPrintLeftPages() const
+{
+ // take care of different property names for the option.
+ // for compatibility the old name should win (may still be used for PDF export or via Uno API)
+
+ // 0: left and right pages
+ // 1: left pages only
+ // 2: right pages only
+ sal_Int64 nEOPages = getIntValue( "EvenOdd", 0 /* default: all */ );
+ bool bRes = nEOPages != 1;
+ bRes = getBoolValue( "EvenOdd", bRes /* <- default value if property is not found */ );
+ return bRes;
+}
+
+bool SwPrintUIOptions::IsPrintRightPages() const
+{
+ // take care of different property names for the option.
+ // for compatibility the old name should win (may still be used for PDF export or via Uno API)
+
+ sal_Int64 nEOPages = getIntValue( "EvenOdd", 0 /* default: all */ );
+ bool bRes = nEOPages != 2;
+ bRes = getBoolValue( "EvenOdd", bRes /* <- default value if property is not found */ );
+ return bRes;
+}
+
+bool SwPrintUIOptions::IsPrintEmptyPages( bool bIsPDFExport ) const
+{
+ // take care of different property names for the option.
+
+ bool bRes = bIsPDFExport ?
+ !getBoolValue( "IsSkipEmptyPages", true ) :
+ getBoolValue( "PrintEmptyPages", true );
+ return bRes;
+}
+
+bool SwPrintUIOptions::IsPrintGraphics() const
+{
+ // take care of different property names for the option.
+ // for compatibility the old name should win (may still be used for PDF export or via Uno API)
+
+ bool bRes = getBoolValue( "PrintPicturesAndObjects", true );
+ bRes = getBoolValue( "PrintGraphics", bRes );
+ return bRes;
+}
+
+bool SwPrintUIOptions::IsPrintDrawings() const
+{
+ // take care of different property names for the option.
+ // for compatibility the old name should win (may still be used for PDF export or via Uno API)
+
+ bool bRes = getBoolValue( "PrintPicturesAndObjects", true );
+ bRes = getBoolValue( "PrintDrawings", bRes );
+ return bRes;
+}
+
+bool SwPrintUIOptions::processPropertiesAndCheckFormat( const uno::Sequence< beans::PropertyValue >& i_rNewProp )
+{
+ bool bChanged = processProperties( i_rNewProp );
+
+ uno::Reference< awt::XDevice > xRenderDevice;
+ uno::Any aVal( getValue( "RenderDevice" ) );
+ aVal >>= xRenderDevice;
+
+ VclPtr< OutputDevice > pOut;
+ if (xRenderDevice.is())
+ {
+ VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>( xRenderDevice.get() );
+ if (pDevice)
+ pOut = pDevice->GetOutputDevice();
+ }
+ bChanged = bChanged || (pOut.get() != m_pLast.get());
+ if( pOut )
+ m_pLast = pOut;
+
+ return bChanged;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/view/vdraw.cxx b/sw/source/core/view/vdraw.cxx
new file mode 100644
index 0000000000..5a95053cd7
--- /dev/null
+++ b/sw/source/core/view/vdraw.cxx
@@ -0,0 +1,280 @@
+/* -*- 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 <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <fmtanchr.hxx>
+#include <frmfmt.hxx>
+
+#include <svx/svdoutl.hxx>
+
+#include <drawdoc.hxx>
+#include <fesh.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <viewimp.hxx>
+#include <dflyobj.hxx>
+#include <printdata.hxx>
+#include <dcontact.hxx>
+#include <dview.hxx>
+#include <flyfrm.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/canvastools.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <basegfx/range/b2irectangle.hxx>
+
+#include <IDocumentDrawModelAccess.hxx>
+
+void SwViewShellImp::StartAction()
+{
+ if ( HasDrawView() )
+ {
+ CurrShell aCurr( GetShell() );
+ if ( auto pFEShell = dynamic_cast<SwFEShell*>( m_pShell) )
+ pFEShell->HideChainMarker(); // might have changed
+ }
+}
+
+void SwViewShellImp::EndAction()
+{
+ if ( HasDrawView() )
+ {
+ CurrShell aCurr( GetShell() );
+ if ( auto pFEShell = dynamic_cast<SwFEShell*>(m_pShell) )
+ pFEShell->SetChainMarker(); // might have changed
+ }
+}
+
+void SwViewShellImp::LockPaint()
+{
+ if ( HasDrawView() )
+ {
+ m_bResetHdlHiddenPaint = !GetDrawView()->areMarkHandlesHidden();
+ GetDrawView()->hideMarkHandles();
+ }
+ else
+ {
+ m_bResetHdlHiddenPaint = false;
+ }
+}
+
+void SwViewShellImp::UnlockPaint()
+{
+ if ( m_bResetHdlHiddenPaint )
+ GetDrawView()->showMarkHandles();
+}
+
+void SwViewShellImp::PaintLayer( const SdrLayerID _nLayerID,
+ SwPrintData const*const pPrintData,
+ SwPageFrame const& rPageFrame,
+ const SwRect& aPaintRect,
+ const Color* _pPageBackgrdColor,
+ const bool _bIsPageRightToLeft,
+ sdr::contact::ViewObjectContactRedirector* pRedirector )
+{
+ if ( !HasDrawView() )
+ return;
+
+ //change the draw mode in high contrast mode
+ OutputDevice* pOutDev = GetShell()->GetOut();
+ DrawModeFlags nOldDrawMode = pOutDev->GetDrawMode();
+ if( GetShell()->GetWin() &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() &&
+ (!GetShell()->IsPreview() || officecfg::Office::Common::Accessibility::IsForPagePreviews::get()))
+ {
+ pOutDev->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill |
+ DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
+ }
+
+ // For correct handling of accessibility, high contrast, the
+ // page background color is set as the background color at the
+ // outliner of the draw view. Only necessary for the layers
+ // hell and heaven
+ Color aOldOutlinerBackgroundColor;
+ // set default horizontal text direction on painting <hell> or
+ // <heaven>.
+ EEHorizontalTextDirection aOldEEHoriTextDir = EEHorizontalTextDirection::L2R;
+ const IDocumentDrawModelAccess& rIDDMA = GetShell()->getIDocumentDrawModelAccess();
+ if ( (_nLayerID == rIDDMA.GetHellId()) ||
+ (_nLayerID == rIDDMA.GetHeavenId()) )
+ {
+ OSL_ENSURE( _pPageBackgrdColor,
+ "incorrect usage of SwViewShellImp::PaintLayer: pPageBackgrdColor have to be set for painting layer <hell> or <heaven>");
+ if ( _pPageBackgrdColor )
+ {
+ aOldOutlinerBackgroundColor =
+ GetDrawView()->GetModel().GetDrawOutliner().GetBackgroundColor();
+ GetDrawView()->GetModel().GetDrawOutliner().SetBackgroundColor( *_pPageBackgrdColor );
+ }
+
+ aOldEEHoriTextDir =
+ GetDrawView()->GetModel().GetDrawOutliner().GetDefaultHorizontalTextDirection();
+ EEHorizontalTextDirection aEEHoriTextDirOfPage =
+ _bIsPageRightToLeft ? EEHorizontalTextDirection::R2L : EEHorizontalTextDirection::L2R;
+ GetDrawView()->GetModel().GetDrawOutliner().SetDefaultHorizontalTextDirection( aEEHoriTextDirOfPage );
+ }
+
+ pOutDev->Push( vcl::PushFlags::LINECOLOR );
+ if (pPrintData)
+ {
+ // hide drawings but not form controls (form controls are handled elsewhere)
+ SdrView &rSdrView = GetPageView()->GetView();
+ rSdrView.setHideDraw( !pPrintData->IsPrintDraw() );
+ }
+ basegfx::B2IRectangle const pageFrame = vcl::unotools::b2IRectangleFromRectangle(rPageFrame.getFrameArea().SVRect());
+ GetPageView()->DrawLayer(_nLayerID, pOutDev, pRedirector, aPaintRect.SVRect(), &pageFrame);
+ pOutDev->Pop();
+
+ // reset background color of the outliner & default horiz. text dir.
+ if ( (_nLayerID == rIDDMA.GetHellId()) ||
+ (_nLayerID == rIDDMA.GetHeavenId()) )
+ {
+ GetDrawView()->GetModel().GetDrawOutliner().SetBackgroundColor( aOldOutlinerBackgroundColor );
+ GetDrawView()->GetModel().GetDrawOutliner().SetDefaultHorizontalTextDirection( aOldEEHoriTextDir );
+ }
+
+ pOutDev->SetDrawMode( nOldDrawMode );
+
+}
+
+#define FUZZY_EDGE 400
+
+bool SwViewShellImp::IsDragPossible( const Point &rPoint )
+{
+ if ( !HasDrawView() )
+ return false;
+
+ const SdrMarkList &rMrkList = GetDrawView()->GetMarkedObjectList();
+
+ if( !rMrkList.GetMarkCount() )
+ return false;
+
+ SdrObject *pO = rMrkList.GetMark(rMrkList.GetMarkCount()-1)->GetMarkedSdrObj();
+
+ SwRect aRect;
+ if( pO && ::CalcClipRect( pO, aRect, false ) )
+ {
+ SwRect aTmp;
+ ::CalcClipRect( pO, aTmp );
+ aRect.Union( aTmp );
+ }
+ else
+ aRect = GetShell()->GetLayout()->getFrameArea();
+
+ aRect.AddTop (- FUZZY_EDGE );
+ aRect.AddBottom( FUZZY_EDGE );
+ aRect.AddLeft (- FUZZY_EDGE );
+ aRect.AddRight ( FUZZY_EDGE );
+ return aRect.Contains( rPoint );
+}
+
+void SwViewShellImp::NotifySizeChg( const Size &rNewSz )
+{
+ if ( !HasDrawView() )
+ return;
+
+ if ( GetPageView() )
+ GetPageView()->GetPage()->SetSize( rNewSz );
+
+ // Limitation of the work area
+ const tools::Rectangle aDocRect( Point( DOCUMENTBORDER, DOCUMENTBORDER ), rNewSz );
+ const tools::Rectangle &rOldWork = GetDrawView()->GetWorkArea();
+ bool bCheckDrawObjs = false;
+ if ( aDocRect != rOldWork )
+ {
+ if ( rOldWork.Bottom() > aDocRect.Bottom() || rOldWork.Right() > aDocRect.Right())
+ bCheckDrawObjs = true;
+ GetDrawView()->SetWorkArea( aDocRect );
+ }
+ if ( !bCheckDrawObjs )
+ return;
+
+ OSL_ENSURE( m_pShell->getIDocumentDrawModelAccess().GetDrawModel(), "NotifySizeChg without DrawModel" );
+ SdrPage* pPage = m_pShell->getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 );
+ for (const rtl::Reference<SdrObject>& pObj : *pPage)
+ {
+ if( dynamic_cast<const SwVirtFlyDrawObj*>( pObj.get()) == nullptr )
+ {
+ // Objects not anchored to the frame, do not need to be adjusted
+ const SwContact *pCont = GetUserCall(pObj.get());
+ // this function might be called by the InsertDocument, when
+ // a PageDesc-Attribute is set on a node. Then the SdrObject
+ // must not have an UserCall.
+ if( !pCont )
+ continue;
+ auto pDrawContact = dynamic_cast<const SwDrawContact*>( pCont);
+ if( !pDrawContact )
+ continue;
+
+ const SwFrame *pAnchor = pDrawContact->GetAnchorFrame();
+ if ( !pAnchor || pAnchor->IsInFly() || !pAnchor->isFrameAreaDefinitionValid() ||
+ !pAnchor->GetUpper() || !pAnchor->FindPageFrame() ||
+ (RndStdIds::FLY_AS_CHAR == pCont->GetFormat()->GetAnchor().GetAnchorId()) )
+ {
+ continue;
+ }
+ else
+ {
+ // Actually this should never happen but currently layouting
+ // is broken. So don't move anchors, if the page is invalid.
+ // This should be turned into a DBG_ASSERT, once layouting is fixed!
+ const SwPageFrame *pPageFrame = pAnchor->FindPageFrame();
+ if (!pPageFrame || pPageFrame->IsInvalid() ) {
+ SAL_WARN( "sw.core", "Trying to move anchor from invalid page - fix layouting!" );
+ continue;
+ }
+ }
+
+ // no move for drawing objects in header/footer
+ if ( pAnchor->FindFooterOrHeader() )
+ {
+ continue;
+ }
+
+ const tools::Rectangle aObjBound( pObj->GetCurrentBoundRect() );
+ if ( !aDocRect.Contains( aObjBound ) )
+ {
+ Size aSz;
+ if ( aObjBound.Left() > aDocRect.Right() )
+ aSz.setWidth( (aDocRect.Right() - aObjBound.Left()) - MINFLY );
+ if ( aObjBound.Top() > aDocRect.Bottom() )
+ aSz.setHeight( (aDocRect.Bottom() - aObjBound.Top()) - MINFLY );
+ if ( aSz.Width() || aSz.Height() )
+ pObj->Move( aSz );
+
+ // Don't let large objects disappear to the top
+ aSz.setWidth(0);
+ aSz.setHeight(0);
+ if ( aObjBound.Right() < aDocRect.Left() )
+ aSz.setWidth( (aDocRect.Left() - aObjBound.Right()) + MINFLY );
+ if ( aObjBound.Bottom() < aDocRect.Top() )
+ aSz.setHeight( (aDocRect.Top() - aObjBound.Bottom()) + MINFLY );
+ if ( aSz.Width() || aSz.Height() )
+ pObj->Move( aSz );
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/view/viewimp.cxx b/sw/source/core/view/viewimp.cxx
new file mode 100644
index 0000000000..3f427ed773
--- /dev/null
+++ b/sw/source/core/view/viewimp.cxx
@@ -0,0 +1,528 @@
+/* -*- 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 <config_wasm_strip.h>
+
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <viewimp.hxx>
+#include <viewopt.hxx>
+#include <flyfrm.hxx>
+#include <layact.hxx>
+#include <dview.hxx>
+#include <svx/svdpage.hxx>
+#include <accmap.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <pagepreviewlayout.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <drawdoc.hxx>
+#include <prevwpage.hxx>
+#include <sfx2/viewsh.hxx>
+
+void SwViewShellImp::Init( const SwViewOption *pNewOpt )
+{
+ OSL_ENSURE( m_pDrawView, "SwViewShellImp::Init without DrawView" );
+ //Create PageView if it doesn't exist
+ SwRootFrame *pRoot = m_pShell->GetLayout();
+ if ( !m_pSdrPageView )
+ {
+ IDocumentDrawModelAccess& rIDDMA = m_pShell->getIDocumentDrawModelAccess();
+ if ( !pRoot->GetDrawPage() )
+ pRoot->SetDrawPage( rIDDMA.GetDrawModel()->GetPage( 0 ) );
+
+ if ( pRoot->GetDrawPage()->GetSize() != pRoot->getFrameArea().SSize() )
+ pRoot->GetDrawPage()->SetSize( pRoot->getFrameArea().SSize() );
+
+ m_pSdrPageView = m_pDrawView->ShowSdrPage( pRoot->GetDrawPage());
+ // Notify drawing page view about invisible layers
+ rIDDMA.NotifyInvisibleLayers( *m_pSdrPageView );
+ }
+ m_pDrawView->SetDragStripes( pNewOpt->IsCrossHair() );
+ m_pDrawView->SetGridSnap( pNewOpt->IsSnap() );
+ m_pDrawView->SetGridVisible( pNewOpt->IsGridVisible() );
+ const Size &rSz = pNewOpt->GetSnapSize();
+ m_pDrawView->SetGridCoarse( rSz );
+ const Size aFSize
+ ( rSz.Width() ? rSz.Width() /std::max(short(1),pNewOpt->GetDivisionX()):0,
+ rSz.Height()? rSz.Height()/std::max(short(1),pNewOpt->GetDivisionY()):0);
+ m_pDrawView->SetGridFine( aFSize );
+ Fraction aSnGrWdtX(rSz.Width(), pNewOpt->GetDivisionX() + 1);
+ Fraction aSnGrWdtY(rSz.Height(), pNewOpt->GetDivisionY() + 1);
+ m_pDrawView->SetSnapGridWidth( aSnGrWdtX, aSnGrWdtY );
+
+ if ( pRoot->getFrameArea().HasArea() )
+ m_pDrawView->SetWorkArea( pRoot->getFrameArea().SVRect() );
+
+ if ( GetShell()->IsPreview() )
+ m_pDrawView->SetAnimationEnabled( false );
+
+ m_pDrawView->SetUseIncompatiblePathCreateInterface( false );
+
+ // set handle size to 9 pixels, always
+ m_pDrawView->SetMarkHdlSizePixel(9);
+}
+
+/// CTor for the core internals
+SwViewShellImp::SwViewShellImp( SwViewShell *pParent ) :
+ m_pShell( pParent ),
+ m_pSdrPageView( nullptr ),
+ m_pFirstVisiblePage( nullptr ),
+ m_pLayAction( nullptr ),
+ m_pIdleAct( nullptr ),
+ m_bFirstPageInvalid( true ),
+ m_bResetHdlHiddenPaint( false ),
+ m_bSmoothUpdate( false ),
+ m_bStopSmooth( false ),
+ m_nRestoreActions( 0 )
+{
+}
+
+SwViewShellImp::~SwViewShellImp()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ m_pAccessibleMap.reset();
+#endif
+
+ m_pPagePreviewLayout.reset();
+
+ // Make sure HideSdrPage is also executed after ShowSdrPage.
+ if( m_pDrawView )
+ m_pDrawView->HideSdrPage();
+
+ m_pDrawView.reset();
+
+ DeletePaintRegion();
+
+ OSL_ENSURE( !m_pLayAction, "Have action for the rest of your life." );
+ OSL_ENSURE( !m_pIdleAct,"Be idle for the rest of your life." );
+}
+
+bool SwViewShellImp::AddPaintRect( const SwRect &rRect )
+{
+ // In case of tiled rendering the visual area is the last painted tile -> not interesting.
+ if ( rRect.Overlaps( m_pShell->VisArea() ) || comphelper::LibreOfficeKit::isActive() )
+ {
+ if ( !m_oPaintRegion )
+ {
+ // In case of normal rendering, this makes sure only visible rectangles are painted.
+ // Otherwise get the rectangle of the full document, so all paint rectangles are invalidated.
+ const SwRect& rArea = comphelper::LibreOfficeKit::isActive() ? m_pShell->GetLayout()->getFrameArea() : m_pShell->VisArea();
+ m_oPaintRegion.emplace();
+ m_oPaintRegion->ChangeOrigin(rArea);
+ }
+ if(!m_oPaintRegion->empty())
+ {
+ // This function often gets called with rectangles that line up vertically.
+ // Try to extend the last one downwards to include the new one (use Union()
+ // in case the new one is actually already contained in the last one).
+ SwRect& last = m_oPaintRegion->back();
+ if(last.Left() == rRect.Left() && last.Width() == rRect.Width()
+ && last.Bottom() + 1 >= rRect.Top() && last.Bottom() <= rRect.Bottom())
+ {
+ last.Union(rRect);
+ // And these rectangles lined up vertically often come up in groups
+ // that line up horizontally. Try to extend the previous rectangle
+ // to the right to include the last one.
+ if(m_oPaintRegion->size() > 1)
+ {
+ SwRect& last2 = (*m_oPaintRegion)[m_oPaintRegion->size() - 2];
+ if(last2.Top() == last.Top() && last2.Height() == last.Height()
+ && last2.Right() + 1 >= last.Left() && last2.Right() <= last2.Right())
+ {
+ last2.Union(last);
+ m_oPaintRegion->pop_back();
+ return true;
+ }
+ }
+ return true;
+ }
+ }
+ (*m_oPaintRegion) += rRect;
+ return true;
+ }
+ return false;
+}
+
+void SwViewShellImp::AddPendingLOKInvalidation( const SwRect& rRect )
+{
+ std::vector<SwRect>& l = m_pendingLOKInvalidations;
+ if(l.empty() && m_pShell && m_pShell->GetSfxViewShell()) // Announce that these invalidations will need flushing.
+ m_pShell->GetSfxViewShell()->libreOfficeKitViewAddPendingInvalidateTiles();
+ // These are often repeated, so check first for duplicates.
+ if( std::find( l.begin(), l.end(), rRect ) == l.end())
+ l.push_back( rRect );
+}
+
+std::vector<SwRect> SwViewShellImp::TakePendingLOKInvalidations()
+{
+ std::vector<SwRect> ret;
+ std::swap(ret, m_pendingLOKInvalidations);
+ return ret;
+}
+
+void SwViewShellImp::CheckWaitCursor()
+{
+ if ( m_pLayAction )
+ m_pLayAction->CheckWaitCursor();
+}
+
+bool SwViewShellImp::IsCalcLayoutProgress() const
+{
+ return m_pLayAction && m_pLayAction->IsCalcLayout();
+}
+
+bool SwViewShellImp::IsUpdateExpFields()
+{
+ if ( m_pLayAction && m_pLayAction->IsCalcLayout() )
+ {
+ m_pLayAction->SetUpdateExpFields();
+ return true;
+ }
+ return false;
+}
+
+void SwViewShellImp::SetFirstVisPage(OutputDevice const * pRenderContext)
+{
+ if ( m_pShell->mbDocSizeChgd && m_pShell->VisArea().Top() > m_pShell->GetLayout()->getFrameArea().Height() )
+ {
+ //We are in an action and because of erase actions the VisArea is
+ //after the first visible page.
+ //To avoid excessive formatting, hand back the last page.
+ m_pFirstVisiblePage = static_cast<SwPageFrame*>(m_pShell->GetLayout()->Lower());
+ while ( m_pFirstVisiblePage && m_pFirstVisiblePage->GetNext() )
+ m_pFirstVisiblePage = static_cast<SwPageFrame*>(m_pFirstVisiblePage->GetNext());
+ }
+ else
+ {
+ const SwViewOption* pSwViewOption = GetShell()->GetViewOptions();
+ const bool bBookMode = pSwViewOption->IsViewLayoutBookMode();
+
+ SwPageFrame *pPage = static_cast<SwPageFrame*>(m_pShell->GetLayout()->Lower());
+ SwRect aPageRect = pPage->GetBoundRect(pRenderContext);
+ while ( pPage && !aPageRect.Overlaps( m_pShell->VisArea() ) )
+ {
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ if ( pPage )
+ {
+ aPageRect = pPage->GetBoundRect(pRenderContext);
+ if ( bBookMode && pPage->IsEmptyPage() )
+ {
+ const SwPageFrame& rFormatPage = pPage->GetFormatPage();
+ aPageRect.SSize( rFormatPage.GetBoundRect(pRenderContext).SSize() );
+ }
+ }
+ }
+ m_pFirstVisiblePage = pPage ? pPage : static_cast<SwPageFrame*>(m_pShell->GetLayout()->Lower());
+ }
+ m_bFirstPageInvalid = false;
+}
+
+void SwViewShellImp::MakeDrawView()
+{
+ IDocumentDrawModelAccess& rIDDMA = GetShell()->getIDocumentDrawModelAccess();
+
+ // the else here is not an error, MakeDrawModel_() calls this method again
+ // after the DrawModel is created to create DrawViews for all shells...
+ if( !rIDDMA.GetDrawModel() )
+ {
+ rIDDMA.MakeDrawModel_();
+ }
+ else
+ {
+ if ( !m_pDrawView )
+ {
+ // #i72809#
+ // Discussed with FME, he also thinks that the getPrinter is old and not correct. When i got
+ // him right, it anyways returns GetOut() when it's a printer, but NULL when not. He suggested
+ // to use GetOut() and check the existing cases.
+ // Check worked well. Took a look at viewing, printing, PDF export and print preview with a test
+ // document which has an empty 2nd page (right page, see bug)
+ auto pWin = GetShell()->GetWin();
+ OutputDevice* pOutDevForDrawView = pWin ? pWin->GetOutDev() : nullptr;
+
+ if(!pOutDevForDrawView)
+ {
+ pOutDevForDrawView = GetShell()->GetOut();
+ }
+
+ m_pDrawView.reset( new SwDrawView(
+ *this,
+ *rIDDMA.GetOrCreateDrawModel(),
+ pOutDevForDrawView) );
+ }
+
+ GetDrawView()->SetActiveLayer("Heaven");
+ const SwViewOption* pSwViewOption = GetShell()->GetViewOptions();
+ Init(pSwViewOption);
+
+ // #i68597# If document is read-only, we will not profit from overlay,
+ // so switch it off.
+ if (m_pDrawView->IsBufferedOverlayAllowed())
+ {
+ if(pSwViewOption->IsReadonly())
+ {
+ m_pDrawView->SetBufferedOverlayAllowed(false);
+ }
+ }
+ }
+}
+
+Color SwViewShellImp::GetRetoucheColor() const
+{
+ Color aRet( COL_TRANSPARENT );
+ const SwViewShell &rSh = *GetShell();
+ if (rSh.GetWin() || rSh.isOutputToWindow())
+ {
+ if ( rSh.GetViewOptions()->getBrowseMode() &&
+ COL_TRANSPARENT != rSh.GetViewOptions()->GetRetoucheColor() )
+ aRet = rSh.GetViewOptions()->GetRetoucheColor();
+ else if(rSh.GetViewOptions()->IsPagePreview() &&
+ !officecfg::Office::Common::Accessibility::IsForPagePreviews::get())
+ aRet = COL_WHITE;
+ else
+ aRet = rSh.GetViewOptions()->GetDocColor();
+ }
+ return aRet;
+}
+
+SwPageFrame *SwViewShellImp::GetFirstVisPage(OutputDevice const * pRenderContext)
+{
+ if ( m_bFirstPageInvalid )
+ SetFirstVisPage(pRenderContext);
+ return m_pFirstVisiblePage;
+}
+
+const SwPageFrame *SwViewShellImp::GetFirstVisPage(OutputDevice const * pRenderContext) const
+{
+ if ( m_bFirstPageInvalid )
+ const_cast<SwViewShellImp*>(this)->SetFirstVisPage(pRenderContext);
+ return m_pFirstVisiblePage;
+}
+
+const SwPageFrame* SwViewShellImp::GetLastVisPage(const OutputDevice* pRenderContext) const
+{
+ const SwViewOption* pSwViewOption = m_pShell->GetViewOptions();
+ const bool bBookMode = pSwViewOption->IsViewLayoutBookMode();
+ const SwPageFrame* pPage = GetFirstVisPage(pRenderContext);
+ const SwPageFrame* pLastVisPage = pPage;
+ SwRect aPageRect = pPage->GetBoundRect(pRenderContext);
+ while (pPage && (pPage->IsEmptyPage() || aPageRect.Overlaps(m_pShell->VisArea())))
+ {
+ pLastVisPage = pPage;
+ pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
+ if (pPage)
+ {
+ aPageRect = pPage->GetBoundRect(pRenderContext);
+ if (bBookMode && pPage->IsEmptyPage())
+ {
+ const SwPageFrame& rFormatPage = pPage->GetFormatPage();
+ aPageRect.SSize(rFormatPage.GetBoundRect(pRenderContext).SSize());
+ }
+ }
+ }
+ return pLastVisPage;
+}
+
+// create page preview layout
+void SwViewShellImp::InitPagePreviewLayout()
+{
+ OSL_ENSURE( m_pShell->GetLayout(), "no layout - page preview layout can not be created.");
+ if ( m_pShell->GetLayout() )
+ m_pPagePreviewLayout.reset( new SwPagePreviewLayout( *m_pShell, *(m_pShell->GetLayout()) ) );
+}
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+void SwViewShellImp::UpdateAccessible()
+{
+ // We require a layout and an XModel to be accessible.
+ IDocumentLayoutAccess& rIDLA = GetShell()->getIDocumentLayoutAccess();
+ vcl::Window *pWin = GetShell()->GetWin();
+ OSL_ENSURE( GetShell()->GetLayout(), "no layout, no access" );
+ OSL_ENSURE( pWin, "no window, no access" );
+
+ if( IsAccessible() && rIDLA.GetCurrentViewShell() && pWin )
+ {
+ try
+ {
+ GetAccessibleMap().GetDocumentView();
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("sw.a11y", "");
+ assert(!"SwViewShellImp::UpdateAccessible: unhandled exception");
+ }
+ }
+}
+
+void SwViewShellImp::DisposeAccessible(const SwFrame *pFrame,
+ const SdrObject *pObj,
+ bool bRecursive,
+ bool bCanSkipInvisible)
+{
+ OSL_ENSURE( !pFrame || pFrame->IsAccessibleFrame(), "frame is not accessible" );
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if( rTmp.Imp()->IsAccessible() )
+ rTmp.Imp()->GetAccessibleMap().A11yDispose( pFrame, pObj, nullptr, bRecursive, bCanSkipInvisible );
+ }
+}
+
+void SwViewShellImp::MoveAccessible( const SwFrame *pFrame, const SdrObject *pObj,
+ const SwRect& rOldFrame )
+{
+ OSL_ENSURE( !pFrame || pFrame->IsAccessibleFrame(), "frame is not accessible" );
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if( rTmp.Imp()->IsAccessible() )
+ rTmp.Imp()->GetAccessibleMap().InvalidatePosOrSize( pFrame, pObj, nullptr,
+ rOldFrame );
+ }
+}
+
+void SwViewShellImp::InvalidateAccessibleFrameContent( const SwFrame *pFrame )
+{
+ OSL_ENSURE( pFrame->IsAccessibleFrame(), "frame is not accessible" );
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if( rTmp.Imp()->IsAccessible() )
+ rTmp.Imp()->GetAccessibleMap().InvalidateContent( pFrame );
+ }
+}
+
+void SwViewShellImp::InvalidateAccessibleCursorPosition( const SwFrame *pFrame )
+{
+ if( IsAccessible() )
+ GetAccessibleMap().InvalidateCursorPosition( pFrame );
+}
+
+void SwViewShellImp::InvalidateAccessibleEditableState( bool bAllShells,
+ const SwFrame *pFrame )
+{
+ if( bAllShells )
+ {
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if( rTmp.Imp()->IsAccessible() )
+ rTmp.Imp()->GetAccessibleMap().InvalidateEditableStates( pFrame );
+ }
+ }
+ else if( IsAccessible() )
+ {
+ GetAccessibleMap().InvalidateEditableStates( pFrame );
+ }
+}
+
+void SwViewShellImp::InvalidateAccessibleRelationSet( const SwFlyFrame *pMaster,
+ const SwFlyFrame *pFollow )
+{
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if( rTmp.Imp()->IsAccessible() )
+ rTmp.Imp()->GetAccessibleMap().InvalidateRelationSet( pMaster,
+ pFollow );
+ }
+}
+
+/// invalidate CONTENT_FLOWS_FROM/_TO relation for paragraphs
+void SwViewShellImp::InvalidateAccessibleParaFlowRelation_( const SwTextFrame* _pFromTextFrame,
+ const SwTextFrame* _pToTextFrame )
+{
+ if ( !_pFromTextFrame && !_pToTextFrame )
+ {
+ // No text frame provided. Thus, nothing to do.
+ return;
+ }
+
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if ( rTmp.Imp()->IsAccessible() )
+ {
+ if ( _pFromTextFrame )
+ {
+ rTmp.Imp()->GetAccessibleMap().
+ InvalidateParaFlowRelation( *_pFromTextFrame, true );
+ }
+ if ( _pToTextFrame )
+ {
+ rTmp.Imp()->GetAccessibleMap().
+ InvalidateParaFlowRelation( *_pToTextFrame, false );
+ }
+ }
+ }
+}
+
+/// invalidate text selection for paragraphs
+void SwViewShellImp::InvalidateAccessibleParaTextSelection_()
+{
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if ( rTmp.Imp()->IsAccessible() )
+ {
+ rTmp.Imp()->GetAccessibleMap().InvalidateTextSelectionOfAllParas();
+ }
+ }
+}
+
+/// invalidate attributes for paragraphs
+void SwViewShellImp::InvalidateAccessibleParaAttrs_( const SwTextFrame& rTextFrame )
+{
+ for(SwViewShell& rTmp : GetShell()->GetRingContainer())
+ {
+ if ( rTmp.Imp()->IsAccessible() )
+ {
+ rTmp.Imp()->GetAccessibleMap().InvalidateAttr( rTextFrame );
+ }
+ }
+}
+
+void SwViewShellImp::UpdateAccessiblePreview( const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
+ const Fraction& _rScale,
+ const SwPageFrame* _pSelectedPageFrame,
+ const Size& _rPreviewWinSize )
+{
+ if( IsAccessible() )
+ GetAccessibleMap().UpdatePreview( _rPreviewPages, _rScale,
+ _pSelectedPageFrame, _rPreviewWinSize );
+}
+
+void SwViewShellImp::InvalidateAccessiblePreviewSelection( sal_uInt16 nSelPage )
+{
+ if( IsAccessible() )
+ GetAccessibleMap().InvalidatePreviewSelection( nSelPage );
+}
+
+SwAccessibleMap *SwViewShellImp::CreateAccessibleMap()
+{
+ assert(!m_pAccessibleMap);
+ m_pAccessibleMap = std::make_shared<SwAccessibleMap>(GetShell());
+ return m_pAccessibleMap.get();
+}
+
+void SwViewShellImp::FireAccessibleEvents()
+{
+ if( IsAccessible() )
+ GetAccessibleMap().FireEvents();
+}
+#endif // ENABLE_WASM_STRIP_ACCESSIBILITY
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/view/viewpg.cxx b/sw/source/core/view/viewpg.cxx
new file mode 100644
index 0000000000..02ebd1a69e
--- /dev/null
+++ b/sw/source/core/view/viewpg.cxx
@@ -0,0 +1,216 @@
+/* -*- 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 <config_wasm_strip.h>
+
+#include <tools/fract.hxx>
+#include <osl/diagnose.h>
+#include <viewsh.hxx>
+#include <pagefrm.hxx>
+#include <viewimp.hxx>
+#include <printdata.hxx>
+#include <ptqueue.hxx>
+#include <fntcache.hxx>
+
+#include <vprint.hxx>
+
+using namespace ::com::sun::star;
+
+SwPagePreviewLayout* SwViewShell::PagePreviewLayout()
+{
+ return Imp()->PagePreviewLayout();
+}
+
+void SwViewShell::ShowPreviewSelection( sal_uInt16 nSelPage )
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ Imp()->InvalidateAccessiblePreviewSelection( nSelPage );
+#else
+ (void)nSelPage;
+#endif
+}
+
+// adjust view options for page preview
+void SwViewShell::AdjustOptionsForPagePreview(SwPrintData const& rPrintOptions)
+{
+ if ( !IsPreview() )
+ {
+ OSL_FAIL( "view shell doesn't belongs to a page preview - no adjustment of its view options");
+ return;
+ }
+
+ PrepareForPrint( rPrintOptions );
+}
+
+/// print brochure
+// consider empty pages on calculation of the scaling
+// for a page to be printed.
+void SwViewShell::PrintProspect(
+ OutputDevice *pOutDev,
+ const SwPrintData &rPrintData,
+ sal_Int32 nRenderer // the index in the vector of prospect pages to be printed
+ )
+{
+ const sal_Int32 nMaxRenderer = rPrintData.GetRenderData().GetPagePairsForProspectPrinting().size() - 1;
+ OSL_ENSURE( 0 <= nRenderer && nRenderer <= nMaxRenderer, "nRenderer out of bounds");
+ Printer *pPrinter = dynamic_cast< Printer * >(pOutDev);
+ if (!pPrinter || nMaxRenderer < 0 || nRenderer < 0 || nRenderer > nMaxRenderer)
+ return;
+
+ // save settings of OutputDevice (should be done always since the
+ // output device is now provided by a call from outside the Writer)
+ pPrinter->Push();
+
+ std::pair< sal_Int32, sal_Int32 > rPagesToPrint =
+ rPrintData.GetRenderData().GetPagePairsForProspectPrinting()[ nRenderer ];
+ OSL_ENSURE( rPagesToPrint.first == -1 || rPrintData.GetRenderData().GetValidPagesSet().count( rPagesToPrint.first ) == 1, "first Page not valid" );
+ OSL_ENSURE( rPagesToPrint.second == -1 || rPrintData.GetRenderData().GetValidPagesSet().count( rPagesToPrint.second ) == 1, "second Page not valid" );
+
+ // create a new shell for the printer
+ SwViewShell aShell( *this, nullptr, pPrinter );
+
+ CurrShell aCurr( &aShell );
+
+ aShell.PrepareForPrint( rPrintData );
+
+ //!! applying view options and formatting the document should now only be done in getRendererCount!
+
+ MapMode aMapMode( MapUnit::MapTwip );
+ Size aPrtSize( pPrinter->PixelToLogic( pPrinter->GetPaperSizePixel(), aMapMode ) );
+
+ SwTwips nMaxRowSz, nMaxColSz;
+
+ const SwPageFrame *pStPage = nullptr;
+ const SwPageFrame *pNxtPage = nullptr;
+ if (rPagesToPrint.first > 0)
+ {
+ pStPage = sw_getPage(*aShell.GetLayout(), rPagesToPrint.first);
+ }
+ if (rPagesToPrint.second > 0)
+ {
+ pNxtPage = sw_getPage(*aShell.GetLayout(), rPagesToPrint.second);
+ }
+
+ // i#14016 consider empty pages on calculation
+ // of page size, used for calculation of scaling.
+ Size aSttPageSize;
+ if ( pStPage )
+ {
+ if ( pStPage->IsEmptyPage() )
+ {
+ if ( pStPage->GetPhyPageNum() % 2 == 0 )
+ aSttPageSize = pStPage->GetPrev()->getFrameArea().SSize();
+ else
+ aSttPageSize = pStPage->GetNext()->getFrameArea().SSize();
+ }
+ else
+ {
+ aSttPageSize = pStPage->getFrameArea().SSize();
+ }
+ }
+ Size aNxtPageSize;
+ if ( pNxtPage )
+ {
+ if ( pNxtPage->IsEmptyPage() )
+ {
+ if ( pNxtPage->GetPhyPageNum() % 2 == 0 )
+ aNxtPageSize = pNxtPage->GetPrev()->getFrameArea().SSize();
+ else
+ aNxtPageSize = pNxtPage->GetNext()->getFrameArea().SSize();
+ }
+ else
+ {
+ aNxtPageSize = pNxtPage->getFrameArea().SSize();
+ }
+ }
+
+ if( !pStPage )
+ {
+ nMaxColSz = 2 * aNxtPageSize.Width();
+ nMaxRowSz = aNxtPageSize.Height();
+ }
+ else if( !pNxtPage )
+ {
+ nMaxColSz = 2 * aSttPageSize.Width();
+ nMaxRowSz = aSttPageSize.Height();
+ }
+ else
+ {
+ nMaxColSz = aNxtPageSize.Width() + aSttPageSize.Width();
+ nMaxRowSz = std::max( aNxtPageSize.Height(), aSttPageSize.Height() );
+ }
+
+ // set the MapMode
+ aMapMode.SetOrigin( Point() );
+ {
+ Fraction aScX( aPrtSize.Width(), nMaxColSz );
+ Fraction aScY( aPrtSize.Height(), nMaxRowSz );
+ if( aScX < aScY )
+ aScY = aScX;
+
+ {
+ // Round percentages for Drawings so that these can paint their objects properly
+ aScY *= Fraction( 1000, 1 );
+ tools::Long nTmp = static_cast<tools::Long>(aScY);
+ if( 1 < nTmp )
+ --nTmp;
+ else
+ nTmp = 1;
+ aScY = Fraction( nTmp, 1000 );
+ }
+
+ aMapMode.SetScaleY( aScY );
+ aMapMode.SetScaleX( aScY );
+ }
+
+ Size aTmpPrtSize( pPrinter->PixelToLogic( pPrinter->GetPaperSizePixel(), aMapMode ) );
+
+ // calculate start point for equal border on all sides
+ Point aSttPt( (aTmpPrtSize.Width() - nMaxColSz) / 2,
+ (aTmpPrtSize.Height() - nMaxRowSz) / 2 );
+ for( int nC = 0; nC < 2; ++nC )
+ {
+ if( pStPage )
+ {
+ aShell.Imp()->SetFirstVisPageInvalid();
+ aShell.maVisArea = pStPage->getFrameArea();
+
+ Point aPos( aSttPt );
+ aPos -= aShell.maVisArea.Pos();
+ aMapMode.SetOrigin( aPos );
+ pPrinter->SetMapMode( aMapMode );
+ pStPage->GetUpper()->PaintSwFrame( *pOutDev, pStPage->getFrameArea() );
+ }
+
+ pStPage = pNxtPage;
+ aSttPt.AdjustX(aTmpPrtSize.Width() / 2 );
+ }
+
+ SwPaintQueue::Repaint();
+
+ //!! applying/modifying view options and formatting the document should now only be done in getRendererCount!
+
+ pFntCache->Flush();
+
+ // restore settings of OutputDevice (should be done always now since the
+ // output device is now provided by a call from outside the Writer)
+ pPrinter->Pop();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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: */
diff --git a/sw/source/core/view/vnew.cxx b/sw/source/core/view/vnew.cxx
new file mode 100644
index 0000000000..613a15df63
--- /dev/null
+++ b/sw/source/core/view/vnew.cxx
@@ -0,0 +1,383 @@
+/* -*- 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 <sfx2/printer.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <doc.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <DocumentSettingManager.hxx>
+#include <IDocumentDeviceAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentState.hxx>
+#include <docsh.hxx>
+#include <viewsh.hxx>
+#include <rootfrm.hxx>
+#include <viewimp.hxx>
+#include <viewopt.hxx>
+#include <txtfrm.hxx>
+#include <notxtfrm.hxx>
+#include <fntcache.hxx>
+#include <docufld.hxx>
+#include <ptqueue.hxx>
+#include <dview.hxx>
+#include <ndgrf.hxx>
+#include <ndindex.hxx>
+#include <accessibilityoptions.hxx>
+
+void SwViewShell::Init( const SwViewOption *pNewOpt )
+{
+ mbDocSizeChgd = false;
+
+ // We play it safe: Remove old font information whenever the printer
+ // resolution or the zoom factor changes. For that, Init() and Reformat()
+ // are the most secure places.
+ pFntCache->Flush( );
+
+ // ViewOptions are created dynamically
+
+ if( !mpOpt )
+ {
+ mpOpt.reset(new SwViewOption);
+
+ // ApplyViewOptions() does not need to be called
+ if( pNewOpt )
+ {
+ *mpOpt = *pNewOpt;
+ // Zoom factor needs to be set because there is no call to ApplyViewOptions() during
+ // CTOR for performance reasons.
+ if( GetWin() && 100 != mpOpt->GetZoom() )
+ {
+ MapMode aMode( mpWin->GetMapMode() );
+ const Fraction aNewFactor( mpOpt->GetZoom(), 100 );
+ aMode.SetScaleX( aNewFactor );
+ aMode.SetScaleY( aNewFactor );
+ mpWin->SetMapMode( aMode );
+ }
+ }
+ }
+
+ SwDocShell* pDShell = mxDoc->GetDocShell();
+ mxDoc->GetDocumentSettingManager().set(DocumentSettingId::HTML_MODE, 0 != ::GetHtmlMode( pDShell ) );
+ // set readonly flag at ViewOptions before creating layout. Otherwise,
+ // one would have to reformat again.
+
+ if( pDShell && pDShell->IsReadOnly() )
+ mpOpt->SetReadonly( true );
+
+ SAL_INFO( "sw.core", "View::Init - before InitPrt" );
+ OutputDevice* pPDFOut = nullptr;
+
+ if (mpOut && (OUTDEV_PDF == mpOut->GetOutDevType()))
+ pPDFOut = mpOut;
+
+ // Only setup the printer if we need one:
+ const bool bBrowseMode = mpOpt->getBrowseMode();
+ if( pPDFOut )
+ InitPrt( pPDFOut );
+
+ // i#44963 Good occasion to check if page sizes in
+ // page descriptions are still set to (LONG_MAX, LONG_MAX) (html import)
+ if ( !bBrowseMode )
+ {
+ mxDoc->CheckDefaultPageFormat();
+ }
+
+ SAL_INFO( "sw.core", "View::Init - after InitPrt" );
+ if( GetWin() )
+ {
+ SwViewOption::Init( GetWin()->GetOutDev() );
+ GetWin()->GetOutDev()->SetFillColor();
+ GetWin()->SetBackground();
+ GetWin()->GetOutDev()->SetLineColor();
+ }
+
+ // Create a new layout, if there is no one available
+ if( !mpLayout )
+ {
+ // Here's the code which disables the usage of "multiple" layouts at the moment
+ // If the problems with controls and groups objects are solved,
+ // this code can be removed...
+ SwViewShell *pCurrShell = GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
+ if( pCurrShell )
+ mpLayout = pCurrShell->mpLayout;
+ // end of "disable multiple layouts"
+ if( !mpLayout )
+ {
+ // switched to two step construction because creating the layout in SwRootFrame needs a valid pLayout set
+ mpLayout = SwRootFramePtr(new SwRootFrame(mxDoc->GetDfltFrameFormat(), this),
+ &SwFrame::DestroyFrame);
+ mpLayout->Init( mxDoc->GetDfltFrameFormat() );
+ }
+ }
+ SizeChgNotify();
+
+ // XForms mode: initialize XForms mode, based on design mode (draw view)
+ // MakeDrawView() requires layout
+ if( GetDoc()->isXForms() )
+ {
+ if( ! HasDrawView() )
+ MakeDrawView();
+ mpOpt->SetFormView( ! GetDrawView()->IsDesignMode() );
+ }
+}
+
+/// CTor for the first Shell.
+SwViewShell::SwViewShell( SwDoc& rDocument, vcl::Window *pWindow,
+ const SwViewOption *pNewOpt, OutputDevice *pOutput,
+ tools::Long nFlags )
+ :
+ mpSfxViewShell( nullptr ),
+ mpImp( new SwViewShellImp( this ) ),
+ mpWin( pWindow ),
+ mpOut( pOutput ? pOutput
+ : pWindow ? pWindow->GetOutDev()
+ : static_cast<OutputDevice*>(rDocument.getIDocumentDeviceAccess().getPrinter( true ))),
+ mpAccOptions( new SwAccessibilityOptions ),
+ mbShowHeaderSeparator( false ),
+ mbShowFooterSeparator( false ),
+ mbHeaderFooterEdit( false ),
+ mpTargetPaintWindow(nullptr),
+ mpBufferedOut(nullptr),
+ mxDoc( &rDocument ),
+ mnStartAction( 0 ),
+ mnLockPaint( 0 ),
+ mbSelectAll(false),
+ mbOutputToWindow(false),
+ mpPrePostOutDev(nullptr)
+{
+ // in order to suppress event handling in
+ // <SwDrawContact::Changed> during construction of <SwViewShell> instance
+ mbInConstructor = true;
+
+ mbPaintInProgress = mbViewLocked = mbInEndAction = false;
+ mbPaintWorks = mbEnableSmooth = true;
+ mbPreview = 0 !=( VSHELLFLAG_ISPREVIEW & nFlags );
+
+ // i#38810 Do not reset modified state of document,
+ // if it's already been modified.
+ const bool bIsDocModified( mxDoc->getIDocumentState().IsModified() );
+ OutputDevice* pOrigOut = mpOut;
+ Init( pNewOpt ); // may change the Outdev (InitPrt())
+ mpOut = pOrigOut;
+
+ // initialize print preview layout after layout
+ // is created in <SwViewShell::Init(..)> - called above.
+ if ( mbPreview )
+ {
+ // init page preview layout
+ mpImp->InitPagePreviewLayout();
+ }
+
+ CurrShell aCurr( this );
+
+ static_cast<SwHiddenTextFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenText ))->
+ SetHiddenFlag( !mpOpt->IsShowHiddenField() );
+
+ // In Init a standard FrameFormat is created.
+ if ( !mxDoc->GetIDocumentUndoRedo().IsUndoNoResetModified()
+ && !bIsDocModified )
+ {
+ mxDoc->getIDocumentState().ResetModified();
+ }
+
+ // extend format cache.
+ if ( SwTextFrame::GetTextCache()->GetCurMax() < 2550 )
+ SwTextFrame::GetTextCache()->IncreaseMax( 100 );
+ if( mpOpt->IsGridVisible() || getIDocumentDrawModelAccess().GetDrawModel() )
+ Imp()->MakeDrawView();
+
+ mbInConstructor = false;
+}
+
+/// CTor for further Shells on a document.
+SwViewShell::SwViewShell( SwViewShell& rShell, vcl::Window *pWindow,
+ OutputDevice * pOutput, tools::Long const nFlags)
+ : Ring( &rShell ) ,
+ maBrowseBorder( rShell.maBrowseBorder ),
+ mpSfxViewShell( nullptr ),
+ mpImp( new SwViewShellImp( this ) ),
+ mpWin( pWindow ),
+ mpOut( pOutput ? pOutput
+ : pWindow ? pWindow->GetOutDev()
+ : static_cast<OutputDevice*>(rShell.GetDoc()->getIDocumentDeviceAccess().getPrinter( true ))),
+ mpAccOptions( new SwAccessibilityOptions ),
+ mbShowHeaderSeparator( false ),
+ mbShowFooterSeparator( false ),
+ mbHeaderFooterEdit( false ),
+ mpTargetPaintWindow(nullptr),
+ mpBufferedOut(nullptr),
+ mxDoc( rShell.GetDoc() ),
+ mnStartAction( 0 ),
+ mnLockPaint( 0 ),
+ mbSelectAll(false),
+ mbOutputToWindow(false),
+ mpPrePostOutDev(nullptr)
+{
+ // in order to suppress event handling in
+ // <SwDrawContact::Changed> during construction of <SwViewShell> instance
+ mbInConstructor = true;
+
+ mbPaintWorks = mbEnableSmooth = true;
+ mbPaintInProgress = mbViewLocked = mbInEndAction = false;
+ mbPreview = 0 !=( VSHELLFLAG_ISPREVIEW & nFlags );
+
+ if( nFlags & VSHELLFLAG_SHARELAYOUT )
+ mpLayout = rShell.mpLayout;
+
+ CurrShell aCurr( this );
+
+ bool bModified = mxDoc->getIDocumentState().IsModified();
+
+ OutputDevice* pOrigOut = mpOut;
+ Init( rShell.GetViewOptions() ); // might change Outdev (InitPrt())
+ mpOut = pOrigOut;
+
+ if ( mbPreview )
+ mpImp->InitPagePreviewLayout();
+
+ static_cast<SwHiddenTextFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenText ))->
+ SetHiddenFlag( !mpOpt->IsShowHiddenField() );
+
+ // In Init a standard FrameFormat is created.
+ if( !bModified && !mxDoc->GetIDocumentUndoRedo().IsUndoNoResetModified() )
+ {
+ mxDoc->getIDocumentState().ResetModified();
+ }
+
+ // extend format cache.
+ if ( SwTextFrame::GetTextCache()->GetCurMax() < 2550 )
+ SwTextFrame::GetTextCache()->IncreaseMax( 100 );
+ if( mpOpt->IsGridVisible() || getIDocumentDrawModelAccess().GetDrawModel() )
+ Imp()->MakeDrawView();
+
+ mbInConstructor = false;
+
+}
+
+SwViewShell::~SwViewShell()
+{
+ IDocumentLayoutAccess* const pLayoutAccess
+ = mxDoc ? &mxDoc->getIDocumentLayoutAccess() : nullptr;
+
+ {
+ CurrShell aCurr( this );
+ mbPaintWorks = false;
+
+ // i#9684 Stopping the animated graphics is not
+ // necessary during printing or pdf export, because the animation
+ // has not been started in this case.
+ if( mxDoc && GetWin() )
+ {
+ SwNodes& rNds = mxDoc->GetNodes();
+
+ SwStartNode *pStNd;
+ SwNodeIndex aIdx( *rNds.GetEndOfAutotext().StartOfSectionNode(), 1 );
+ while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
+ {
+ ++aIdx;
+ SwGrfNode *pGNd = aIdx.GetNode().GetGrfNode();
+ if ( nullptr != pGNd )
+ {
+ if( pGNd->IsAnimated() )
+ {
+ SwIterator<SwFrame,SwGrfNode> aIter( *pGNd );
+ for( SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
+ {
+ OSL_ENSURE( pFrame->IsNoTextFrame(), "GraphicNode with Text?" );
+ static_cast<SwNoTextFrame*>(pFrame)->StopAnimation( mpOut );
+ }
+ }
+ }
+ aIdx.Assign( *pStNd->EndOfSectionNode(), +1 );
+ }
+
+ GetDoc()->StopNumRuleAnimations( mpOut );
+ }
+
+ mpImp.reset();
+
+ if (mxDoc)
+ {
+ if( mxDoc->getReferenceCount() > 1 )
+ GetLayout()->ResetNewLayout();
+ }
+
+ mpOpt.reset();
+
+ // resize format cache.
+ if ( SwTextFrame::GetTextCache()->GetCurMax() > 250 )
+ SwTextFrame::GetTextCache()->DecreaseMax( 100 );
+
+ // Remove from PaintQueue if necessary
+ SwPaintQueue::Remove( this );
+
+ OSL_ENSURE( !mnStartAction, "EndAction() pending." );
+ }
+
+ if ( pLayoutAccess )
+ {
+ GetLayout()->DeRegisterShell( this );
+ if(pLayoutAccess->GetCurrentViewShell()==this)
+ {
+ pLayoutAccess->SetCurrentViewShell(nullptr);
+ for(SwViewShell& rShell : GetRingContainer())
+ {
+ if(&rShell != this)
+ {
+ pLayoutAccess->SetCurrentViewShell(&rShell);
+ break;
+ }
+ }
+ }
+ }
+
+ mpAccOptions.reset();
+}
+
+bool SwViewShell::HasDrawView() const
+{
+ return Imp() && Imp()->HasDrawView();
+}
+
+void SwViewShell::MakeDrawView()
+{
+ Imp()->MakeDrawView( );
+}
+
+bool SwViewShell::HasDrawViewDrag() const
+{
+ return Imp()->HasDrawView() && Imp()->GetDrawView()->IsDragObj();
+}
+
+SdrView* SwViewShell::GetDrawView()
+{
+ return Imp()->GetDrawView();
+}
+
+SdrView* SwViewShell::GetDrawViewWithValidMarkList()
+{
+ SwDrawView* pDView = Imp()->GetDrawView();
+ pDView->ValidateMarkList();
+ return pDView;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/view/vprint.cxx b/sw/source/core/view/vprint.cxx
new file mode 100644
index 0000000000..bc5dd5bd6c
--- /dev/null
+++ b/sw/source/core/view/vprint.cxx
@@ -0,0 +1,676 @@
+/* -*- 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 <hintids.hxx>
+#include <sfx2/printer.hxx>
+#include <svx/svdview.hxx>
+#include <osl/diagnose.h>
+#include <tools/UnitConversion.hxx>
+
+#include <txtfld.hxx>
+#include <fmtfld.hxx>
+#include <fmtfsize.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <cntfrm.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <IDocumentDeviceAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <fesh.hxx>
+#include <pam.hxx>
+#include <viewimp.hxx>
+#include <layact.hxx>
+#include <ndtxt.hxx>
+#include <viewopt.hxx>
+#include <printdata.hxx>
+#include <pagedesc.hxx>
+#include <ptqueue.hxx>
+#include <viscrs.hxx>
+#include <fmtpdsc.hxx>
+#include <PostItMgr.hxx>
+#include <vprint.hxx>
+
+using namespace ::com::sun::star;
+
+/// Painting buffer
+class SwQueuedPaint
+{
+public:
+ SwQueuedPaint *pNext;
+ SwViewShell *pSh;
+ SwRect aRect;
+
+ SwQueuedPaint( SwViewShell *pNew, const SwRect &rRect ) :
+ pNext( nullptr ),
+ pSh( pNew ),
+ aRect( rRect )
+ {}
+};
+
+SwQueuedPaint *SwPaintQueue::s_pPaintQueue = nullptr;
+
+namespace {
+
+// saves some settings from the draw view
+class SwDrawViewSave
+{
+ SdrView* pDV;
+ bool bPrintControls;
+public:
+ explicit SwDrawViewSave( SdrView* pSdrView );
+ ~SwDrawViewSave();
+};
+
+}
+
+void SwPaintQueue::Add( SwViewShell *pNew, const SwRect &rNew )
+{
+ SwQueuedPaint *pPt = s_pPaintQueue;
+ if (nullptr != pPt)
+ {
+ while ( pPt->pSh != pNew && pPt->pNext )
+ pPt = pPt->pNext;
+ if ( pPt->pSh == pNew )
+ {
+ pPt->aRect.Union( rNew );
+ return;
+ }
+ }
+ SwQueuedPaint *pNQ = new SwQueuedPaint( pNew, rNew );
+ if ( pPt )
+ pPt->pNext = pNQ;
+ else
+ s_pPaintQueue = pNQ;
+}
+
+void SwPaintQueue::Repaint()
+{
+ if (SwRootFrame::IsInPaint() || !s_pPaintQueue)
+ return;
+
+ SwQueuedPaint *pPt = s_pPaintQueue;
+ do
+ { SwViewShell *pSh = pPt->pSh;
+ CurrShell aCurr( pSh );
+ if ( pSh->IsPreview() )
+ {
+ if ( pSh->GetWin() )
+ {
+ // for previewing, since rows/columns are known in PaintHdl (UI)
+ pSh->GetWin()->Invalidate();
+ }
+ }
+ else
+ pSh->Paint(*pSh->GetOut(), pPt->aRect.SVRect());
+ pPt = pPt->pNext;
+ } while ( pPt );
+
+ do
+ {
+ pPt = s_pPaintQueue;
+ s_pPaintQueue = s_pPaintQueue->pNext;
+ delete pPt;
+ } while (s_pPaintQueue);
+}
+
+void SwPaintQueue::Remove( SwViewShell const *pSh )
+{
+ SwQueuedPaint *pPt = s_pPaintQueue;
+ if (nullptr == pPt)
+ return;
+
+ SwQueuedPaint *pPrev = nullptr;
+ while ( pPt && pPt->pSh != pSh )
+ {
+ pPrev = pPt;
+ pPt = pPt->pNext;
+ }
+ if ( pPt )
+ {
+ if ( pPrev )
+ pPrev->pNext = pPt->pNext;
+ else if (pPt == s_pPaintQueue)
+ s_pPaintQueue = nullptr;
+ delete pPt;
+ }
+}
+
+void SetSwVisArea( SwViewShell *pSh, const SwRect &rRect )
+{
+ OSL_ENSURE( !pSh->GetWin(), "Print with window?" );
+ pSh->maVisArea = rRect;
+ pSh->Imp()->SetFirstVisPageInvalid();
+ Point aPt( rRect.Pos() );
+
+ // calculate an offset for the rectangle of the n-th page to
+ // move the start point of the output operation to a position
+ // such that in the output device all pages will be painted
+ // at the same position
+ aPt.setX( -aPt.X() ); aPt.setY( -aPt.Y() );
+
+ vcl::RenderContext *pOut = pSh->GetOut();
+
+ MapMode aMapMode( pOut->GetMapMode() );
+ aMapMode.SetOrigin( aPt );
+ pOut->SetMapMode( aMapMode );
+}
+
+void SwViewShell::InitPrt( OutputDevice *pOutDev )
+{
+ // For printing we use a negative offset (exactly the offset of OutputSize).
+ // This is necessary because the origin is in the upper left corner of the
+ // physical page while the output uses OutputOffset as origin.
+ if ( pOutDev )
+ {
+ maPrtOffset = Point();
+
+ maPrtOffset += pOutDev->GetMapMode().GetOrigin();
+ MapMode aMapMode( pOutDev->GetMapMode() );
+ aMapMode.SetMapUnit( MapUnit::MapTwip );
+ pOutDev->SetMapMode( aMapMode );
+ pOutDev->SetLineColor();
+ pOutDev->SetFillColor();
+ }
+ else
+ {
+ maPrtOffset.setX(0);
+ maPrtOffset.setY(0);
+ }
+
+ if ( !mpWin )
+ mpOut = pOutDev;
+}
+
+void SwViewShell::ChgAllPageOrientation( Orientation eOri )
+{
+ OSL_ENSURE( mnStartAction, "missing an Action" );
+ CurrShell aCurr( this );
+
+ const size_t nAll = GetDoc()->GetPageDescCnt();
+ bool bNewOri = eOri != Orientation::Portrait;
+
+ for( size_t i = 0; i < nAll; ++ i )
+ {
+ const SwPageDesc& rOld = GetDoc()->GetPageDesc( i );
+
+ if( rOld.GetLandscape() != bNewOri )
+ {
+ SwPageDesc aNew( rOld );
+ {
+ ::sw::UndoGuard const ug(GetDoc()->GetIDocumentUndoRedo());
+ GetDoc()->CopyPageDesc(rOld, aNew);
+ }
+ aNew.SetLandscape( bNewOri );
+ SwFrameFormat& rFormat = aNew.GetMaster();
+ SwFormatFrameSize aSz( rFormat.GetFrameSize() );
+ // adjust size
+ // PORTRAIT -> higher than wide
+ // LANDSCAPE -> wider than high
+ // Height is the VarSize, width the FixSize (per Def.)
+ if( bNewOri ? aSz.GetHeight() > aSz.GetWidth()
+ : aSz.GetHeight() < aSz.GetWidth() )
+ {
+ SwTwips aTmp = aSz.GetHeight();
+ aSz.SetHeight( aSz.GetWidth() );
+ aSz.SetWidth( aTmp );
+ rFormat.SetFormatAttr( aSz );
+ }
+ GetDoc()->ChgPageDesc( i, aNew );
+ }
+ }
+}
+
+void SwViewShell::ChgAllPageSize( Size const &rSz )
+{
+ OSL_ENSURE( mnStartAction, "missing an Action" );
+ CurrShell aCurr( this );
+
+ SwDoc* pMyDoc = GetDoc();
+ const size_t nAll = pMyDoc->GetPageDescCnt();
+
+ for( size_t i = 0; i < nAll; ++i )
+ {
+ const SwPageDesc &rOld = pMyDoc->GetPageDesc( i );
+ SwPageDesc aNew( rOld );
+ {
+ ::sw::UndoGuard const ug(GetDoc()->GetIDocumentUndoRedo());
+ GetDoc()->CopyPageDesc( rOld, aNew );
+ }
+ SwFrameFormat& rPgFormat = aNew.GetMaster();
+ Size aSz( rSz );
+ const bool bOri = aNew.GetLandscape();
+ if( bOri ? aSz.Height() > aSz.Width()
+ : aSz.Height() < aSz.Width() )
+ {
+ SwTwips aTmp = aSz.Height();
+ aSz.setHeight( aSz.Width() );
+ aSz.setWidth( aTmp );
+ }
+
+ SwFormatFrameSize aFrameSz( rPgFormat.GetFrameSize() );
+ aFrameSz.SetSize( aSz );
+ rPgFormat.SetFormatAttr( aFrameSz );
+ pMyDoc->ChgPageDesc( i, aNew );
+ }
+}
+
+void SwViewShell::CalcPagesForPrint( sal_uInt16 nMax )
+{
+ CurrShell aCurr( this );
+
+ SwRootFrame* pMyLayout = GetLayout();
+
+ const SwFrame *pPage = pMyLayout->Lower();
+ SwLayAction aAction( pMyLayout, Imp() );
+
+ pMyLayout->StartAllAction();
+ for ( sal_uInt16 i = 1; pPage && i <= nMax; pPage = pPage->GetNext(), ++i )
+ {
+ pPage->Calc(GetOut());
+ SwRect aOldVis( VisArea() );
+ maVisArea = pPage->getFrameArea();
+ Imp()->SetFirstVisPageInvalid();
+ aAction.Reset();
+ aAction.SetPaint( false );
+ aAction.SetWaitAllowed( false );
+ aAction.SetReschedule( true );
+
+ aAction.Action(GetOut());
+
+ maVisArea = aOldVis; //reset due to the paints
+ Imp()->SetFirstVisPageInvalid();
+ }
+
+ pMyLayout->EndAllAction();
+}
+
+void SwViewShell::FillPrtDoc( SwDoc& rPrtDoc, const SfxPrinter* pPrt)
+{
+ assert( dynamic_cast<const SwFEShell*>( this) && "SwViewShell::Prt for FEShell only");
+ SwFEShell* pFESh = static_cast<SwFEShell*>(this);
+ rPrtDoc.getIDocumentFieldsAccess().LockExpFields();
+
+ // use given printer
+ //! Make a copy of it since it gets destroyed with the temporary document
+ //! used for PDF export
+ if (pPrt)
+ rPrtDoc.getIDocumentDeviceAccess().setPrinter( VclPtr<SfxPrinter>::Create(*pPrt), true, true );
+
+ const SfxItemPool& rPool = GetAttrPool();
+ for( sal_uInt16 nWh = POOLATTR_BEGIN; nWh < POOLATTR_END; ++nWh )
+ {
+ const SfxPoolItem* pCpyItem = rPool.GetPoolDefaultItem( nWh );
+ if( nullptr != pCpyItem )
+ rPrtDoc.GetAttrPool().SetPoolDefaultItem( *pCpyItem );
+ }
+
+ // JP 29.07.99 - Bug 67951 - set all Styles from the SourceDoc into
+ // the PrintDoc - will be replaced!
+ rPrtDoc.ReplaceStyles( *GetDoc() );
+
+ SwShellCursor *pActCursor = pFESh->GetCursor_();
+ SwShellCursor *pFirstCursor = pActCursor->GetNext();
+ if( !pActCursor->HasMark() ) // with a multi-selection the current cursor might be empty
+ {
+ pActCursor = pActCursor->GetPrev();
+ }
+
+ // Y-position of the first selection
+ Point aSelPoint;
+ if( pFESh->IsTableMode() )
+ {
+ SwShellTableCursor* pShellTableCursor = pFESh->GetTableCursor();
+
+ const SwContentNode *const pContentNode =
+ pShellTableCursor->Start()->GetNode().GetContentNode();
+ const SwContentFrame *const pContentFrame = pContentNode ? pContentNode->getLayoutFrame(GetLayout(), pShellTableCursor->Start()) : nullptr;
+ if( pContentFrame )
+ {
+ SwRect aCharRect;
+ SwCursorMoveState aTmpState( CursorMoveState::NONE );
+ pContentFrame->GetCharRect( aCharRect, *pShellTableCursor->Start(), &aTmpState );
+ aSelPoint = Point( aCharRect.Left(), aCharRect.Top() );
+ }
+ }
+ else if (pFirstCursor)
+ {
+ aSelPoint = pFirstCursor->GetSttPos();
+ }
+
+ const SwPageFrame* pPage = GetLayout()->GetPageAtPos( aSelPoint );
+ OSL_ENSURE( pPage, "no page found!" );
+
+ // get page descriptor - fall back to the first one if pPage could not be found
+ const SwPageDesc* pPageDesc = pPage ? rPrtDoc.FindPageDesc(
+ pPage->GetPageDesc()->GetName() ) : &rPrtDoc.GetPageDesc( 0 );
+
+ if( !pFESh->IsTableMode() && pActCursor && pActCursor->HasMark() )
+ { // Tweak paragraph attributes of last paragraph
+ SwNodeIndex aNodeIdx( *rPrtDoc.GetNodes().GetEndOfContent().StartOfSectionNode() );
+ SwTextNode* pTextNd = rPrtDoc.GetNodes().GoNext( &aNodeIdx )->GetTextNode();
+ SwContentNode *pLastNd =
+ (*pActCursor->GetMark()) <= (*pActCursor->GetPoint())
+ ? pActCursor->GetPointContentNode()
+ : pActCursor->GetMarkContentNode();
+ // copy the paragraph attributes of the first paragraph
+ if( pLastNd && pLastNd->IsTextNode() )
+ static_cast<SwTextNode*>(pLastNd)->CopyCollFormat( *pTextNd );
+ }
+
+ // fill it with the selected content
+ pFESh->Copy(rPrtDoc);
+
+ // set the page style at the first paragraph
+ {
+ SwNodeIndex aNodeIdx( *rPrtDoc.GetNodes().GetEndOfContent().StartOfSectionNode() );
+ SwContentNode* pCNd = rPrtDoc.GetNodes().GoNext( &aNodeIdx ); // go to 1st ContentNode
+ if( pFESh->IsTableMode() )
+ {
+ SwTableNode* pTNd = pCNd->FindTableNode();
+ if( pTNd )
+ pTNd->GetTable().GetFrameFormat()->SetFormatAttr( SwFormatPageDesc( pPageDesc ) );
+ }
+ else
+ {
+ pCNd->SetAttr( SwFormatPageDesc( pPageDesc ) );
+ if( pFirstCursor && pFirstCursor->HasMark() )
+ {
+ SwTextNode *pTextNd = pCNd->GetTextNode();
+ if( pTextNd )
+ {
+ SwContentNode *pFirstNd =
+ (*pFirstCursor->GetMark()) > (*pFirstCursor->GetPoint())
+ ? pFirstCursor->GetPointContentNode()
+ : pFirstCursor->GetMarkContentNode();
+ // copy paragraph attributes of the first paragraph
+ if( pFirstNd && pFirstNd->IsTextNode() )
+ static_cast<SwTextNode*>(pFirstNd)->CopyCollFormat( *pTextNd );
+ }
+ }
+ }
+ }
+}
+
+// TODO: there is already a GetPageByPageNum, but it checks some physical page
+// number; unsure if we want that here, should find out what that is...
+SwPageFrame const*
+sw_getPage(SwRootFrame const& rLayout, sal_Int32 const nPage)
+{
+ // yes this is O(n^2) but at least it does not crash...
+ SwPageFrame const* pPage = dynamic_cast<const SwPageFrame*>(rLayout.Lower());
+ for (sal_Int32 i = nPage; pPage && (i > 0); --i)
+ {
+ if (1 == i) { // note: nPage is 1-based, i.e. 0 is invalid!
+ return pPage;
+ }
+ pPage = dynamic_cast<SwPageFrame const*>(pPage->GetNext());
+ }
+ OSL_ENSURE(pPage, "ERROR: SwPageFrame expected");
+ OSL_FAIL("non-existent page requested");
+ return nullptr;
+}
+
+namespace sw
+{
+ // tdf#91680 Reserve space in margin for comments only if there are comments
+ bool IsShrinkPageForPostIts(SwViewShell const& rShell, SwPrintData const& rPrintData)
+ {
+ SwPostItMode const nPostItMode(rPrintData.GetPrintPostIts());
+ return nPostItMode == SwPostItMode::InMargins
+ && sw_GetPostIts(rShell.GetDoc()->getIDocumentFieldsAccess(), nullptr);
+ }
+}
+
+bool SwViewShell::PrintOrPDFExport(
+ OutputDevice *pOutDev,
+ SwPrintData const& rPrintData,
+ sal_Int32 nRenderer, /* the index in the vector of pages to be printed */
+ bool bIsPDFExport )
+{
+ // CAUTION: Do also always update the printing routines in viewpg.cxx (PrintProspect)!
+
+ const sal_Int32 nMaxRenderer = rPrintData.GetRenderData().GetPagesToPrint().size() - 1;
+ OSL_ENSURE( 0 <= nRenderer && nRenderer <= nMaxRenderer, "nRenderer out of bounds");
+ if (!pOutDev || nMaxRenderer < 0 || nRenderer < 0 || nRenderer > nMaxRenderer)
+ return false;
+
+ // save settings of OutputDevice (should be done always since the
+ // output device is now provided by a call from outside the Writer)
+ pOutDev->Push();
+
+
+ const bool bHasPostItsToPrintInMargins(::sw::IsShrinkPageForPostIts(*this, rPrintData));
+ ::std::optional<tools::Long> oOrigHeight;
+
+ // Print/PDF export for (multi-)selection has already generated a
+ // temporary document with the selected text.
+ // (see XRenderable implementation in unotxdoc.cxx)
+ // It is implemented this way because PDF export calls this Prt function
+ // once per page and we do not like to always have the temporary document
+ // to be created that often here.
+ std::unique_ptr<SwViewShell> pShell(new SwViewShell(*this, nullptr, pOutDev));
+
+ SdrView *pDrawView = pShell->GetDrawView();
+ if (pDrawView)
+ {
+ pDrawView->SetBufferedOutputAllowed( false );
+ pDrawView->SetBufferedOverlayAllowed( false );
+ }
+
+ { // additional scope so that the CurrShell is reset before destroying the shell
+
+ CurrShell aCurr( pShell.get() );
+
+ //JP 01.02.99: Bug 61335 - the ReadOnly flag is never copied
+ if( mpOpt->IsReadonly() )
+ pShell->mpOpt->SetReadonly( true );
+
+ // save options at draw view:
+ SwDrawViewSave aDrawViewSave( pShell->GetDrawView() );
+ pShell->PrepareForPrint( rPrintData, bIsPDFExport );
+
+ const sal_Int32 nPage = rPrintData.GetRenderData().GetPagesToPrint()[ nRenderer ];
+ OSL_ENSURE( nPage < 0 ||
+ rPrintData.GetRenderData().GetValidPagesSet().count( nPage ) == 1,
+ "SwViewShell::PrintOrPDFExport: nPage not valid" );
+ SwViewShell *const pViewSh2 = (nPage < 0)
+ ? rPrintData.GetRenderData().m_pPostItShell.get()// post-it page
+ : pShell.get(); // a 'regular' page, not one from the post-it doc
+
+ SwPageFrame const*const pStPage =
+ sw_getPage(*pViewSh2->GetLayout(), abs(nPage));
+ OSL_ENSURE( pStPage, "failed to get start page" );
+ if (!pStPage)
+ {
+ return false;
+ }
+
+ //!! applying view options and formatting the document should now only be done in getRendererCount!
+
+ ::SetSwVisArea( pViewSh2, pStPage->getFrameArea() );
+
+ pShell->InitPrt(pOutDev);
+
+ ::SetSwVisArea( pViewSh2, pStPage->getFrameArea() );
+
+ pStPage->GetUpper()->PaintSwFrame( *pOutDev, pStPage->getFrameArea(), &rPrintData );
+
+ SwPaintQueue::Repaint();
+
+ SwPostItMgr *pPostItManager = bHasPostItsToPrintInMargins ? pShell->GetPostItMgr() : nullptr;
+
+ if (pPostItManager)
+ {
+ pPostItManager->CalcRects();
+ pPostItManager->LayoutPostIts();
+ pPostItManager->DrawNotesForPage(pOutDev, nPage-1);
+ oOrigHeight.emplace(pStPage->getFrameArea().Height());
+ }
+ }
+
+ pShell.reset();
+
+ // restore settings of OutputDevice (should be done always now since the
+ // output device is now provided by a call from outside the Writer)
+ pOutDev->Pop();
+
+ // avoid a warning about unbalanced Push/Pop by doing this last:
+ if (oOrigHeight)
+ {
+ // fdo#36815 Now scale the recorded page down so the comments in
+ // margins will fit in the final page
+ double fScale = 0.75;
+ tools::Long nNewHeight = *oOrigHeight*fScale;
+ tools::Long nShiftY = (*oOrigHeight-nNewHeight)/2;
+ GDIMetaFile *const pMetaFile = pOutDev->GetConnectMetaFile();
+ pMetaFile->ScaleActions(fScale, fScale);
+ //Move the scaled page down to center it
+ //the other variant of Move does not map pixels
+ //back to the logical units correctly
+ pMetaFile->Move(0, convertTwipToMm100(nShiftY), pOutDev->GetDPIX(), pOutDev->GetDPIY());
+ }
+
+ return true;
+}
+
+void SwViewShell::PrtOle2( SwDoc *pDoc, const SwViewOption *pOpt, const SwPrintData& rOptions,
+ vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect,
+ bool bOutputForScreen )
+{
+ // For printing a shell is needed. Either the Doc already has one, then we
+ // create a new view, or it has none, then we create the first view.
+ std::unique_ptr<SwViewShell> pSh;
+ if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() )
+ pSh.reset(new SwViewShell( *pDoc->getIDocumentLayoutAccess().GetCurrentViewShell(), nullptr, &rRenderContext,VSHELLFLAG_SHARELAYOUT ));
+ else
+ pSh.reset(new SwViewShell( *pDoc, nullptr, pOpt, &rRenderContext));
+
+ pSh->setOutputToWindow(bOutputForScreen);
+
+ {
+ CurrShell aCurr( pSh.get() );
+ pSh->PrepareForPrint( rOptions );
+ pSh->SetPrtFormatOption( true );
+
+ SwRect aSwRect( rRect );
+ pSh->maVisArea = aSwRect;
+
+ if ( pSh->GetViewOptions()->getBrowseMode() &&
+ pSh->GetRingContainer().size() == 1 )
+ {
+ pSh->InvalidateLayout( false );
+ pSh->GetLayout()->Lower()->InvalidateSize();
+ }
+
+ // CalcPagesForPrint() should not be necessary here. The pages in the
+ // visible area will be formatted in SwRootFrame::PaintSwFrame().
+ // Removing this gives us a performance gain during saving the
+ // document because the thumbnail creation will not trigger a complete
+ // formatting of the document.
+
+ rRenderContext.Push( vcl::PushFlags::CLIPREGION );
+ rRenderContext.IntersectClipRegion( aSwRect.SVRect() );
+ pSh->GetLayout()->PaintSwFrame( rRenderContext, aSwRect );
+
+ rRenderContext.Pop();
+ // first the CurrShell object needs to be destroyed!
+ }
+}
+
+/// Check if the DocNodesArray contains fields.
+bool SwViewShell::IsAnyFieldInDoc() const
+{
+ for (const SfxPoolItem* pItem : mxDoc->GetAttrPool().GetItemSurrogates(RES_TXTATR_FIELD))
+ {
+ auto pFormatField = dynamic_cast<const SwFormatField*>(pItem);
+ if(pFormatField)
+ {
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ if( pTextField && pTextField->GetTextNode().GetNodes().IsDocNodes() )
+ {
+ return true;
+ }
+ }
+ }
+
+ for (const SfxPoolItem* pItem : mxDoc->GetAttrPool().GetItemSurrogates(RES_TXTATR_INPUTFIELD))
+ {
+ const SwFormatField* pFormatField = dynamic_cast<const SwFormatField*>(pItem);
+ if(pFormatField)
+ {
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ if( pTextField && pTextField->GetTextNode().GetNodes().IsDocNodes() )
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/// Saves some settings at the draw view
+SwDrawViewSave::SwDrawViewSave( SdrView* pSdrView )
+ : pDV( pSdrView )
+ , bPrintControls(true)
+{
+ if ( pDV )
+ {
+ bPrintControls = pDV->IsLayerPrintable( "Controls" );
+ }
+}
+
+SwDrawViewSave::~SwDrawViewSave()
+{
+ if ( pDV )
+ {
+ pDV->SetLayerPrintable( "Controls", bPrintControls );
+ }
+}
+
+// OD 09.01.2003 #i6467# - method also called for page preview
+void SwViewShell::PrepareForPrint( const SwPrintData &rOptions, bool bIsPDFExport )
+ {
+ mpOpt->SetGraphic ( rOptions.m_bPrintGraphic );
+ mpOpt->SetTable ( rOptions.m_bPrintTable );
+ mpOpt->SetDraw ( rOptions.m_bPrintDraw );
+ mpOpt->SetControl ( rOptions.m_bPrintControl );
+ mpOpt->SetPageBack ( rOptions.m_bPrintPageBackground );
+ // Font should not be black if it's a PDF Export
+ mpOpt->SetBlackFont( rOptions.m_bPrintBlackFont && !bIsPDFExport );
+
+ if ( !HasDrawView() )
+ return;
+
+ SdrView *pDrawView = GetDrawView();
+ // OD 09.01.2003 #i6467# - consider, if view shell belongs to page preview
+ if ( !IsPreview() )
+ {
+ pDrawView->SetLayerPrintable( "Controls", rOptions.m_bPrintControl );
+ }
+ else
+ {
+ pDrawView->SetLayerVisible( "Controls", rOptions.m_bPrintControl );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */