Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / view / viewsh.cxx
blob20cd26c17fb3687e28c82d155df1ad0013b968ac
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <officecfg/Office/Common.hxx>
21 #include <config_wasm_strip.h>
23 #include <com/sun/star/accessibility/XAccessible.hpp>
24 #include <sfx2/viewfrm.hxx>
25 #include <sfx2/progress.hxx>
26 #include <svx/srchdlg.hxx>
27 #include <sfx2/viewsh.hxx>
28 #include <sfx2/ipclient.hxx>
29 #include <sal/log.hxx>
30 #include <drawdoc.hxx>
31 #include <swwait.hxx>
32 #include <crsrsh.hxx>
33 #include <doc.hxx>
34 #include <IDocumentDeviceAccess.hxx>
35 #include <IDocumentDrawModelAccess.hxx>
36 #include <IDocumentOutlineNodes.hxx>
37 #include <IDocumentFieldsAccess.hxx>
38 #include <IDocumentLayoutAccess.hxx>
39 #include <IDocumentState.hxx>
40 #include <rootfrm.hxx>
41 #include <pagefrm.hxx>
42 #include <viewimp.hxx>
43 #include <frmtool.hxx>
44 #include <viewopt.hxx>
45 #include <dview.hxx>
46 #include <swregion.hxx>
47 #include <hints.hxx>
48 #include <docufld.hxx>
49 #include <txtfrm.hxx>
50 #include <layact.hxx>
51 #include <mdiexp.hxx>
52 #include <fntcache.hxx>
53 #include <ptqueue.hxx>
54 #include <docsh.hxx>
55 #include <bookmark.hxx>
56 #include <ndole.hxx>
57 #include <ndindex.hxx>
58 #include <accmap.hxx>
59 #include <vcl/bitmapex.hxx>
60 #include <svtools/accessibilityoptions.hxx>
61 #include <accessibilityoptions.hxx>
62 #include <strings.hrc>
63 #include <bitmaps.hlst>
64 #include <pagepreviewlayout.hxx>
65 #include <sortedobjs.hxx>
66 #include <anchoredobject.hxx>
67 #include <DocumentSettingManager.hxx>
68 #include <DocumentRedlineManager.hxx>
69 #include <DocumentLayoutManager.hxx>
71 #include <unotxdoc.hxx>
72 #include <view.hxx>
73 #include <PostItMgr.hxx>
74 #include <unotools/configmgr.hxx>
75 #include <vcl/virdev.hxx>
76 #include <vcl/svapp.hxx>
77 #include <svx/sdrpaintwindow.hxx>
78 #include <svx/sdrpagewindow.hxx>
79 #include <svx/svdpagv.hxx>
80 #include <comphelper/lok.hxx>
81 #include <sfx2/lokhelper.hxx>
82 #include <tools/UnitConversion.hxx>
84 #if !HAVE_FEATURE_DESKTOP
85 #include <vcl/sysdata.hxx>
86 #endif
88 #include <frameformats.hxx>
89 #include <fmtcntnt.hxx>
91 bool SwViewShell::sbLstAct = false;
92 ShellResource *SwViewShell::spShellRes = nullptr;
93 vcl::DeleteOnDeinit<std::shared_ptr<weld::Window>> SwViewShell::spCareDialog {};
95 static bool bInSizeNotify = false;
98 using namespace ::com::sun::star;
100 void SwViewShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow ) {
102 //tdf#118621 - Optionally disable floating header/footer menu
103 if ( bShow )
104 bShow = GetViewOptions()->IsUseHeaderFooterMenu();
106 if ( eControl == FrameControlType::Header )
107 mbShowHeaderSeparator = bShow;
108 else
109 mbShowFooterSeparator = bShow;
112 void SwViewShell::ToggleHeaderFooterEdit()
114 mbHeaderFooterEdit = !mbHeaderFooterEdit;
115 if ( !mbHeaderFooterEdit )
117 SetShowHeaderFooterSeparator( FrameControlType::Header, false );
118 SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
121 // Avoid corner case
122 if ( ( GetViewOptions()->IsUseHeaderFooterMenu() ) &&
123 ( !IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
124 !IsShowHeaderFooterSeparator( FrameControlType::Footer ) ) )
126 mbHeaderFooterEdit = false;
129 // Repaint everything
130 GetWin()->Invalidate();
133 void SwViewShell::setOutputToWindow(bool bOutputToWindow)
135 mbOutputToWindow = bOutputToWindow;
138 bool SwViewShell::isOutputToWindow() const
140 return mbOutputToWindow;
143 void SwViewShell::dumpAsXml(xmlTextWriterPtr pWriter) const
145 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwViewShell"));
146 (void)xmlTextWriterEndElement(pWriter);
149 static void
150 lcl_PaintTransparentFormControls(SwViewShell const & rShell, SwRect const& rRect)
152 // Direct paint has been performed: the background of transparent child
153 // windows has been painted, so need to paint the child windows now.
154 if (rShell.GetWin())
156 vcl::Window& rWindow = *(rShell.GetWin());
157 const tools::Rectangle aRectanglePixel(rShell.GetOut()->LogicToPixel(rRect.SVRect()));
158 PaintTransparentChildren(rWindow, aRectanglePixel);
162 // #i72754# 2nd set of Pre/PostPaints
163 // This time it uses the lock counter (mPrePostPaintRegions empty/non-empty) to allow only one activation
164 // and deactivation and mpPrePostOutDev to remember the OutDev from the BeginDrawLayers
165 // call. That way, all places where paint take place can be handled the same way, even
166 // when calling other paint methods. This is the case at the places where SW paints
167 // buffered into VDevs to avoid flicker. It is in general problematic and should be
168 // solved once using the BufferedOutput functionality of the DrawView.
170 void SwViewShell::PrePaint()
172 // forward PrePaint event from VCL Window to DrawingLayer
173 if(HasDrawView())
175 Imp()->GetDrawView()->PrePaint();
179 void SwViewShell::DLPrePaint2(const vcl::Region& rRegion)
181 if(mPrePostPaintRegions.empty())
183 mPrePostPaintRegions.push( rRegion );
184 // #i75172# ensure DrawView to use DrawingLayer bufferings
185 if ( !HasDrawView() )
186 MakeDrawView();
188 // Prefer window; if not available, get mpOut (e.g. printer)
189 const bool bWindow = GetWin() && !comphelper::LibreOfficeKit::isActive() && !isOutputToWindow();
190 mpPrePostOutDev = bWindow ? GetWin()->GetOutDev() : GetOut();
192 // #i74769# use SdrPaintWindow now direct
193 mpTargetPaintWindow = Imp()->GetDrawView()->BeginDrawLayers(mpPrePostOutDev, rRegion);
194 OSL_ENSURE(mpTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
196 // #i74769# if prerender, save OutDev and redirect to PreRenderDevice
197 if(mpTargetPaintWindow->GetPreRenderDevice())
199 mpBufferedOut = mpOut;
200 mpOut = &(mpTargetPaintWindow->GetTargetOutputDevice());
202 else if (isOutputToWindow())
203 // In case mpOut is used without buffering and we're not printing, need to set clipping.
204 mpOut->SetClipRegion(rRegion);
206 // remember original paint MapMode for wrapped FlyFrame paints
207 maPrePostMapMode = mpOut->GetMapMode();
209 else
211 // region needs to be updated to the given one
212 if( mPrePostPaintRegions.top() != rRegion )
213 Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, rRegion);
214 mPrePostPaintRegions.push( rRegion );
218 void SwViewShell::DLPostPaint2(bool bPaintFormLayer)
220 OSL_ENSURE(!mPrePostPaintRegions.empty(), "SwViewShell::DLPostPaint2: Pre/PostPaint encapsulation broken (!)");
222 if( mPrePostPaintRegions.size() > 1 )
224 vcl::Region current = std::move(mPrePostPaintRegions.top());
225 mPrePostPaintRegions.pop();
226 if( current != mPrePostPaintRegions.top())
227 Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, mPrePostPaintRegions.top());
228 return;
230 mPrePostPaintRegions.pop(); // clear
231 if(nullptr != mpTargetPaintWindow)
233 // #i74769# restore buffered OutDev
234 if(mpTargetPaintWindow->GetPreRenderDevice())
236 mpOut = mpBufferedOut;
239 // #i74769# use SdrPaintWindow now direct
240 Imp()->GetDrawView()->EndDrawLayers(*mpTargetPaintWindow, bPaintFormLayer);
241 mpTargetPaintWindow = nullptr;
244 // end of Pre/PostPaints
246 void SwViewShell::ImplEndAction( const bool bIdleEnd )
248 // Nothing to do for the printer?
249 if ( !GetWin() || IsPreview() )
251 mbPaintWorks = true;
252 UISizeNotify();
253 // tdf#101464 print preview may generate events if another view shell
254 // performs layout...
255 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
256 if (IsPreview() && Imp()->IsAccessible())
258 Imp()->FireAccessibleEvents();
260 #endif
261 return;
264 mbInEndAction = true;
265 //will this put the EndAction of the last shell in the sequence?
267 SwViewShell::sbLstAct = true;
268 for(SwViewShell& rShell : GetRingContainer())
270 if(&rShell != this && rShell.ActionPend())
272 SwViewShell::sbLstAct = false;
273 break;
277 const bool bIsShellForCheckViewLayout = ( this == GetLayout()->GetCurrShell() );
279 CurrShell aCurr( this );
280 if ( Imp()->HasDrawView() && !Imp()->GetDrawView()->areMarkHandlesHidden() )
281 Imp()->StartAction();
283 if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
284 Imp()->DeletePaintRegion();
286 const bool bExtraData = ::IsExtraData( GetDoc() );
288 if ( !bIdleEnd )
290 SwLayAction aAction( GetLayout(), Imp() );
291 aAction.SetComplete( false );
292 if ( mnLockPaint )
293 aAction.SetPaint( false );
294 aAction.SetInputType( VclInputFlags::KEYBOARD );
295 aAction.Action(GetWin()->GetOutDev());
298 if ( bIsShellForCheckViewLayout )
299 GetLayout()->CheckViewLayout( GetViewOptions(), &maVisArea );
301 //If we don't call Paints, we wait for the Paint of the system.
302 //Then the clipping is set correctly; e.g. shifting of a Draw object
303 if ( Imp()->HasPaintRegion() ||
304 maInvalidRect.HasArea() ||
305 bExtraData )
307 if ( !mnLockPaint )
309 SolarMutexGuard aGuard;
311 bool bPaintsFromSystem = maInvalidRect.HasArea();
312 GetWin()->PaintImmediately();
313 if ( maInvalidRect.HasArea() )
315 if ( bPaintsFromSystem )
316 Imp()->AddPaintRect( maInvalidRect );
318 ResetInvalidRect();
319 bPaintsFromSystem = true;
321 mbPaintWorks = true;
323 std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();
325 //JP 27.11.97: what hid the selection, must also Show it,
326 // else we get Paint errors!
327 // e.g. additional mode, page half visible vertically, in the
328 // middle a selection and with another cursor jump to left
329 // right border. Without ShowCursor the selection disappears.
330 bool bShowCursor = oRegion && dynamic_cast<const SwCursorShell*>(this) != nullptr;
331 if( bShowCursor )
332 static_cast<SwCursorShell*>(this)->HideCursors();
334 if ( oRegion )
336 SwRootFrame* pCurrentLayout = GetLayout();
338 oRegion->LimitToOrigin();
339 oRegion->Compress( SwRegionRects::CompressFuzzy );
341 while ( !oRegion->empty() )
343 SwRect aRect( oRegion->back() );
344 oRegion->pop_back();
346 if (GetWin()->SupportsDoubleBuffering())
347 InvalidateWindows(aRect);
348 else
350 // #i75172# begin DrawingLayer paint
351 // need to do begin/end DrawingLayer preparation for each single rectangle of the
352 // repaint region. I already tried to prepare only once for the whole Region. This
353 // seems to work (and does technically) but fails with transparent objects. Since the
354 // region given to BeginDrawLayers() defines the clip region for DrawingLayer paint,
355 // transparent objects in the single rectangles will indeed be painted multiple times.
356 if (!comphelper::LibreOfficeKit::isActive())
358 DLPrePaint2(vcl::Region(aRect.SVRect()));
361 if ( bPaintsFromSystem )
362 PaintDesktop(*GetOut(), aRect);
363 if (!comphelper::LibreOfficeKit::isActive())
364 pCurrentLayout->PaintSwFrame( *mpOut, aRect );
365 else
366 pCurrentLayout->GetCurrShell()->InvalidateWindows(aRect);
368 // #i75172# end DrawingLayer paint
369 if (!comphelper::LibreOfficeKit::isActive())
371 DLPostPaint2(true);
375 lcl_PaintTransparentFormControls(*this, aRect); // i#107365
378 if( bShowCursor )
379 static_cast<SwCursorShell*>(this)->ShowCursors( true );
381 else
383 Imp()->DeletePaintRegion();
384 mbPaintWorks = true;
387 else
388 mbPaintWorks = true;
390 mbInEndAction = false;
391 SwViewShell::sbLstAct = false;
392 Imp()->EndAction();
394 //We artificially end the action here to enable the automatic scrollbars
395 //to adjust themselves correctly
396 //EndAction sends a Notify, and that must call Start-/EndAction to
397 //adjust the scrollbars correctly
398 --mnStartAction;
399 UISizeNotify();
400 ++mnStartAction;
402 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
403 if( Imp()->IsAccessible() )
404 Imp()->FireAccessibleEvents();
405 #endif
408 void SwViewShell::ImplStartAction()
410 mbPaintWorks = false;
411 Imp()->StartAction();
414 void SwViewShell::ImplLockPaint()
416 if ( GetWin() && GetWin()->IsVisible() && !comphelper::LibreOfficeKit::isActive())
417 GetWin()->EnablePaint( false ); //Also cut off the controls.
418 Imp()->LockPaint();
421 void SwViewShell::ImplUnlockPaint(std::vector<LockPaintReason>& rReasons, bool bVirDev)
423 CurrShell aCurr( this );
424 if ( GetWin() && GetWin()->IsVisible() )
426 if ( (bInSizeNotify || bVirDev ) && VisArea().HasArea() && !comphelper::LibreOfficeKit::isActive())
428 //Refresh with virtual device to avoid flickering.
429 VclPtrInstance<VirtualDevice> pVout( *mpOut );
430 pVout->SetMapMode( mpOut->GetMapMode() );
431 Size aSize( VisArea().SSize() );
432 aSize.AdjustWidth(20 );
433 aSize.AdjustHeight(20 );
434 if( pVout->SetOutputSize( aSize ) )
436 GetWin()->EnablePaint( true );
437 GetWin()->Validate();
439 Imp()->UnlockPaint();
440 pVout->SetLineColor( mpOut->GetLineColor() );
441 pVout->SetFillColor( mpOut->GetFillColor() );
443 // #i72754# start Pre/PostPaint encapsulation before mpOut is changed to the buffering VDev
444 const vcl::Region aRepaintRegion(VisArea().SVRect());
445 DLPrePaint2(aRepaintRegion);
447 OutputDevice *pOld = mpOut;
448 mpOut = pVout.get();
449 Paint(*mpOut, VisArea().SVRect());
450 mpOut = pOld;
451 mpOut->DrawOutDev( VisArea().Pos(), aSize,
452 VisArea().Pos(), aSize, *pVout );
454 // #i72754# end Pre/PostPaint encapsulation when mpOut is back and content is painted
455 DLPostPaint2(true);
457 lcl_PaintTransparentFormControls(*this, VisArea()); // fdo#63949
459 else
461 Imp()->UnlockPaint();
462 GetWin()->EnablePaint( true );
463 InvalidateAll(rReasons);
465 pVout.disposeAndClear();
467 else
469 Imp()->UnlockPaint();
470 GetWin()->EnablePaint( true );
471 InvalidateAll(rReasons);
474 else
475 Imp()->UnlockPaint();
478 namespace
480 std::string_view to_string(LockPaintReason eReason)
482 switch(eReason)
484 case LockPaintReason::ViewLayout:
485 return "ViewLayout";
486 case LockPaintReason::OuterResize:
487 return "OuterResize";
488 case LockPaintReason::Undo:
489 return "Undo";
490 case LockPaintReason::Redo:
491 return "Redo";
492 case LockPaintReason::OutlineFolding:
493 return "OutlineFolding";
494 case LockPaintReason::EndSdrCreate:
495 return "EndSdrCreate";
496 case LockPaintReason::SwLayIdle:
497 return "SwLayIdle";
498 case LockPaintReason::InvalidateLayout:
499 return "InvalidateLayout";
500 case LockPaintReason::StartDrag:
501 return "StartDrag";
502 case LockPaintReason::DataChanged:
503 return "DataChanged";
504 case LockPaintReason::InsertFrame:
505 return "InsertFrame";
506 case LockPaintReason::GotoPage:
507 return "GotoPage";
508 case LockPaintReason::InsertGraphic:
509 return "InsertGraphic";
510 case LockPaintReason::SetZoom:
511 return "SetZoom";
512 case LockPaintReason::ExampleFrame:
513 return "ExampleFram";
515 return "";
519 void SwViewShell::InvalidateAll(std::vector<LockPaintReason>& rReasons)
521 assert(!rReasons.empty() && "there must be a reason to InvalidateAll");
523 for (const auto& reason : rReasons)
524 SAL_INFO("sw.core", "InvalidateAll because of: " << to_string(reason));
526 if (comphelper::LibreOfficeKit::isActive())
528 // https://github.com/CollaboraOnline/online/issues/6379
529 // ditch OuterResize as a reason to invalidate all in the online case
530 rReasons.erase(std::remove(rReasons.begin(), rReasons.end(), LockPaintReason::OuterResize), rReasons.end());
533 if (!rReasons.empty())
534 GetWin()->Invalidate(InvalidateFlags::Children);
535 rReasons.clear();
538 bool SwViewShell::AddPaintRect( const SwRect & rRect )
540 bool bRet = false;
541 for(SwViewShell& rSh : GetRingContainer())
543 if( rSh.Imp() )
545 if ( rSh.IsPreview() && rSh.GetWin() )
546 ::RepaintPagePreview( &rSh, rRect );
547 else
548 bRet |= rSh.Imp()->AddPaintRect( rRect );
551 return bRet;
554 void SwViewShell::InvalidateWindows( const SwRect &rRect )
556 if ( Imp()->IsCalcLayoutProgress() )
557 return;
559 if(comphelper::LibreOfficeKit::isActive())
561 // If we are inside tiled painting, invalidations are ignored.
562 // Ignore them right now to save work, but also to avoid the problem
563 // that this state could be reset before FlushPendingLOKInvalidateTiles()
564 // gets called.
565 if(comphelper::LibreOfficeKit::isTiledPainting())
566 return;
567 // First collect all invalidations and perform them only later,
568 // otherwise the number of Invalidate() calls would be at least
569 // O(n^2) if not worse. The problem is that if any change in a document
570 // is made, SwEditShell::EndAllAction() is called, which calls EndAction()
571 // for every view. And every view does it own handling of paint rectangles,
572 // and then calls InvalidateWindows() based on that. On then this code
573 // would call Invalidate() for all views for each rectangle.
574 // So collect the rectangles, avoid duplicates (which there usually will
575 // be many because of the repetitions), FlushPendingLOKInvalidateTiles()
576 // will collect all rectangles from all related views, compress them
577 // and only with those relatively few rectangle it'd call Invalidate()
578 // for all views.
579 Imp()->AddPendingLOKInvalidation(rRect);
580 return;
583 for(SwViewShell& rSh : GetRingContainer())
585 if ( rSh.GetWin() )
587 if ( rSh.IsPreview() )
588 ::RepaintPagePreview( &rSh, rRect );
589 // In case of tiled rendering, invalidation is wanted even if
590 // the rectangle is outside the visual area.
591 else if ( rSh.VisArea().Overlaps( rRect ) || comphelper::LibreOfficeKit::isActive() )
592 rSh.GetWin()->Invalidate( rRect.SVRect() );
597 void SwViewShell::FlushPendingLOKInvalidateTiles()
599 assert(comphelper::LibreOfficeKit::isActive());
600 SwRegionRects rects;
601 for(SwViewShell& rSh : GetRingContainer())
603 std::vector<SwRect> tmpRects = rSh.Imp()->TakePendingLOKInvalidations();
604 rects.insert( rects.end(), tmpRects.begin(), tmpRects.end());
606 rects.Compress( SwRegionRects::CompressFuzzy );
607 if(rects.empty())
608 return;
609 // This is basically the loop from SwViewShell::InvalidateWindows().
610 for(SwViewShell& rSh : GetRingContainer())
612 if ( rSh.GetWin() )
614 if ( rSh.IsPreview() )
616 for( const SwRect& rect : rects )
617 ::RepaintPagePreview( &rSh, rect );
619 else
621 for( const SwRect& rect : rects )
622 rSh.GetWin()->Invalidate( rect.SVRect() );
628 const SwRect& SwViewShell::VisArea() const
630 // when using the tiled rendering, consider the entire document as our
631 // visible area
632 return comphelper::LibreOfficeKit::isActive()? GetLayout()->getFrameArea(): maVisArea;
635 void SwViewShell::MakeVisible( const SwRect &rRect )
637 if ( !(!VisArea().Contains( rRect ) || IsScrollMDI( this, rRect ) || GetCareDialog(*this)) )
638 return;
640 if ( IsViewLocked() )
641 return;
643 if( mpWin )
645 const SwFrame* pRoot = GetLayout();
646 int nLoopCnt = 3;
647 tools::Long nOldH;
649 nOldH = pRoot->getFrameArea().Height();
650 StartAction();
651 ScrollMDI( this, rRect, USHRT_MAX, USHRT_MAX );
652 EndAction();
653 } while( nOldH != pRoot->getFrameArea().Height() && nLoopCnt-- );
655 #if OSL_DEBUG_LEVEL > 0
656 else
658 //MA: 04. Nov. 94, no one needs this, does one?
659 OSL_ENSURE( false, "Is MakeVisible still needed for printers?" );
662 #endif
665 weld::Window* SwViewShell::CareChildWin(SwViewShell const & rVSh)
667 if (!rVSh.mpSfxViewShell)
668 return nullptr;
669 #if HAVE_FEATURE_DESKTOP
670 const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId();
671 SfxViewFrame& rVFrame = rVSh.mpSfxViewShell->GetViewFrame();
672 SfxChildWindow* pChWin = rVFrame.GetChildWindow( nId );
673 if (!pChWin)
674 return nullptr;
675 weld::DialogController* pController = pChWin->GetController().get();
676 if (!pController)
677 return nullptr;
678 weld::Window* pWin = pController->getDialog();
679 if (pWin && pWin->get_visible())
680 return pWin;
681 #endif
682 return nullptr;
685 Point SwViewShell::GetPagePos( sal_uInt16 nPageNum ) const
687 return GetLayout()->GetPagePos( nPageNum );
690 sal_uInt16 SwViewShell::GetNumPages() const
692 //It is possible that no layout exists when the method from
693 //root-Ctor is called.
694 return GetLayout() ? GetLayout()->GetPageNum() : 0;
697 bool SwViewShell::IsDummyPage( sal_uInt16 nPageNum ) const
699 return GetLayout() && GetLayout()->IsDummyPage( nPageNum );
703 * Forces update of each field.
704 * It notifies all fields with pNewHt. If that is 0 (default), the field
705 * type is sent (???).
706 * @param[in] bCloseDB Passed in to GetDoc()->UpdateFields. [TODO] Purpose???
708 void SwViewShell::UpdateFields(bool bCloseDB)
710 CurrShell aCurr( this );
712 auto pCursorShell = dynamic_cast<SwCursorShell*>( this );
713 if ( pCursorShell )
714 pCursorShell->StartAction();
715 else
716 StartAction();
718 GetDoc()->getIDocumentFieldsAccess().UpdateFields(bCloseDB);
720 if ( pCursorShell )
721 pCursorShell->EndAction();
722 else
723 EndAction();
726 void SwViewShell::UpdateOleObjectPreviews()
728 SwDoc* pDoc = GetDoc();
729 for(sw::SpzFrameFormat* pFormat: *pDoc->GetSpzFrameFormats())
731 if (pFormat->Which() != RES_FLYFRMFMT)
733 continue;
736 const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
737 if (!pNodeIndex || !pNodeIndex->GetNodes().IsDocNodes())
739 continue;
742 SwNode* pNode = pDoc->GetNodes()[pNodeIndex->GetIndex() + 1];
743 SwOLENode* pOleNode = pNode->GetOLENode();
744 if (!pOleNode)
746 continue;
749 SwOLEObj& rOleObj = pOleNode->GetOLEObj();
750 svt::EmbeddedObjectRef& rObject = rOleObj.GetObject();
751 rObject.UpdateReplacement( true );
752 // Trigger the repaint.
753 pOleNode->SetChanged();
757 /** update all charts for which any table exists */
758 void SwViewShell::UpdateAllCharts()
760 CurrShell aCurr( this );
761 // Start-/EndAction handled in the SwDoc-Method!
762 GetDoc()->UpdateAllCharts();
765 bool SwViewShell::HasCharts() const
767 bool bRet = false;
768 SwNodeIndex aIdx( *GetDoc()->GetNodes().GetEndOfAutotext().
769 StartOfSectionNode(), 1 );
770 while (aIdx.GetNode().GetStartNode())
772 ++aIdx;
773 const SwOLENode *pNd = aIdx.GetNode().GetOLENode();
774 if( pNd && !pNd->GetChartTableName().isEmpty() )
776 bRet = true;
777 break;
780 return bRet;
783 void SwViewShell::LayoutIdle()
785 if( !mpOpt->IsIdle() || !GetWin() || HasDrawViewDrag() )
786 return;
788 //No idle when printing is going on.
789 for(const SwViewShell& rSh : GetRingContainer())
791 if ( !rSh.GetWin() )
792 return;
795 CurrShell aCurr( this );
797 #ifdef DBG_UTIL
798 // If Test5 has been set, the IdleFormatter is disabled.
799 if( mpOpt->IsTest5() )
800 return;
801 #endif
804 // Preserve top of the text frame cache.
805 SwSaveSetLRUOfst aSaveLRU;
806 // #125243# there are lots of stacktraces indicating that Imp() returns NULL
807 // this SwViewShell seems to be invalid - but it's not clear why
808 // this return is only a workaround!
809 OSL_ENSURE(Imp(), "SwViewShell already deleted?");
810 if(!Imp())
811 return;
812 SwLayIdle aIdle( GetLayout(), Imp() );
816 static void lcl_InvalidateAllContent( SwViewShell& rSh, SwInvalidateFlags nInv )
818 auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh);
819 if ( pCursorShell )
820 pCursorShell->StartAction();
821 else
822 rSh.StartAction();
823 rSh.GetLayout()->InvalidateAllContent( nInv );
824 if ( pCursorShell )
825 pCursorShell->EndAction();
826 else
827 rSh.EndAction();
829 rSh.GetDoc()->getIDocumentState().SetModified();
832 /** local method to invalidate/re-calculate positions of floating screen
833 * objects (Writer fly frame and drawing objects), which are anchored
834 * to paragraph or to character. #i11860#
836 static void lcl_InvalidateAllObjPos( SwViewShell &_rSh )
838 auto pCursorShell = dynamic_cast<SwCursorShell*>( &_rSh);
839 if ( pCursorShell )
840 pCursorShell->StartAction();
841 else
842 _rSh.StartAction();
844 _rSh.GetLayout()->InvalidateAllObjPos();
846 if ( pCursorShell )
847 pCursorShell->EndAction();
848 else
849 _rSh.EndAction();
851 _rSh.GetDoc()->getIDocumentState().SetModified();
854 void SwViewShell::SetParaSpaceMax( bool bNew )
856 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
857 if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) != bNew )
859 SwWait aWait( *GetDoc()->GetDocShell(), true );
860 rIDSA.set(DocumentSettingId::PARA_SPACE_MAX, bNew );
861 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
862 lcl_InvalidateAllContent( *this, nInv );
866 void SwViewShell::SetParaSpaceMaxAtPages( bool bNew )
868 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
869 if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) != bNew )
871 SwWait aWait( *GetDoc()->GetDocShell(), true );
872 rIDSA.set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, bNew );
873 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
874 lcl_InvalidateAllContent( *this, nInv );
878 void SwViewShell::SetTabCompat( bool bNew )
880 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
881 if( rIDSA.get(DocumentSettingId::TAB_COMPAT) != bNew )
883 SwWait aWait( *GetDoc()->GetDocShell(), true );
884 rIDSA.set(DocumentSettingId::TAB_COMPAT, bNew );
885 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
886 lcl_InvalidateAllContent( *this, nInv );
890 void SwViewShell::SetAddExtLeading( bool bNew )
892 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
893 if ( rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) != bNew )
895 SwWait aWait( *GetDoc()->GetDocShell(), true );
896 rIDSA.set(DocumentSettingId::ADD_EXT_LEADING, bNew );
897 SwDrawModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
898 if ( pTmpDrawModel )
899 pTmpDrawModel->SetAddExtLeading( bNew );
900 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
901 lcl_InvalidateAllContent( *this, nInv );
905 /** Sets if paragraph and table spacing is added at bottom of table cells.
906 * #106629#
907 * @param[in] (bool) setting of the new value
909 void SwViewShell::SetAddParaSpacingToTableCells( bool _bAddParaSpacingToTableCells )
911 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
912 if (rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells
913 || rIDSA.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells)
915 SwWait aWait( *GetDoc()->GetDocShell(), true );
916 rIDSA.set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
917 // note: the dialog can't change the value to indeterminate, so only false/false and true/true
918 rIDSA.set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
919 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
920 lcl_InvalidateAllContent( *this, nInv );
925 * Sets if former formatting of text lines with proportional line spacing should used.
926 * #i11859#
927 * @param[in] (bool) setting of the new value
929 void SwViewShell::SetUseFormerLineSpacing( bool _bUseFormerLineSpacing )
931 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
932 if ( rIDSA.get(DocumentSettingId::OLD_LINE_SPACING) != _bUseFormerLineSpacing )
934 SwWait aWait( *GetDoc()->GetDocShell(), true );
935 rIDSA.set(DocumentSettingId::OLD_LINE_SPACING, _bUseFormerLineSpacing );
936 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
937 lcl_InvalidateAllContent( *this, nInv );
942 * Sets IDocumentSettingAccess if former object positioning should be used.
943 * #i11860#
944 * @param[in] (bool) setting the new value
946 void SwViewShell::SetUseFormerObjectPositioning( bool _bUseFormerObjPos )
948 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
949 if ( rIDSA.get(DocumentSettingId::USE_FORMER_OBJECT_POS) != _bUseFormerObjPos )
951 SwWait aWait( *GetDoc()->GetDocShell(), true );
952 rIDSA.set(DocumentSettingId::USE_FORMER_OBJECT_POS, _bUseFormerObjPos );
953 lcl_InvalidateAllObjPos( *this );
957 // #i28701#
958 void SwViewShell::SetConsiderWrapOnObjPos( bool _bConsiderWrapOnObjPos )
960 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
961 if ( rIDSA.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) != _bConsiderWrapOnObjPos )
963 SwWait aWait( *GetDoc()->GetDocShell(), true );
964 rIDSA.set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, _bConsiderWrapOnObjPos );
965 lcl_InvalidateAllObjPos( *this );
969 void SwViewShell::SetUseFormerTextWrapping( bool _bUseFormerTextWrapping )
971 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
972 if ( rIDSA.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) != _bUseFormerTextWrapping )
974 SwWait aWait( *GetDoc()->GetDocShell(), true );
975 rIDSA.set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, _bUseFormerTextWrapping );
976 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
977 lcl_InvalidateAllContent( *this, nInv );
981 // #i45491#
982 void SwViewShell::SetDoNotJustifyLinesWithManualBreak( bool _bDoNotJustifyLinesWithManualBreak )
984 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
985 if ( rIDSA.get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK) != _bDoNotJustifyLinesWithManualBreak )
987 SwWait aWait( *GetDoc()->GetDocShell(), true );
988 rIDSA.set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, _bDoNotJustifyLinesWithManualBreak );
989 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
990 lcl_InvalidateAllContent( *this, nInv );
994 void SwViewShell::SetProtectForm( bool _bProtectForm )
996 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
997 rIDSA.set(DocumentSettingId::PROTECT_FORM, _bProtectForm );
1000 void SwViewShell::SetMsWordCompTrailingBlanks( bool _bMsWordCompTrailingBlanks )
1002 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1003 if (rIDSA.get(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS) != _bMsWordCompTrailingBlanks)
1005 SwWait aWait(*GetDoc()->GetDocShell(), true);
1006 rIDSA.set(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS, _bMsWordCompTrailingBlanks);
1007 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
1008 lcl_InvalidateAllContent(*this, nInv);
1012 void SwViewShell::SetSubtractFlysAnchoredAtFlys(bool bSubtractFlysAnchoredAtFlys)
1014 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1015 rIDSA.set(DocumentSettingId::SUBTRACT_FLYS, bSubtractFlysAnchoredAtFlys);
1018 void SwViewShell::SetEmptyDbFieldHidesPara(bool bEmptyDbFieldHidesPara)
1020 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1021 if (rIDSA.get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA) == bEmptyDbFieldHidesPara)
1022 return;
1024 SwWait aWait(*GetDoc()->GetDocShell(), true);
1025 rIDSA.set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, bEmptyDbFieldHidesPara);
1026 StartAction();
1027 GetDoc()->getIDocumentState().SetModified();
1028 for (auto const & pFieldType : *GetDoc()->getIDocumentFieldsAccess().GetFieldTypes())
1030 if(pFieldType->Which() == SwFieldIds::Database)
1031 pFieldType->UpdateFields();
1033 EndAction();
1036 void SwViewShell::Reformat()
1038 SwWait aWait( *GetDoc()->GetDocShell(), true );
1040 // we go for safe: get rid of the old font information,
1041 // when the printer resolution or zoom factor changes.
1042 // Init() and Reformat() are the safest locations.
1043 pFntCache->Flush( );
1045 if( GetLayout()->IsCallbackActionEnabled() )
1047 StartAction();
1048 GetLayout()->InvalidateAllContent( SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea );
1049 EndAction();
1053 void SwViewShell::ChgNumberDigits()
1055 SdrModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
1056 if ( pTmpDrawModel )
1057 pTmpDrawModel->ReformatAllTextObjects();
1058 Reformat();
1061 void SwViewShell::CalcLayout()
1063 // extremely likely to be a Bad Idea to call this without StartAction
1064 // (except the Page Preview apparently only has a non-subclassed ViewShell)
1065 assert((typeid(*this) == typeid(SwViewShell)) || mnStartAction);
1067 CurrShell aCurr( this );
1068 SwWait aWait( *GetDoc()->GetDocShell(), true );
1070 // Preserve top of the text frame cache.
1071 SwSaveSetLRUOfst aSaveLRU;
1073 //switch on Progress when none is running yet.
1074 const bool bEndProgress = SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) == nullptr;
1075 if ( bEndProgress )
1077 tools::Long nEndPage = GetLayout()->GetPageNum();
1078 nEndPage += nEndPage * 10 / 100;
1079 ::StartProgress( STR_STATSTR_REFORMAT, 0, nEndPage, GetDoc()->GetDocShell() );
1082 SwLayAction aAction( GetLayout(), Imp() );
1083 aAction.SetPaint( false );
1084 aAction.SetStatBar( true );
1085 aAction.SetCalcLayout( true );
1086 aAction.SetReschedule( true );
1087 GetDoc()->getIDocumentFieldsAccess().LockExpFields();
1088 aAction.Action(GetOut());
1089 GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
1091 //the SetNewFieldLst() on the Doc was cut off and must be fetched again
1092 //(see flowfrm.cxx, txtfld.cxx)
1093 if ( aAction.IsExpFields() )
1095 aAction.Reset();
1096 aAction.SetPaint( false );
1097 aAction.SetStatBar( true );
1098 aAction.SetReschedule( true );
1100 GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(0);
1101 GetDoc()->getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
1103 aAction.Action(GetOut());
1106 if ( VisArea().HasArea() )
1107 InvalidateWindows( VisArea() );
1108 if ( bEndProgress )
1109 ::EndProgress( GetDoc()->GetDocShell() );
1112 void SwViewShell::SetFirstVisPageInvalid()
1114 for(SwViewShell& rSh : GetRingContainer())
1116 if ( rSh.Imp() )
1117 rSh.Imp()->SetFirstVisPageInvalid();
1121 void SwViewShell::SizeChgNotify()
1123 if ( !mpWin )
1124 mbDocSizeChgd = true;
1125 else if( ActionPend() || Imp()->IsCalcLayoutProgress() || mbPaintInProgress )
1127 mbDocSizeChgd = true;
1129 if ( !Imp()->IsCalcLayoutProgress() && dynamic_cast<const SwCursorShell*>( this ) != nullptr )
1131 PageNumNotify(this);
1133 if (comphelper::LibreOfficeKit::isActive())
1135 Size aDocSize = GetDocSize();
1136 OString sPayload = OString::number(aDocSize.Width() + 2 * DOCUMENTBORDER) +
1137 ", " + OString::number(aDocSize.Height() + 2 * DOCUMENTBORDER);
1139 SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(GetSfxViewShell()->GetCurrentDocument());
1140 SfxLokHelper::notifyDocumentSizeChanged(GetSfxViewShell(), sPayload, pModel);
1144 else
1146 mbDocSizeChgd = false;
1147 ::SizeNotify( this, GetDocSize() );
1151 void SwViewShell::VisPortChgd( const SwRect &rRect)
1153 OSL_ENSURE( GetWin(), "VisPortChgd without Window." );
1155 if ( rRect == VisArea() )
1156 return;
1158 // Is someone spuriously rescheduling again?
1159 SAL_WARN_IF(mbInEndAction, "sw.core", "Scrolling during EndAction");
1161 //First get the old visible page, so we don't have to look
1162 //for it afterwards.
1163 const SwFrame *pOldPage = Imp()->GetFirstVisPage(GetWin()->GetOutDev());
1165 const SwRect aPrevArea( VisArea() );
1166 const bool bFull = aPrevArea.IsEmpty();
1167 maVisArea = rRect;
1168 SetFirstVisPageInvalid();
1170 //When there a PaintRegion still exists and the VisArea has changed,
1171 //the PaintRegion is at least by now obsolete. The PaintRegion can
1172 //have been created by RootFrame::PaintSwFrame.
1173 if ( !mbInEndAction &&
1174 Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
1175 Imp()->DeletePaintRegion();
1177 CurrShell aCurr( this );
1179 bool bScrolled = false;
1181 SwPostItMgr* pPostItMgr = GetPostItMgr();
1183 if ( bFull )
1184 GetWin()->Invalidate();
1185 else
1187 //Calculate amount to be scrolled.
1188 const tools::Long nXDiff = aPrevArea.Left() - VisArea().Left();
1189 const tools::Long nYDiff = aPrevArea.Top() - VisArea().Top();
1191 if( !nXDiff && !GetViewOptions()->getBrowseMode() &&
1192 (!Imp()->HasDrawView() || !Imp()->GetDrawView()->IsGridVisible() ) )
1194 // If possible, don't scroll the application background
1195 // (PaintDesktop). Also limit the left and right side of
1196 // the scroll range to the pages.
1197 const SwPageFrame *pPage = static_cast<SwPageFrame*>(GetLayout()->Lower());
1198 if ( pPage->getFrameArea().Top() > pOldPage->getFrameArea().Top() )
1199 pPage = static_cast<const SwPageFrame*>(pOldPage);
1200 SwRect aBoth( VisArea() );
1201 aBoth.Union( aPrevArea );
1202 const SwTwips nBottom = aBoth.Bottom();
1203 SwTwips nMinLeft = SAL_MAX_INT32;
1204 SwTwips nMaxRight= 0;
1206 const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();
1208 while ( pPage && pPage->getFrameArea().Top() <= nBottom )
1210 SwRect aPageRect( pPage->GetBoundRect(GetWin()->GetOutDev()) );
1211 if ( bBookMode )
1213 const SwPageFrame& rFormatPage = pPage->GetFormatPage();
1214 aPageRect.SSize( rFormatPage.GetBoundRect(GetWin()->GetOutDev()).SSize() );
1217 // #i9719# - consider new border and shadow width
1218 if ( aPageRect.Overlaps( aBoth ) )
1220 SwTwips nPageLeft = 0;
1221 SwTwips nPageRight = 0;
1222 const sw::sidebarwindows::SidebarPosition aSidebarPos = pPage->SidebarPosition();
1224 if( aSidebarPos != sw::sidebarwindows::SidebarPosition::NONE )
1226 nPageLeft = aPageRect.Left();
1227 nPageRight = aPageRect.Right();
1230 if( nPageLeft < nMinLeft )
1231 nMinLeft = nPageLeft;
1232 if( nPageRight > nMaxRight )
1233 nMaxRight = nPageRight;
1234 //match with the draw objects
1235 //take nOfst into account as the objects have been
1236 //selected and have handles attached.
1237 if ( pPage->GetSortedObjs() )
1239 const tools::Long nOfst = GetOut()->PixelToLogic(
1240 Size(Imp()->GetDrawView()->GetMarkHdlSizePixel()/2,0)).Width();
1241 for (SwAnchoredObject* pObj : *pPage->GetSortedObjs())
1243 // ignore objects that are not actually placed on the page
1244 if (pObj->IsFormatPossible())
1246 const tools::Rectangle &rBound = pObj->GetObjRect().SVRect();
1247 if (rBound.Left() != FAR_AWAY) {
1248 // OD 03.03.2003 #107927# - use correct datatype
1249 const SwTwips nL = std::max( SwTwips(0), SwTwips(rBound.Left() - nOfst) );
1250 if ( nL < nMinLeft )
1251 nMinLeft = nL;
1252 if( rBound.Right() + nOfst > nMaxRight )
1253 nMaxRight = rBound.Right() + nOfst;
1259 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1261 tools::Rectangle aRect( aPrevArea.SVRect() );
1262 aRect.SetLeft( nMinLeft );
1263 aRect.SetRight( nMaxRight );
1264 if( VisArea().Overlaps( aPrevArea ) && !mnLockPaint )
1266 bScrolled = true;
1267 maVisArea.Pos() = aPrevArea.Pos();
1268 if ( SmoothScroll( nXDiff, nYDiff, &aRect ) )
1269 return;
1270 maVisArea.Pos() = rRect.Pos();
1272 else if (!comphelper::LibreOfficeKit::isActive())
1273 GetWin()->Invalidate( aRect );
1275 else if ( !mnLockPaint ) //will be released in Unlock
1277 if( VisArea().Overlaps( aPrevArea ) )
1279 bScrolled = true;
1280 maVisArea.Pos() = aPrevArea.Pos();
1281 if ( SmoothScroll( nXDiff, nYDiff, nullptr ) )
1282 return;
1283 maVisArea.Pos() = rRect.Pos();
1285 else
1286 GetWin()->Invalidate();
1290 // When tiled rendering, the map mode of the window is disabled, avoid
1291 // enabling it here.
1292 if (!comphelper::LibreOfficeKit::isActive())
1294 Point aPt( VisArea().Pos() );
1295 aPt.setX( -aPt.X() ); aPt.setY( -aPt.Y() );
1296 MapMode aMapMode( GetWin()->GetMapMode() );
1297 aMapMode.SetOrigin( aPt );
1298 GetWin()->SetMapMode( aMapMode );
1301 if ( HasDrawView() )
1303 Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
1304 Imp()->GetDrawView()->SetActualWin( GetWin()->GetOutDev() );
1306 GetWin()->PaintImmediately();
1308 if ( pPostItMgr ) // #i88070#
1310 pPostItMgr->Rescale();
1311 pPostItMgr->CalcRects();
1312 pPostItMgr->LayoutPostIts();
1315 if ( !bScrolled && pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1316 pPostItMgr->CorrectPositions();
1318 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1319 if( Imp()->IsAccessible() )
1320 Imp()->UpdateAccessible();
1321 #endif
1324 bool SwViewShell::SmoothScroll( tools::Long lXDiff, tools::Long lYDiff, const tools::Rectangle *pRect )
1326 #if !defined(MACOSX) && !defined(ANDROID) && !defined(IOS)
1327 // #i98766# - disable smooth scrolling for Mac
1329 const sal_uLong nBitCnt = mpOut->GetBitCount();
1330 tools::Long lMult = 1, lMax = LONG_MAX;
1331 if ( nBitCnt == 16 )
1333 lMax = 7000;
1334 lMult = 2;
1336 if ( nBitCnt == 24 )
1338 lMax = 5000;
1339 lMult = 6;
1341 else if ( nBitCnt == 1 )
1343 lMax = 3000;
1344 lMult = 12;
1347 // #i75172# isolated static conditions
1348 const bool bOnlyYScroll(!lXDiff && std::abs(lYDiff) != 0 && std::abs(lYDiff) < lMax);
1349 const bool bAllowedWithChildWindows(GetWin()->GetWindowClipRegionPixel().IsNull());
1350 const bool bSmoothScrollAllowed(bOnlyYScroll && mbEnableSmooth && GetViewOptions()->IsSmoothScroll() && bAllowedWithChildWindows);
1352 if(bSmoothScrollAllowed)
1354 Imp()->m_bStopSmooth = false;
1356 const SwRect aOldVis( VisArea() );
1358 //create virtual device and set.
1359 const Size aPixSz = GetWin()->PixelToLogic(Size(1,1));
1360 VclPtrInstance<VirtualDevice> pVout( *GetWin()->GetOutDev() );
1361 pVout->SetLineColor( GetWin()->GetOutDev()->GetLineColor() );
1362 pVout->SetFillColor( GetWin()->GetOutDev()->GetFillColor() );
1363 MapMode aMapMode( GetWin()->GetMapMode() );
1364 pVout->SetMapMode( aMapMode );
1365 Size aSize( maVisArea.Width()+2*aPixSz.Width(), std::abs(lYDiff)+(2*aPixSz.Height()) );
1366 if ( pRect )
1367 aSize.setWidth( std::min(aSize.Width(), pRect->GetWidth()+2*aPixSz.Width()) );
1368 if ( pVout->SetOutputSize( aSize ) )
1370 mnLockPaint++;
1372 //First Paint everything in the virtual device.
1373 SwRect aRect( VisArea() );
1374 aRect.Height( aSize.Height() );
1375 if ( pRect )
1377 aRect.Pos().setX( std::max(aRect.Left(),pRect->Left()-aPixSz.Width()) );
1378 aRect.Right( std::min(aRect.Right()+2*aPixSz.Width(), pRect->Right()+aPixSz.Width()));
1380 else
1381 aRect.AddWidth(2*aPixSz.Width() );
1382 aRect.Pos().setY( lYDiff < 0 ? aOldVis.Bottom() - aPixSz.Height()
1383 : aRect.Top() - aSize.Height() + aPixSz.Height() );
1384 aRect.Pos().setX( std::max( tools::Long(0), aRect.Left()-aPixSz.Width() ) );
1385 aRect.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.Pos()));
1386 aRect.SSize( GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.SSize())) );
1387 maVisArea = aRect;
1388 const Point aPt( -aRect.Left(), -aRect.Top() );
1389 aMapMode.SetOrigin( aPt );
1390 pVout->SetMapMode( aMapMode );
1391 OutputDevice *pOld = mpOut;
1392 mpOut = pVout.get();
1395 // #i75172# To get a clean repaint, a new ObjectContact is needed here. Without, the
1396 // repaint would not be correct since it would use the wrong DrawPage visible region.
1397 // This repaint IS about painting something currently outside the visible part (!).
1398 // For that purpose, AddDeviceToPaintView is used which creates a new SdrPageViewWindow
1399 // and all the necessary stuff. It's not cheap, but necessary here. Alone because repaint
1400 // target really is NOT the current window.
1401 // Also will automatically NOT use PreRendering and overlay (since target is VirtualDevice)
1402 if(!HasDrawView())
1403 MakeDrawView();
1404 SdrView* pDrawView = GetDrawView();
1405 pDrawView->AddDeviceToPaintView(*pVout, nullptr);
1407 // clear mpWin during DLPrePaint2 to get paint preparation for mpOut, but set it again
1408 // immediately afterwards. There are many decisions in SW which imply that Printing
1409 // is used when mpWin == 0 (wrong but widely used).
1410 vcl::Window* pOldWin = mpWin;
1411 mpWin = nullptr;
1412 DLPrePaint2(vcl::Region(aRect.SVRect()));
1413 mpWin = pOldWin;
1415 // SW paint stuff
1416 PaintDesktop(*GetOut(), aRect);
1417 SwViewShell::sbLstAct = true;
1418 GetLayout()->PaintSwFrame( *GetOut(), aRect );
1419 SwViewShell::sbLstAct = false;
1421 // end paint and destroy ObjectContact again
1422 DLPostPaint2(true);
1423 pDrawView->DeleteDeviceFromPaintView(*pVout);
1426 mpOut = pOld;
1427 maVisArea = aOldVis;
1429 //Now shift in parts and copy the new Pixel from the virtual device.
1431 // ??????????????????????
1432 // or is it better to get the scrollfactor from the User
1433 // as option?
1434 // ??????????????????????
1435 tools::Long lMaDelta = aPixSz.Height();
1436 if ( std::abs(lYDiff) > ( maVisArea.Height() / 3 ) )
1437 lMaDelta *= 6;
1438 else
1439 lMaDelta *= 2;
1441 lMaDelta *= lMult;
1443 if ( lYDiff < 0 )
1444 lMaDelta = -lMaDelta;
1446 tools::Long lDiff = lYDiff;
1447 while ( lDiff )
1449 tools::Long lScroll;
1450 if ( Imp()->m_bStopSmooth || std::abs(lDiff) <= std::abs(lMaDelta) )
1452 lScroll = lDiff;
1453 lDiff = 0;
1455 else
1457 lScroll = lMaDelta;
1458 lDiff -= lMaDelta;
1461 const SwRect aTmpOldVis = VisArea();
1462 maVisArea.Pos().AdjustY( -lScroll );
1463 maVisArea.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( VisArea().Pos()));
1464 lScroll = aTmpOldVis.Top() - VisArea().Top();
1465 if ( pRect )
1467 tools::Rectangle aTmp( aTmpOldVis.SVRect() );
1468 aTmp.SetLeft( pRect->Left() );
1469 aTmp.SetRight( pRect->Right() );
1470 GetWin()->Scroll( 0, lScroll, aTmp, ScrollFlags::Children);
1472 else
1473 GetWin()->Scroll( 0, lScroll, ScrollFlags::Children );
1475 const Point aTmpPt( -VisArea().Left(), -VisArea().Top() );
1476 MapMode aTmpMapMode( GetWin()->GetMapMode() );
1477 aTmpMapMode.SetOrigin( aTmpPt );
1478 GetWin()->SetMapMode( aTmpMapMode );
1480 if ( Imp()->HasDrawView() )
1481 Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
1483 SetFirstVisPageInvalid();
1484 if ( !Imp()->m_bStopSmooth )
1486 const bool bScrollDirectionIsUp(lScroll > 0);
1487 Imp()->m_aSmoothRect = VisArea();
1489 if(bScrollDirectionIsUp)
1491 Imp()->m_aSmoothRect.Bottom( VisArea().Top() + lScroll + aPixSz.Height());
1493 else
1495 Imp()->m_aSmoothRect.Top( VisArea().Bottom() + lScroll - aPixSz.Height());
1498 Imp()->m_bSmoothUpdate = true;
1499 GetWin()->PaintImmediately();
1500 Imp()->m_bSmoothUpdate = false;
1502 if(!Imp()->m_bStopSmooth)
1504 // start paint on logic base
1505 const tools::Rectangle aTargetLogic(Imp()->m_aSmoothRect.SVRect());
1506 DLPrePaint2(vcl::Region(aTargetLogic));
1508 // get target rectangle in discrete pixels
1509 OutputDevice& rTargetDevice = mpTargetPaintWindow->GetTargetOutputDevice();
1510 const tools::Rectangle aTargetPixel(rTargetDevice.LogicToPixel(aTargetLogic));
1512 // get source top-left in discrete pixels
1513 const Point aSourceTopLeft(pVout->LogicToPixel(aTargetLogic.TopLeft()));
1515 // switch off MapModes
1516 const bool bMapModeWasEnabledDest(rTargetDevice.IsMapModeEnabled());
1517 const bool bMapModeWasEnabledSource(pVout->IsMapModeEnabled());
1518 rTargetDevice.EnableMapMode(false);
1519 pVout->EnableMapMode(false);
1521 rTargetDevice.DrawOutDev(
1522 aTargetPixel.TopLeft(), aTargetPixel.GetSize(), // dest
1523 aSourceTopLeft, aTargetPixel.GetSize(), // source
1524 *pVout);
1526 // restore MapModes
1527 rTargetDevice.EnableMapMode(bMapModeWasEnabledDest);
1528 pVout->EnableMapMode(bMapModeWasEnabledSource);
1530 // end paint on logoc base
1531 DLPostPaint2(true);
1533 else
1534 --mnLockPaint;
1537 pVout.disposeAndClear();
1538 GetWin()->PaintImmediately();
1539 if ( !Imp()->m_bStopSmooth )
1540 --mnLockPaint;
1541 SetFirstVisPageInvalid();
1542 return true;
1544 pVout.disposeAndClear();
1546 #endif
1548 maVisArea.Pos().AdjustX( -lXDiff );
1549 maVisArea.Pos().AdjustY( -lYDiff );
1550 if ( pRect )
1551 GetWin()->Scroll( lXDiff, lYDiff, *pRect, ScrollFlags::Children);
1552 else
1553 GetWin()->Scroll( lXDiff, lYDiff, ScrollFlags::Children);
1554 return false;
1557 void SwViewShell::PaintDesktop(const vcl::RenderContext& rRenderContext, const SwRect &rRect)
1559 if ( !GetWin() && !GetOut()->GetConnectMetaFile() )
1560 return; //for the printer we don't do anything here.
1562 if(comphelper::LibreOfficeKit::isActive())
1563 return;
1565 //Catch exceptions, so that it doesn't look so surprising.
1566 //Can e.g. happen during Idle.
1567 //Unfortunately we must at any rate Paint the rectangles next to the pages,
1568 //as these are not painted at VisPortChgd.
1569 bool bBorderOnly = false;
1570 const SwRootFrame *pRoot = GetLayout();
1571 if ( rRect.Top() > pRoot->getFrameArea().Bottom() )
1573 const SwFrame *pPg = pRoot->Lower();
1574 while ( pPg && pPg->GetNext() )
1575 pPg = pPg->GetNext();
1576 if ( !pPg || !pPg->getFrameArea().Overlaps( VisArea() ) )
1577 bBorderOnly = true;
1580 const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();
1582 SwRegionRects aRegion( rRect );
1584 //mod #i6193: remove sidebar area to avoid flickering
1585 const SwPostItMgr* pPostItMgr = GetPostItMgr();
1586 const SwTwips nSidebarWidth = pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ?
1587 pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() :
1590 if ( bBorderOnly )
1592 const SwFrame *pPage =pRoot->Lower();
1593 SwRect aLeft( rRect ), aRight( rRect );
1594 while ( pPage )
1596 tools::Long nTmp = pPage->getFrameArea().Left();
1597 if ( nTmp < aLeft.Right() )
1598 aLeft.Right( nTmp );
1599 nTmp = pPage->getFrameArea().Right();
1600 if ( nTmp > aRight.Left() )
1602 aRight.Left( nTmp + nSidebarWidth );
1604 pPage = pPage->GetNext();
1606 aRegion.clear();
1607 if ( aLeft.HasArea() )
1608 aRegion.push_back( aLeft );
1609 if ( aRight.HasArea() )
1610 aRegion.push_back( aRight );
1612 else
1614 const SwFrame *pPage = Imp()->GetFirstVisPage(&rRenderContext);
1615 const SwTwips nBottom = rRect.Bottom();
1616 while ( pPage && !aRegion.empty() &&
1617 (pPage->getFrameArea().Top() <= nBottom) )
1619 SwRect aPageRect( pPage->getFrameArea() );
1620 if ( bBookMode )
1622 const SwPageFrame& rFormatPage = static_cast<const SwPageFrame*>(pPage)->GetFormatPage();
1623 aPageRect.SSize( rFormatPage.getFrameArea().SSize() );
1626 const bool bSidebarRight =
1627 static_cast<const SwPageFrame*>(pPage)->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
1628 aPageRect.Pos().AdjustX( -(bSidebarRight ? 0 : nSidebarWidth) );
1629 aPageRect.AddWidth(nSidebarWidth );
1631 if ( aPageRect.Overlaps( rRect ) )
1632 aRegion -= aPageRect;
1634 pPage = pPage->GetNext();
1637 if ( !aRegion.empty() )
1638 PaintDesktop_(aRegion);
1641 // PaintDesktop is split in two, this part is also used by PreviewPage
1642 void SwViewShell::PaintDesktop_(const SwRegionRects &rRegion)
1644 // OD 2004-04-23 #116347#
1645 GetOut()->Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
1646 GetOut()->SetLineColor();
1648 for ( auto &rRgn : rRegion )
1650 const tools::Rectangle aRectangle(rRgn.SVRect());
1652 // #i93170#
1653 // Here we have a real Problem. On the one hand we have the buffering for paint
1654 // and overlay which needs an embracing pair of DLPrePaint2/DLPostPaint2 calls,
1655 // on the other hand the MapMode is not set correctly when this code is executed.
1656 // This is done in the users of this method, for each SWpage before painting it.
1657 // Since the MapMode is not correct here, the call to DLPostPaint2 will paint
1658 // existing FormControls due to the current MapMode.
1660 // There are basically three solutions for this:
1662 // (1) Set the MapMode correct, move the background painting to the users of
1663 // this code
1665 // (2) Do no DLPrePaint2/DLPostPaint2 here; no SdrObjects are allowed to lie in
1666 // the desktop region. Disadvantage: the desktop will not be part of the
1667 // buffers, e.g. overlay. Thus, as soon as overlay will be used over the
1668 // desktop, it will not work.
1670 // (3) expand DLPostPaint2 with a flag to signal if FormControl paints shall
1671 // be done or not
1673 // Currently, (3) will be the best possible solution. It will keep overlay and
1674 // buffering intact and work without MapMode for single pages. In the medium
1675 // to long run, (1) will need to be used and the bool bPaintFormLayer needs
1676 // to be removed again
1678 // #i68597# inform Drawinglayer about display change
1679 DLPrePaint2(vcl::Region(aRectangle));
1681 // #i75172# needed to move line/Fill color setters into loop since DLPrePaint2
1682 // may exchange GetOut(), that's it's purpose. This happens e.g. at print preview.
1683 GetOut()->SetFillColor( GetViewOptions()->GetAppBackgroundColor());
1684 GetOut()->SetLineColor();
1685 GetOut()->DrawRect(aRectangle);
1687 DLPostPaint2(false);
1690 GetOut()->Pop();
1693 bool SwViewShell::CheckInvalidForPaint( const SwRect &rRect )
1695 if ( !GetWin() )
1696 return false;
1698 const SwPageFrame *pPage = Imp()->GetFirstVisPage(GetOut());
1699 const SwTwips nBottom = VisArea().Bottom();
1700 const SwTwips nRight = VisArea().Right();
1701 bool bRet = false;
1702 while ( !bRet && pPage && ((pPage->getFrameArea().Top() <= nBottom) &&
1703 (pPage->getFrameArea().Left() <= nRight)))
1705 if ( pPage->IsInvalid() || pPage->IsInvalidFly() )
1706 bRet = true;
1707 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1710 if ( bRet )
1712 //Unfortunately Start/EndAction won't help here, as the Paint originated
1713 //from GUI and so Clipping has been set against getting through.
1714 //Ergo: do it all yourself (see ImplEndAction())
1715 if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea())
1716 Imp()->DeletePaintRegion();
1718 SwLayAction aAction( GetLayout(), Imp() );
1719 aAction.SetComplete( false );
1720 // We increment the action counter to avoid a recursive call of actions
1721 // e.g. from a SwFEShell::RequestObjectResize(..) in bug 95829.
1722 // A recursive call of actions is no good idea because the inner action
1723 // can't format frames which are locked by the outer action. This may
1724 // cause and endless loop.
1725 ++mnStartAction;
1726 aAction.Action(GetWin()->GetOutDev());
1727 --mnStartAction;
1729 std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();
1730 if ( oRegion && aAction.IsBrowseActionStop() )
1732 //only of interest when something has changed in the visible range
1733 bool bStop = true;
1734 for ( size_t i = 0; i < oRegion->size(); ++i )
1736 const SwRect &rTmp = (*oRegion)[i];
1737 bStop = rTmp.Overlaps( VisArea() );
1738 if ( !bStop )
1739 break;
1741 if ( bStop )
1742 oRegion.reset();
1745 if ( oRegion )
1747 oRegion->LimitToOrigin();
1748 oRegion->Compress( SwRegionRects::CompressFuzzy );
1749 bRet = false;
1750 if ( !oRegion->empty() )
1752 SwRegionRects aRegion( rRect );
1753 for ( size_t i = 0; i < oRegion->size(); ++i )
1754 { const SwRect &rTmp = (*oRegion)[i];
1755 if ( !rRect.Contains( rTmp ) )
1757 InvalidateWindows( rTmp );
1758 if ( rTmp.Overlaps( VisArea() ) )
1759 { aRegion -= rTmp;
1760 bRet = true;
1764 if ( bRet )
1766 for ( size_t i = 0; i < aRegion.size(); ++i )
1767 GetWin()->Invalidate( aRegion[i].SVRect() );
1769 if ( rRect != VisArea() )
1771 //rRect == VisArea is the special case for new or
1772 //Shift-Ctrl-R, when it shouldn't be necessary to
1773 //hold the rRect again in Document coordinates.
1774 if ( maInvalidRect.IsEmpty() )
1775 maInvalidRect = rRect;
1776 else
1777 maInvalidRect.Union( rRect );
1781 else
1782 bRet = false;
1784 else
1785 bRet = false;
1787 return bRet;
1790 namespace
1792 /// Similar to comphelper::FlagRestorationGuard, but for vcl::RenderContext.
1793 class RenderContextGuard
1795 std::unique_ptr<SdrPaintWindow> m_TemporaryPaintWindow;
1796 SdrPageWindow* m_pPatchedPageWindow;
1797 SdrPaintWindow* m_pPreviousPaintWindow = nullptr;
1799 public:
1800 RenderContextGuard(VclPtr<vcl::RenderContext>& pRef, vcl::RenderContext* pValue, SwViewShell* pShell)
1801 : m_pPatchedPageWindow(nullptr)
1803 pRef = pValue;
1805 if (pValue == pShell->GetWin()->GetOutDev())
1806 return;
1808 SdrView* pDrawView(pShell->Imp()->GetDrawView());
1810 if (nullptr == pDrawView)
1811 return;
1813 SdrPageView* pSdrPageView(pDrawView->GetSdrPageView());
1815 if (nullptr != pSdrPageView)
1817 m_pPatchedPageWindow = pSdrPageView->FindPageWindow(*pShell->GetWin()->GetOutDev());
1819 if (nullptr != m_pPatchedPageWindow)
1821 m_TemporaryPaintWindow.reset(new SdrPaintWindow(*pDrawView, *pValue));
1822 m_pPreviousPaintWindow = m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
1827 ~RenderContextGuard()
1829 if(nullptr != m_pPatchedPageWindow)
1831 m_pPatchedPageWindow->unpatchPaintWindow(m_pPreviousPaintWindow);
1837 void SwViewShell::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect)
1839 RenderContextGuard aGuard(mpOut, &rRenderContext, this);
1840 if ( mnLockPaint )
1842 if ( Imp()->m_bSmoothUpdate )
1844 SwRect aTmp( rRect );
1845 if ( !Imp()->m_aSmoothRect.Contains( aTmp ) )
1846 Imp()->m_bStopSmooth = true;
1847 else
1849 Imp()->m_aSmoothRect = aTmp;
1850 return;
1853 else
1854 return;
1857 if ( SwRootFrame::IsInPaint() )
1859 //During the publication of a page at printing the Paint is buffered.
1860 SwPaintQueue::Add( this, SwRect( rRect ) );
1861 return;
1864 //With !nStartAction I try to protect me against erroneous code at other places.
1865 //Hopefully it will not lead to problems!?
1866 if ( mbPaintWorks && !mnStartAction )
1868 if( GetWin() && GetWin()->IsVisible() )
1870 SwRect aRect( rRect );
1871 if ( mbPaintInProgress ) //Guard against double Paints!
1873 GetWin()->Invalidate( rRect );
1874 return;
1877 mbPaintInProgress = true;
1878 CurrShell aCurr( this );
1879 SwRootFrame::SetNoVirDev( true );
1881 //We don't want to Clip to and from, we trust that all are limited
1882 //to the rectangle and only need to calculate the clipping once.
1883 //The ClipRect is removed here once and not recovered, as externally
1884 //no one needs it anymore anyway.
1885 //Not when we paint a Metafile.
1886 if( !GetOut()->GetConnectMetaFile() && GetOut()->IsClipRegion())
1887 GetOut()->SetClipRegion();
1889 if ( IsPreview() )
1891 //When useful, process or destroy the old InvalidRect.
1892 if ( aRect.Contains( maInvalidRect ) )
1893 ResetInvalidRect();
1894 SwViewShell::sbLstAct = true;
1895 GetLayout()->PaintSwFrame( rRenderContext, aRect );
1896 SwViewShell::sbLstAct = false;
1898 else
1900 //When one of the visible pages still has anything entered for
1901 //Repaint, Repaint must be triggered.
1902 if ( !CheckInvalidForPaint( aRect ) )
1904 // --> OD 2009-08-12 #i101192#
1905 // start Pre/PostPaint encapsulation to avoid screen blinking
1906 const vcl::Region aRepaintRegion(aRect.SVRect());
1907 DLPrePaint2(aRepaintRegion);
1909 // <--
1910 PaintDesktop(rRenderContext, aRect);
1912 //When useful, process or destroy the old InvalidRect.
1913 if ( aRect.Contains( maInvalidRect ) )
1914 ResetInvalidRect();
1915 SwViewShell::sbLstAct = true;
1916 GetLayout()->PaintSwFrame( rRenderContext, aRect );
1917 SwViewShell::sbLstAct = false;
1918 // --> OD 2009-08-12 #i101192#
1919 // end Pre/PostPaint encapsulation
1920 DLPostPaint2(true);
1921 // <--
1924 SwRootFrame::SetNoVirDev( false );
1925 mbPaintInProgress = false;
1926 UISizeNotify();
1929 else
1931 if ( maInvalidRect.IsEmpty() )
1932 maInvalidRect = SwRect( rRect );
1933 else
1934 maInvalidRect.Union( SwRect( rRect ) );
1936 if ( mbInEndAction && GetWin() )
1938 const vcl::Region aRegion(GetWin()->GetPaintRegion());
1939 RectangleVector aRectangles;
1940 aRegion.GetRegionRectangles(aRectangles);
1942 for(const auto& rRectangle : aRectangles)
1944 Imp()->AddPaintRect(SwRect(rRectangle));
1947 //RegionHandle hHdl( aRegion.BeginEnumRects() );
1948 //Rectangle aRect;
1949 //while ( aRegion.GetEnumRects( hHdl, aRect ) )
1950 // Imp()->AddPaintRect( aRect );
1951 //aRegion.EndEnumRects( hHdl );
1953 else if ( SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) &&
1954 GetOut() == GetWin()->GetOutDev() )
1956 // #i68597#
1957 const vcl::Region aDLRegion(rRect);
1958 DLPrePaint2(aDLRegion);
1960 rRenderContext.Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
1961 rRenderContext.SetFillColor( Imp()->GetRetoucheColor() );
1962 rRenderContext.SetLineColor();
1963 rRenderContext.DrawRect( rRect );
1964 rRenderContext.Pop();
1965 // #i68597#
1966 DLPostPaint2(true);
1971 void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contextHeight, int tilePosX, int tilePosY, tools::Long tileWidth, tools::Long tileHeight)
1973 // SwViewShell's output device setup
1974 // TODO clean up SwViewShell's approach to output devices (the many of
1975 // them - mpBufferedOut, mpOut, mpWin, ...)
1976 OutputDevice *pSaveOut = mpOut;
1977 comphelper::LibreOfficeKit::setTiledPainting(true);
1978 mpOut = &rDevice;
1980 // resizes the virtual device so to contain the entries context
1981 rDevice.SetOutputSizePixel(Size(contextWidth, contextHeight));
1983 // setup the output device to draw the tile
1984 MapMode aMapMode(rDevice.GetMapMode());
1985 aMapMode.SetMapUnit(MapUnit::MapTwip);
1986 aMapMode.SetOrigin(Point(-tilePosX, -tilePosY));
1988 // Scaling. Must convert from pixels to twips. We know
1989 // that VirtualDevices use a DPI of 96.
1990 const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
1991 Fraction scaleX = Fraction(contextWidth, tileWidth) * scale;
1992 Fraction scaleY = Fraction(contextHeight, tileHeight) * scale;
1993 aMapMode.SetScaleX(scaleX);
1994 aMapMode.SetScaleY(scaleY);
1995 rDevice.SetMapMode(aMapMode);
1997 // Update scaling of SwEditWin and its sub-widgets, needed for comments.
1998 sal_uInt16 nOldZoomValue = 0;
1999 if (GetWin() && GetWin()->GetMapMode().GetScaleX() != scaleX)
2001 double fScale = double(scaleX);
2002 SwViewOption aOption(*GetViewOptions());
2003 nOldZoomValue = aOption.GetZoom();
2004 aOption.SetZoom(fScale * 100);
2005 ApplyViewOptions(aOption);
2006 // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
2007 GetWin()->EnableMapMode(false);
2010 tools::Rectangle aOutRect(Point(tilePosX, tilePosY),
2011 rDevice.PixelToLogic(Size(contextWidth, contextHeight)));
2013 // Make the requested area visible -- we can't use MakeVisible as that will
2014 // only scroll the contents, but won't zoom/resize if needed.
2015 // Without this, items/text that are outside the visible area (in the SwView)
2016 // won't be painted when rendering tiles (at least when using either the
2017 // tiledrendering app, or the gtktiledviewer) -- although ultimately we
2018 // probably want to fix things so that the SwView's area doesn't affect
2019 // tiled rendering?
2020 VisPortChgd(SwRect(aOutRect));
2022 // Invoke SwLayAction if layout is not yet ready.
2023 CheckInvalidForPaint(SwRect(aOutRect));
2025 // draw - works in logic coordinates
2026 Paint(rDevice, aOutRect);
2028 SwPostItMgr* pPostItMgr = GetPostItMgr();
2029 if (GetViewOptions()->IsPostIts() && pPostItMgr)
2030 pPostItMgr->PaintTile(rDevice);
2032 // SwViewShell's output device tear down
2034 // A view shell can get a PaintTile call for a tile at a zoom level
2035 // different from the one, the related client really is.
2036 // In such a case it is better to reset the current scale value to
2037 // the original one, since such a value should be in synchronous with
2038 // the zoom level in the client (see setClientZoom).
2039 // At present the zoom value returned by GetViewOptions()->GetZoom() is
2040 // used in SwXTextDocument methods (postMouseEvent and setGraphicSelection)
2041 // for passing the correct mouse position to an edited chart (if any).
2042 if (nOldZoomValue !=0)
2044 SwViewOption aOption(*GetViewOptions());
2045 aOption.SetZoom(nOldZoomValue);
2046 ApplyViewOptions(aOption);
2048 // Changing the zoom value doesn't always trigger the updating of
2049 // the client ole object area, so we call it directly.
2050 SfxInPlaceClient* pIPClient = GetSfxViewShell()->GetIPClient();
2051 if (pIPClient)
2053 pIPClient->VisAreaChanged();
2055 // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
2056 GetWin()->EnableMapMode(false);
2059 mpOut = pSaveOut;
2060 comphelper::LibreOfficeKit::setTiledPainting(false);
2063 void SwViewShell::SetBrowseBorder( const Size& rNew )
2065 if( rNew != maBrowseBorder )
2067 maBrowseBorder = rNew;
2068 if ( maVisArea.HasArea() )
2069 InvalidateLayout( false );
2073 const Size& SwViewShell::GetBrowseBorder() const
2075 return maBrowseBorder;
2078 sal_Int32 SwViewShell::GetBrowseWidth() const
2080 const SwPostItMgr* pPostItMgr = GetPostItMgr();
2081 if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
2083 Size aBorder( maBrowseBorder );
2084 aBorder.AdjustWidth(maBrowseBorder.Width() );
2085 aBorder.AdjustWidth(pPostItMgr->GetSidebarWidth(true) + pPostItMgr->GetSidebarBorderWidth(true) );
2086 return maVisArea.Width() - GetOut()->PixelToLogic(aBorder).Width();
2088 else
2089 return maVisArea.Width() - 2 * GetOut()->PixelToLogic(maBrowseBorder).Width();
2092 void SwViewShell::InvalidateLayout( bool bSizeChanged )
2094 if ( !bSizeChanged && !GetViewOptions()->getBrowseMode() &&
2095 !GetViewOptions()->IsWhitespaceHidden() )
2096 return;
2098 CurrShell aCurr( this );
2100 OSL_ENSURE( GetLayout(), "Layout not ready" );
2102 // When the Layout doesn't have a height yet, nothing is formatted.
2103 // That leads to problems with Invalidate, e.g. when setting up a new View
2104 // the content is inserted and formatted (regardless of empty VisArea).
2105 // Therefore the pages must be roused for formatting.
2106 if( !GetLayout()->getFrameArea().Height() )
2108 SwFrame* pPage = GetLayout()->Lower();
2109 while( pPage )
2111 pPage->InvalidateSize_();
2112 pPage = pPage->GetNext();
2114 return;
2117 LockPaint(LockPaintReason::InvalidateLayout);
2118 StartAction();
2120 SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
2122 { pPg->InvalidateSize();
2123 pPg->InvalidatePrt_();
2124 pPg->InvaPercentLowers();
2125 if ( bSizeChanged )
2127 pPg->PrepareHeader();
2128 pPg->PrepareFooter();
2130 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
2131 } while ( pPg );
2133 // When the size ratios in browse mode change,
2134 // the Position and PrtArea of the Content and Tab frames must be Invalidated.
2135 SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
2136 // In case of layout or mode change, the ContentFrames need a size-Invalidate
2137 // because of printer/screen formatting.
2138 if ( bSizeChanged )
2139 nInv |= SwInvalidateFlags::Size | SwInvalidateFlags::Direction;
2141 GetLayout()->InvalidateAllContent( nInv );
2143 SwFrame::CheckPageDescs( static_cast<SwPageFrame*>(GetLayout()->Lower()) );
2145 EndAction();
2146 UnlockPaint();
2149 SwRootFrame *SwViewShell::GetLayout() const
2151 return mpLayout.get();
2154 vcl::RenderContext& SwViewShell::GetRefDev() const
2156 OutputDevice* pTmpOut = nullptr;
2157 if ( GetWin() &&
2158 GetViewOptions()->getBrowseMode() &&
2159 !GetViewOptions()->IsPrtFormat() )
2160 pTmpOut = GetWin()->GetOutDev();
2161 else
2162 pTmpOut = GetDoc()->getIDocumentDeviceAccess().getReferenceDevice( true );
2164 return *pTmpOut;
2167 const SwNodes& SwViewShell::GetNodes() const
2169 return mxDoc->GetNodes();
2172 void SwViewShell::DrawSelChanged()
2176 Size SwViewShell::GetDocSize() const
2178 Size aSz;
2179 const SwRootFrame* pRoot = GetLayout();
2180 if( pRoot )
2181 aSz = pRoot->getFrameArea().SSize();
2183 return aSz;
2186 SfxItemPool& SwViewShell::GetAttrPool()
2188 return GetDoc()->GetAttrPool();
2191 void SwViewShell::ApplyViewOptions( const SwViewOption &rOpt )
2193 for(SwViewShell& rSh : GetRingContainer())
2194 rSh.StartAction();
2196 ImplApplyViewOptions( rOpt );
2198 // With one layout per view it is no longer necessary
2199 // to sync these "layout related" view options
2200 // But as long as we have to disable "multiple layout"
2202 for(SwViewShell& rSh : GetRingContainer())
2204 if(&rSh == this)
2205 continue;
2206 SwViewOption aOpt( *rSh.GetViewOptions() );
2207 aOpt.SetFieldName( rOpt.IsFieldName() );
2208 aOpt.SetShowHiddenField( rOpt.IsShowHiddenField() );
2209 aOpt.SetShowHiddenPara( rOpt.IsShowHiddenPara() );
2210 aOpt.SetShowHiddenChar( rOpt.IsShowHiddenChar() );
2211 aOpt.SetViewLayoutBookMode( rOpt.IsViewLayoutBookMode() );
2212 aOpt.SetHideWhitespaceMode(rOpt.IsHideWhitespaceMode());
2213 aOpt.SetViewLayoutColumns(rOpt.GetViewLayoutColumns());
2214 aOpt.SetPostIts(rOpt.IsPostIts());
2215 if ( !(aOpt == *rSh.GetViewOptions()) )
2216 rSh.ImplApplyViewOptions( aOpt );
2218 // End of disabled multiple window
2220 for(SwViewShell& rSh : GetRingContainer())
2221 rSh.EndAction();
2224 static bool
2225 IsCursorInFieldmarkHidden(SwPaM const& rCursor, sw::FieldmarkMode const eMode)
2227 if (eMode == sw::FieldmarkMode::ShowBoth)
2229 return false;
2231 IDocumentMarkAccess const& rIDMA(*rCursor.GetDoc().getIDocumentMarkAccess());
2232 // iterate, for nested fieldmarks
2233 for (auto iter = rIDMA.getFieldmarksBegin(); iter != rIDMA.getFieldmarksEnd(); ++iter)
2235 if (*rCursor.GetPoint() <= (**iter).GetMarkStart())
2237 return false;
2239 if (*rCursor.GetPoint() < (**iter).GetMarkEnd())
2241 SwPosition const sepPos(sw::mark::FindFieldSep(
2242 dynamic_cast<sw::mark::IFieldmark&>(**iter)));
2243 if (eMode == sw::FieldmarkMode::ShowResult)
2245 if (*rCursor.GetPoint() <= sepPos
2246 && *rCursor.GetPoint() != (**iter).GetMarkStart())
2248 return true;
2251 else
2253 if (sepPos < *rCursor.GetPoint())
2255 return true;
2260 return false;
2263 void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
2265 if (*mpOpt == rOpt)
2266 return;
2268 vcl::Window *pMyWin = GetWin();
2269 if( !pMyWin )
2271 OSL_ENSURE( pMyWin, "SwViewShell::ApplyViewOptions: no window" );
2272 return;
2275 CurrShell aCurr( this );
2277 bool bReformat = false;
2279 if( mpOpt->IsShowHiddenField() != rOpt.IsShowHiddenField() )
2281 static_cast<SwHiddenTextFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenText ))->
2282 SetHiddenFlag( !rOpt.IsShowHiddenField() );
2283 bReformat = true;
2285 if ( mpOpt->IsShowHiddenPara() != rOpt.IsShowHiddenPara() )
2287 SwHiddenParaFieldType* pFieldType = static_cast<SwHiddenParaFieldType*>(GetDoc()->
2288 getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenPara));
2289 if( pFieldType && pFieldType->HasWriterListeners() )
2290 pFieldType->PrintHiddenPara();
2291 bReformat = true;
2293 if ( !bReformat && mpOpt->IsShowHiddenChar() != rOpt.IsShowHiddenChar() )
2295 bReformat = GetDoc()->ContainsHiddenChars();
2297 if ( mpOpt->IsShowChangesInMargin() != rOpt.IsShowChangesInMargin() ||
2298 mpOpt->IsShowChangesInMargin2() != rOpt.IsShowChangesInMargin2() )
2300 if (rOpt.IsShowChangesInMargin())
2301 GetDoc()->GetDocumentRedlineManager().HideAll(
2302 /*bDeletion=*/!rOpt.IsShowChangesInMargin2() );
2303 else
2304 GetDoc()->GetDocumentRedlineManager().ShowAll();
2305 GetLayout()->SetHideRedlines( false );
2308 // bReformat becomes true, if ...
2309 // - fieldnames apply or not ...
2310 // ( - SwEndPortion must _no_ longer be generated. )
2311 // - Of course, the screen is something completely different than the printer ...
2312 bool const isToggleFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName());
2314 if (mpOpt->IsFieldName() != rOpt.IsFieldName()
2315 || mpOpt->IsParagraph() != rOpt.IsParagraph())
2317 GetLayout()->SetFieldmarkMode( rOpt.IsFieldName()
2318 ? sw::FieldmarkMode::ShowCommand
2319 : sw::FieldmarkMode::ShowResult,
2320 rOpt.IsParagraph()
2321 ? sw::ParagraphBreakMode::Shown
2322 : sw::ParagraphBreakMode::Hidden);
2323 bReformat = true;
2326 // The map mode is changed, minima/maxima will be attended by UI
2327 if( mpOpt->GetZoom() != rOpt.GetZoom() && !IsPreview() )
2329 MapMode aMode( pMyWin->GetMapMode() );
2330 Fraction aNewFactor( rOpt.GetZoom(), 100 );
2331 aMode.SetScaleX( aNewFactor );
2332 aMode.SetScaleY( aNewFactor );
2333 pMyWin->SetMapMode( aMode );
2334 // if not a reference device (printer) is used for formatting,
2335 // but the screen, new formatting is needed for zoomfactor changes.
2336 if (mpOpt->getBrowseMode() || mpOpt->IsWhitespaceHidden())
2337 bReformat = true;
2340 bool bBrowseModeChanged = false;
2341 if( mpOpt->getBrowseMode() != rOpt.getBrowseMode() )
2343 bBrowseModeChanged = true;
2344 bReformat = true;
2346 else if( mpOpt->getBrowseMode() && mpOpt->IsPrtFormat() != rOpt.IsPrtFormat() )
2347 bReformat = true;
2349 bool bHideWhitespaceModeChanged = false;
2350 if (mpOpt->IsWhitespaceHidden() != rOpt.IsWhitespaceHidden())
2352 // When whitespace is hidden, view change needs reformatting.
2353 bHideWhitespaceModeChanged = true;
2354 bReformat = true;
2357 if ( HasDrawView() || rOpt.IsGridVisible() )
2359 if ( !HasDrawView() )
2360 MakeDrawView();
2362 SwDrawView *pDView = Imp()->GetDrawView();
2363 if ( pDView->IsDragStripes() != rOpt.IsCrossHair() )
2364 pDView->SetDragStripes( rOpt.IsCrossHair() );
2366 if ( pDView->IsGridSnap() != rOpt.IsSnap() )
2367 pDView->SetGridSnap( rOpt.IsSnap() );
2369 if ( pDView->IsGridVisible() != rOpt.IsGridVisible() )
2370 pDView->SetGridVisible( rOpt.IsGridVisible() );
2372 const Size &rSz = rOpt.GetSnapSize();
2373 pDView->SetGridCoarse( rSz );
2375 const Size aFSize
2376 ( rSz.Width() ? rSz.Width() / (rOpt.GetDivisionX()+1) : 0,
2377 rSz.Height()? rSz.Height()/ (rOpt.GetDivisionY()+1) : 0);
2378 pDView->SetGridFine( aFSize );
2379 Fraction aSnGrWdtX(rSz.Width(), rOpt.GetDivisionX() + 1);
2380 Fraction aSnGrWdtY(rSz.Height(), rOpt.GetDivisionY() + 1);
2381 pDView->SetSnapGridWidth( aSnGrWdtX, aSnGrWdtY );
2383 // set handle size to 9 pixels, always
2384 pDView->SetMarkHdlSizePixel(9);
2387 bool bOnlineSpellChgd = mpOpt->IsOnlineSpell() != rOpt.IsOnlineSpell();
2389 *mpOpt = rOpt; // First the options are taken.
2390 mpOpt->SetUIOptions(rOpt);
2392 mxDoc->GetDocumentSettingManager().set(DocumentSettingId::HTML_MODE, 0 != ::GetHtmlMode(mxDoc->GetDocShell()));
2394 if( bBrowseModeChanged || bHideWhitespaceModeChanged )
2396 // #i44963# Good occasion to check if page sizes in
2397 // page descriptions are still set to (LONG_MAX, LONG_MAX) (html import)
2398 mxDoc->CheckDefaultPageFormat();
2399 InvalidateLayout( true );
2402 SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(GetSfxViewShell()->GetCurrentDocument());
2403 SfxLokHelper::notifyViewRenderState(GetSfxViewShell(), pModel);
2405 pMyWin->Invalidate();
2406 if ( bReformat )
2408 // Nothing helps, we need to send all ContentFrames a
2409 // Prepare, we format anew:
2410 StartAction();
2411 Reformat();
2412 EndAction();
2415 if (isToggleFieldNames)
2417 for(SwViewShell& rSh : GetRingContainer())
2419 if (SwCursorShell *const pSh = dynamic_cast<SwCursorShell *>(&rSh))
2421 if ((mpOpt->IsFieldName() && pSh->CursorInsideInputField())
2422 || IsCursorInFieldmarkHidden(*pSh->GetCursor(),
2423 pSh->GetLayout()->GetFieldmarkMode()))
2424 { // move cursor out of field
2425 pSh->Left(1, SwCursorSkipMode::Chars);
2429 // the layout changes but SetModified() wasn't called so do it here:
2430 mxDoc->GetDocumentLayoutManager().ClearSwLayouterEntries();
2433 if( !bOnlineSpellChgd )
2434 return;
2436 bool bOnlineSpl = rOpt.IsOnlineSpell();
2437 for(SwViewShell& rSh : GetRingContainer())
2439 if(&rSh == this)
2440 continue;
2441 rSh.mpOpt->SetOnlineSpell( bOnlineSpl );
2442 vcl::Window *pTmpWin = rSh.GetWin();
2443 if( pTmpWin )
2444 pTmpWin->Invalidate();
2449 void SwViewShell::SetUIOptions( const SwViewOption &rOpt )
2451 mpOpt->SetUIOptions(rOpt);
2452 //the API-Flag of the view options is set but never reset
2453 //it is required to set scroll bars in readonly documents
2454 if(rOpt.IsStarOneSetting())
2455 mpOpt->SetStarOneSetting(true);
2457 mpOpt->SetSymbolFont(rOpt.GetSymbolFont());
2460 void SwViewShell::SetReadonlyOption(bool bSet)
2462 //JP 01.02.99: at readonly flag query properly
2463 // and if need be format; Bug 61335
2465 // Are we switching from readonly to edit?
2466 if( bSet == mpOpt->IsReadonly() )
2467 return;
2469 // so that the flags can be queried properly.
2470 mpOpt->SetReadonly( false );
2472 bool bReformat = mpOpt->IsFieldName();
2474 mpOpt->SetReadonly( bSet );
2476 if( bReformat )
2478 StartAction();
2479 Reformat();
2480 if ( GetWin() )
2481 GetWin()->Invalidate();
2482 EndAction();
2484 else if ( GetWin() )
2485 GetWin()->Invalidate();
2486 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2487 if( Imp()->IsAccessible() )
2488 Imp()->InvalidateAccessibleEditableState( false );
2489 #endif
2492 void SwViewShell::SetPDFExportOption(bool bSet)
2494 if( bSet != mpOpt->IsPDFExport() )
2496 if( bSet && mpOpt->getBrowseMode() )
2497 mpOpt->SetPrtFormat( true );
2498 mpOpt->SetPDFExport(bSet);
2502 void SwViewShell::SetReadonlySelectionOption(bool bSet)
2504 if( bSet != mpOpt->IsSelectionInReadonly() )
2506 mpOpt->SetSelectionInReadonly(bSet);
2510 void SwViewShell::SetPrtFormatOption( bool bSet )
2512 mpOpt->SetPrtFormat( bSet );
2515 void SwViewShell::UISizeNotify()
2517 if ( mbDocSizeChgd )
2519 mbDocSizeChgd = false;
2520 bool bOld = bInSizeNotify;
2521 bInSizeNotify = true;
2522 ::SizeNotify( this, GetDocSize() );
2523 bInSizeNotify = bOld;
2527 void SwViewShell::SetRestoreActions(sal_uInt16 nSet)
2529 OSL_ENSURE(!GetRestoreActions()||!nSet, "multiple restore of the Actions ?");
2530 Imp()->SetRestoreActions(nSet);
2532 sal_uInt16 SwViewShell::GetRestoreActions() const
2534 return Imp()->GetRestoreActions();
2537 bool SwViewShell::IsNewLayout() const
2539 return GetLayout()->IsNewLayout();
2542 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2543 uno::Reference< css::accessibility::XAccessible > SwViewShell::CreateAccessible()
2545 uno::Reference< css::accessibility::XAccessible > xAcc;
2547 // We require a layout and an XModel to be accessible.
2548 OSL_ENSURE( mpLayout, "no layout, no access" );
2549 OSL_ENSURE( GetWin(), "no window, no access" );
2551 if( mxDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && GetWin() )
2552 xAcc = Imp()->GetAccessibleMap().GetDocumentView();
2554 return xAcc;
2557 uno::Reference< css::accessibility::XAccessible > SwViewShell::CreateAccessiblePreview()
2559 OSL_ENSURE( IsPreview(),
2560 "Can't create accessible preview for non-preview SwViewShell" );
2562 // We require a layout and an XModel to be accessible.
2563 OSL_ENSURE( mpLayout, "no layout, no access" );
2564 OSL_ENSURE( GetWin(), "no window, no access" );
2566 if ( IsPreview() && GetLayout()&& GetWin() )
2568 return Imp()->GetAccessibleMap().GetDocumentPreview(
2569 PagePreviewLayout()->maPreviewPages,
2570 GetWin()->GetMapMode().GetScaleX(),
2571 GetLayout()->GetPageByPageNum( PagePreviewLayout()->mnSelectedPageNum ),
2572 PagePreviewLayout()->maWinSize );
2574 return nullptr;
2577 void SwViewShell::InvalidateAccessibleFocus()
2579 if( Imp() && Imp()->IsAccessible() )
2580 Imp()->GetAccessibleMap().InvalidateFocus();
2584 * invalidate CONTENT_FLOWS_FROM/_TO relation for paragraphs #i27138#
2586 void SwViewShell::InvalidateAccessibleParaFlowRelation( const SwTextFrame* _pFromTextFrame,
2587 const SwTextFrame* _pToTextFrame )
2589 if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
2591 Imp()->InvalidateAccessibleParaFlowRelation_( _pFromTextFrame, _pToTextFrame );
2596 * invalidate text selection for paragraphs #i27301#
2598 void SwViewShell::InvalidateAccessibleParaTextSelection()
2600 if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
2602 Imp()->InvalidateAccessibleParaTextSelection_();
2607 * invalidate attributes for paragraphs #i88069#
2609 void SwViewShell::InvalidateAccessibleParaAttrs( const SwTextFrame& rTextFrame )
2611 if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
2613 Imp()->InvalidateAccessibleParaAttrs_( rTextFrame );
2617 SwAccessibleMap* SwViewShell::GetAccessibleMap()
2619 if ( Imp()->IsAccessible() )
2621 return &(Imp()->GetAccessibleMap());
2624 return nullptr;
2627 void SwViewShell::ApplyAccessibilityOptions()
2629 if (utl::ConfigManager::IsFuzzing())
2630 return;
2631 if (mpOpt->IsPagePreview() && !officecfg::Office::Common::Accessibility::IsForPagePreviews::get())
2633 mpAccOptions->SetAlwaysAutoColor(false);
2634 mpAccOptions->SetStopAnimatedGraphics(false);
2636 else
2638 mpAccOptions->SetAlwaysAutoColor(SvtAccessibilityOptions::GetIsAutomaticFontColor());
2639 mpAccOptions->SetStopAnimatedGraphics(! SvtAccessibilityOptions::GetIsAllowAnimatedGraphics());
2641 // Form view
2642 // Always set this option, not only if document is read-only:
2643 mpOpt->SetSelectionInReadonly(SvtAccessibilityOptions::IsSelectionInReadonly());
2646 #endif // ENABLE_WASM_STRIP_ACCESSIBILITY
2648 ShellResource* SwViewShell::GetShellRes()
2650 return spShellRes;
2653 void SwViewShell::SetCareDialog(const std::shared_ptr<weld::Window>& rNew)
2655 (*spCareDialog.get()) = rNew;
2658 sal_uInt16 SwViewShell::GetPageCount() const
2660 return GetLayout() ? GetLayout()->GetPageNum() : 1;
2663 Size SwViewShell::GetPageSize( sal_uInt16 nPageNum, bool bSkipEmptyPages ) const
2665 Size aSize;
2666 const SwRootFrame* pTmpRoot = GetLayout();
2667 if( pTmpRoot && nPageNum )
2669 const SwPageFrame* pPage = static_cast<const SwPageFrame*>
2670 (pTmpRoot->Lower());
2672 while( --nPageNum && pPage->GetNext() )
2673 pPage = static_cast<const SwPageFrame*>( pPage->GetNext() );
2675 if( !bSkipEmptyPages && pPage->IsEmptyPage() && pPage->GetNext() )
2676 pPage = static_cast<const SwPageFrame*>( pPage->GetNext() );
2678 aSize = pPage->getFrameArea().SSize();
2680 return aSize;
2683 void SwViewShell::OnGraphicArrived(const SwRect& rRect)
2685 for(SwViewShell& rShell : GetRingContainer())
2687 CurrShell aCurr(&rShell);
2688 if(rShell.IsPreview())
2690 if(rShell.GetWin())
2691 ::RepaintPagePreview(&rShell, rRect);
2693 else if(rShell.VisArea().Overlaps(rRect) && OUTDEV_WINDOW == rShell.GetOut()->GetOutDevType())
2695 // invalidate instead of painting
2696 rShell.GetWin()->Invalidate(rRect.SVRect());
2700 // #i12836# enhanced pdf export
2701 sal_Int32 SwViewShell::GetPageNumAndSetOffsetForPDF( OutputDevice& rOut, const SwRect& rRect ) const
2703 OSL_ENSURE( GetLayout(), "GetPageNumAndSetOffsetForPDF assumes presence of layout" );
2705 sal_Int32 nRet = -1;
2707 // #i40059# Position out of bounds:
2708 SwRect aRect( rRect );
2709 aRect.Pos().setX( std::max( aRect.Left(), GetLayout()->getFrameArea().Left() ) );
2711 const SwPageFrame* pPage = GetLayout()->GetPageAtPos( aRect.Center() );
2712 if ( pPage )
2714 OSL_ENSURE( pPage, "GetPageNumAndSetOffsetForPDF: No page found" );
2716 Point aOffset( pPage->getFrameArea().Pos() );
2717 aOffset.setX( -aOffset.X() );
2718 aOffset.setY( -aOffset.Y() );
2720 MapMode aMapMode( rOut.GetMapMode() );
2721 aMapMode.SetOrigin( aOffset );
2722 rOut.SetMapMode( aMapMode );
2724 nRet = pPage->GetPhyPageNum() - 1;
2727 return nRet;
2730 // --> PB 2007-05-30 #146850#
2731 const BitmapEx& SwViewShell::GetReplacementBitmap( bool bIsErrorState )
2733 if (bIsErrorState)
2735 if (!m_xErrorBmp)
2736 m_xErrorBmp.reset(new BitmapEx(RID_GRAPHIC_ERRORBMP));
2737 return *m_xErrorBmp;
2740 if (!m_xReplaceBmp)
2741 m_xReplaceBmp.reset(new BitmapEx(RID_GRAPHIC_REPLACEBMP));
2742 return *m_xReplaceBmp;
2745 void SwViewShell::DeleteReplacementBitmaps()
2747 m_xErrorBmp.reset();
2748 m_xReplaceBmp.reset();
2751 SwPostItMgr* SwViewShell::GetPostItMgr()
2753 SwView* pView = GetDoc()->GetDocShell() ? GetDoc()->GetDocShell()->GetView() : nullptr;
2754 if ( pView )
2755 return pView->GetPostItMgr();
2757 return nullptr;
2760 void SwViewShell::GetFirstLastVisPageNumbers(SwVisiblePageNumbers& rVisiblePageNumbers)
2762 SwView* pView = GetDoc()->GetDocShell() ? GetDoc()->GetDocShell()->GetView() : nullptr;
2763 if (!pView)
2764 return;
2765 SwRect rViewVisArea(pView->GetVisArea());
2766 vcl::RenderContext* pRenderContext = GetOut();
2767 const SwPageFrame* pPageFrame = Imp()->GetFirstVisPage(pRenderContext);
2768 SwRect rPageRect = pPageFrame->getFrameArea();
2769 rPageRect.AddBottom(-pPageFrame->GetBottomMargin());
2770 while (!rPageRect.Overlaps(rViewVisArea) && pPageFrame->GetNext())
2772 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
2773 rPageRect = pPageFrame->getFrameArea();
2774 if (rPageRect.Top() > 0)
2775 rPageRect.AddBottom(-pPageFrame->GetBottomMargin());
2777 rVisiblePageNumbers.nFirstPhy = pPageFrame->GetPhyPageNum();
2778 rVisiblePageNumbers.nFirstVirt = pPageFrame->GetVirtPageNum();
2779 const SvxNumberType& rFirstVisNum = pPageFrame->GetPageDesc()->GetNumType();
2780 rVisiblePageNumbers.sFirstCustomPhy = rFirstVisNum.GetNumStr(rVisiblePageNumbers.nFirstPhy);
2781 rVisiblePageNumbers.sFirstCustomVirt = rFirstVisNum.GetNumStr(rVisiblePageNumbers.nFirstVirt);
2782 pPageFrame = Imp()->GetLastVisPage(pRenderContext);
2783 rPageRect = pPageFrame->getFrameArea();
2784 rPageRect.AddTop(pPageFrame->GetTopMargin());
2785 while (!rPageRect.Overlaps(rViewVisArea) && pPageFrame->GetPrev())
2787 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetPrev());
2788 rPageRect = pPageFrame->getFrameArea();
2789 rPageRect.AddTop(pPageFrame->GetTopMargin());
2791 rVisiblePageNumbers.nLastPhy = pPageFrame->GetPhyPageNum();
2792 rVisiblePageNumbers.nLastVirt = pPageFrame->GetVirtPageNum();
2793 const SvxNumberType& rLastVisNum = pPageFrame->GetPageDesc()->GetNumType();
2794 rVisiblePageNumbers.sLastCustomPhy = rLastVisNum.GetNumStr(rVisiblePageNumbers.nLastPhy);
2795 rVisiblePageNumbers.sLastCustomVirt = rLastVisNum.GetNumStr(rVisiblePageNumbers.nLastVirt);
2799 * Document Interface Access
2801 const IDocumentSettingAccess& SwViewShell::getIDocumentSettingAccess() const { return mxDoc->GetDocumentSettingManager(); }
2802 IDocumentSettingAccess& SwViewShell::getIDocumentSettingAccess() { return mxDoc->GetDocumentSettingManager(); }
2803 const IDocumentDeviceAccess& SwViewShell::getIDocumentDeviceAccess() const { return mxDoc->getIDocumentDeviceAccess(); }
2804 IDocumentDeviceAccess& SwViewShell::getIDocumentDeviceAccess() { return mxDoc->getIDocumentDeviceAccess(); }
2805 const IDocumentMarkAccess* SwViewShell::getIDocumentMarkAccess() const { return mxDoc->getIDocumentMarkAccess(); }
2806 IDocumentMarkAccess* SwViewShell::getIDocumentMarkAccess() { return mxDoc->getIDocumentMarkAccess(); }
2807 const IDocumentDrawModelAccess& SwViewShell::getIDocumentDrawModelAccess() const { return mxDoc->getIDocumentDrawModelAccess(); }
2808 IDocumentDrawModelAccess& SwViewShell::getIDocumentDrawModelAccess() { return mxDoc->getIDocumentDrawModelAccess(); }
2809 const IDocumentRedlineAccess& SwViewShell::getIDocumentRedlineAccess() const { return mxDoc->getIDocumentRedlineAccess(); }
2810 IDocumentRedlineAccess& SwViewShell::getIDocumentRedlineAccess() { return mxDoc->getIDocumentRedlineAccess(); }
2811 const IDocumentLayoutAccess& SwViewShell::getIDocumentLayoutAccess() const { return mxDoc->getIDocumentLayoutAccess(); }
2812 IDocumentLayoutAccess& SwViewShell::getIDocumentLayoutAccess() { return mxDoc->getIDocumentLayoutAccess(); }
2813 IDocumentContentOperations& SwViewShell::getIDocumentContentOperations() { return mxDoc->getIDocumentContentOperations(); }
2814 IDocumentStylePoolAccess& SwViewShell::getIDocumentStylePoolAccess() { return mxDoc->getIDocumentStylePoolAccess(); }
2815 const IDocumentStatistics& SwViewShell::getIDocumentStatistics() const { return mxDoc->getIDocumentStatistics(); }
2817 IDocumentUndoRedo & SwViewShell::GetIDocumentUndoRedo()
2818 { return mxDoc->GetIDocumentUndoRedo(); }
2819 IDocumentUndoRedo const& SwViewShell::GetIDocumentUndoRedo() const
2820 { return mxDoc->GetIDocumentUndoRedo(); }
2822 // --> OD 2007-11-14 #i83479#
2823 const IDocumentListItems* SwViewShell::getIDocumentListItemsAccess() const
2825 return &mxDoc->getIDocumentListItems();
2828 const IDocumentOutlineNodes* SwViewShell::getIDocumentOutlineNodesAccess() const
2830 return &mxDoc->getIDocumentOutlineNodes();
2833 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */