LibreOffice Module sw (master) 1
layact.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <config_feature_desktop.h>
21#include <config_wasm_strip.h>
22
23#include <ctime>
24#include <rootfrm.hxx>
25#include <pagefrm.hxx>
26#include <viewimp.hxx>
27#include <crsrsh.hxx>
28#include <dflyobj.hxx>
29#include <frmatr.hxx>
30#include <frmtool.hxx>
31#include <viewopt.hxx>
32#include <dbg_lay.hxx>
33#include <layouter.hxx>
34#include <docstat.hxx>
35#include <swevent.hxx>
39
40#include <sfx2/event.hxx>
41
42#include <ftnidx.hxx>
43#include <vcl/svapp.hxx>
44#include <editeng/opaqitem.hxx>
45#include <SwSmartTagMgr.hxx>
46#include <sal/log.hxx>
47
48#include <layact.hxx>
49#include <swwait.hxx>
50#include <fmtsrnd.hxx>
51#include <docsh.hxx>
52
54#include <ndtxt.hxx>
55#include <tabfrm.hxx>
56#include <ftnfrm.hxx>
57#include <txtfrm.hxx>
58#include <notxtfrm.hxx>
59#include <flyfrms.hxx>
60#include <mdiexp.hxx>
61#include <sectfrm.hxx>
62#include <acmplwrd.hxx>
63#include <deletelistener.hxx>
64#include <sortedobjs.hxx>
65#include <objectformatter.hxx>
66#include <fntcache.hxx>
67#include <fmtanchr.hxx>
69#include <vector>
71
73{
74 if (IsReschedule())
75 {
77 }
78 if ( !m_pWait && IsWaitAllowed() && IsPaint() &&
79 ((std::clock() - m_nStartTicks) * 1000 / CLOCKS_PER_SEC >= CLOCKS_PER_SEC/2) )
80 {
81 m_pWait.reset( new SwWait( *m_pRoot->GetFormat()->GetDoc()->GetDocShell(), true ) );
82 }
83}
84
85// Time over already?
87{
88 if (!IsInterrupt())
90}
91
92void SwLayAction::SetStatBar( bool bNew )
93{
94 if ( bNew )
95 {
97 m_nEndPage += m_nEndPage * 10 / 100;
98 }
99 else
100 m_nEndPage = USHRT_MAX;
101}
102
104 const SwPageFrame *pPage )
105{
106 SwRegionRects aTmp( rRect );
107 const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
108 const SwFlyFrame *pSelfFly = pCnt->FindFlyFrame();
109
110 for ( size_t i = 0; i < rObjs.size() && !aTmp.empty(); ++i )
111 {
112 SwVirtFlyDrawObj *pVirtFly = dynamic_cast<SwVirtFlyDrawObj*>(rObjs[i]->DrawObj());
113 if ( !pVirtFly )
114 continue;
115
116 // do not consider invisible objects
118 if ( !rIDDMA.IsVisibleLayerId( pVirtFly->GetLayer() ) )
119 {
120 continue;
121 }
122
123 SwFlyFrame *pFly = pVirtFly->GetFlyFrame();
124
125 if ( pFly == pSelfFly || !rRect.Overlaps( pFly->getFrameArea() ) )
126 continue;
127
128 if ( pSelfFly && pSelfFly->IsLowerOf( pFly ) )
129 continue;
130
131 if ( pFly->GetVirtDrawObj()->GetLayer() == rIDDMA.GetHellId() )
132 continue;
133
134 if ( pSelfFly )
135 {
136 const SdrObject *pTmp = pSelfFly->GetVirtDrawObj();
137 if ( pVirtFly->GetLayer() == pTmp->GetLayer() )
138 {
139 if ( pVirtFly->GetOrdNumDirect() < pTmp->GetOrdNumDirect() )
140 // Only look at things above us, if inside the same layer
141 continue;
142 }
143 else
144 {
145 const bool bLowerOfSelf = pFly->IsLowerOf( pSelfFly );
146 if ( !bLowerOfSelf && !pFly->GetFormat()->GetOpaque().GetValue() )
147 // Things from other layers are only interesting to us if
148 // they're not transparent or lie inwards
149 continue;
150 }
151 }
152
153 // Fly frame without a lower have to be subtracted from paint region.
154 // For checking, if fly frame contains transparent graphic or
155 // has surrounded contour, assure that fly frame has a lower
156 if ( pFly->Lower() &&
157 pFly->Lower()->IsNoTextFrame() &&
158 ( static_cast<SwNoTextFrame*>(pFly->Lower())->IsTransparent() ||
159 pFly->GetFormat()->GetSurround().IsContour() )
160 )
161 {
162 continue;
163 }
164
165 // vcl::Region of a fly frame with transparent background or a transparent
166 // shadow have not to be subtracted from paint region
167 if ( pFly->IsBackgroundTransparent() )
168 {
169 continue;
170 }
171
172 aTmp -= pFly->getFrameArea();
173 }
174
175 bool bRetPaint = false;
176 for ( const auto& rRegionRect : aTmp )
177 bRetPaint |= m_pImp->GetShell()->AddPaintRect( rRegionRect );
178 return bRetPaint;
179}
180
181inline bool SwLayAction::PaintContent_( const SwContentFrame *pContent,
182 const SwPageFrame *pPage,
183 const SwRect &rRect )
184{
185 if ( rRect.HasArea() )
186 {
187 if ( pPage->GetSortedObjs() )
188 return PaintWithoutFlys( rRect, pContent, pPage );
189 else
190 return m_pImp->GetShell()->AddPaintRect( rRect );
191 }
192 return false;
193}
194
200 const SwPageFrame *pPage,
201 const SwRect &rOldRect,
202 tools::Long nOldBottom )
203{
204 SwRectFnSet aRectFnSet(pCnt);
205
206 if ( pCnt->IsCompletePaint() || !pCnt->IsTextFrame() )
207 {
208 SwRect aPaint( pCnt->GetPaintArea() );
209 if ( !PaintContent_( pCnt, pPage, aPaint ) )
210 pCnt->ResetCompletePaint();
211 }
212 else
213 {
214 // paint the area between printing bottom and frame bottom and
215 // the area left and right beside the frame, if its height changed.
216 tools::Long nOldHeight = aRectFnSet.GetHeight(rOldRect);
217 tools::Long nNewHeight = aRectFnSet.GetHeight(pCnt->getFrameArea());
218 const bool bHeightDiff = nOldHeight != nNewHeight;
219 if( bHeightDiff )
220 {
221 // consider whole potential paint area.
222 SwRect aDrawRect( pCnt->GetPaintArea() );
223 if( nOldHeight > nNewHeight )
224 nOldBottom = aRectFnSet.GetPrtBottom(*pCnt);
225 aRectFnSet.SetTop( aDrawRect, nOldBottom );
226 PaintContent_( pCnt, pPage, aDrawRect );
227 }
228 // paint content area
229 SwRect aPaintRect = static_cast<SwTextFrame*>(const_cast<SwContentFrame*>(pCnt))->GetPaintSwRect();
230 PaintContent_( pCnt, pPage, aPaintRect );
231 }
232
233 if ( !pCnt->IsRetouche() || pCnt->GetNext() )
234 return;
235
236 const SwFrame *pTmp = pCnt;
237 if( pCnt->IsInSct() )
238 {
239 const SwSectionFrame* pSct = pCnt->FindSctFrame();
240 if( pSct->IsRetouche() && !pSct->GetNext() )
241 pTmp = pSct;
242 }
243 SwRect aRect( pTmp->GetUpper()->GetPaintArea() );
244 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pTmp) );
245 if ( !PaintContent_( pCnt, pPage, aRect ) )
246 pCnt->ResetRetouche();
247}
248
250 m_pRoot( pRt ),
251 m_pImp( pI ),
252 m_pOptTab( nullptr ),
253 m_nPreInvaPage( USHRT_MAX ),
254 m_nStartTicks( std::clock() ),
255 m_nInputType( VclInputFlags::NONE ),
256 m_nEndPage( USHRT_MAX ),
257 m_nCheckPageNum( USHRT_MAX )
258{
263 // init new flag <mbFormatContentOnInterrupt>.
265
266 assert(!m_pImp->m_pLayAction); // there can be only one SwLayAction
267 m_pImp->m_pLayAction = this; // register there
268}
269
271{
272 OSL_ENSURE( !m_pWait, "Wait object not destroyed" );
273 m_pImp->m_pLayAction = nullptr; // unregister
274}
275
277{
278 SetAgain(false);
279 m_pOptTab = nullptr;
280 m_nStartTicks = std::clock();
281 m_nInputType = VclInputFlags::NONE;
286}
287
289{
290 // switching from the normal to the browser mode, empty pages may be
291 // retained for an annoyingly long time, so delete them here
292 bool bRet = false;
293 const SwViewShell *pSh = m_pRoot->GetCurrShell();
294 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
295 {
296 SwPageFrame *pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
297 do
298 {
299 if ( (pPage->GetSortedObjs() && pPage->GetSortedObjs()->size()) ||
300 pPage->ContainsContent() ||
301 pPage->FindFootnoteCont() )
302 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
303 else
304 {
305 bRet = true;
306 SwPageFrame *pDel = pPage;
307 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
308 pDel->Cut();
310 }
311 } while ( pPage );
312 }
313 return bRet;
314}
315
316void SwLayAction::SetAgain(bool bAgain)
317{
318 if (bAgain == m_bAgain)
319 return;
320
321 m_bAgain = bAgain;
322
323 assert(m_aFrameStack.size() == m_aFrameDeleteGuards.size());
324 size_t nCount = m_aFrameStack.size();
325 if (m_bAgain)
326 {
327 // LayAction::FormatLayout is now flagged to exit early and will avoid
328 // dereferencing any SwFrames in the stack of FormatLayouts so allow
329 // their deletion
330 for (size_t i = 0; i < nCount; ++i)
331 m_aFrameDeleteGuards[i].reset();
332 }
333 else
334 {
335 // LayAction::FormatLayout is now continue normally and will
336 // dereference the top SwFrame in the stack of m_aFrameStack as each
337 // FormatLevel returns so disallow their deletion
338 for (size_t i = 0; i < nCount; ++i)
339 m_aFrameDeleteGuards[i] = std::make_unique<SwFrameDeleteGuard>(m_aFrameStack[i]);
340 }
341}
342
344{
345 /* Workaround crash seen in crashtesting with fdo53985-1.docx
346
347 Lock pLow against getting deleted when it will be dereferenced
348 after FormatLayout
349
350 If SetAgain is called to make SwLayAction exit early to avoid that
351 dereference, then it clears these guards
352 */
353 m_aFrameStack.push_back(pLow);
354 m_aFrameDeleteGuards.push_back(std::make_unique<SwFrameDeleteGuard>(pLow));
355}
356
358{
359 m_aFrameDeleteGuards.pop_back();
360 m_aFrameStack.pop_back();
361}
362
364{
365 m_bActionInProgress = true;
366
367 //TurboMode? Hands-off during idle-format
368 if ( IsPaint() && !IsIdle() && TurboAction() )
369 {
370 m_pWait.reset();
372 m_bActionInProgress = false;
374 return;
375 }
376 else if ( m_pRoot->GetTurbo() )
377 {
379 const SwFrame *pFrame = m_pRoot->GetTurbo();
381 pFrame->InvalidatePage();
382 }
384
385 if ( IsCalcLayout() )
386 SetCheckPages( false );
387
388 InternalAction(pRenderContext);
390 SetAgain(true);
391 while ( IsAgain() )
392 {
393 SetAgain(false);
394 m_bNextCycle = false;
395 InternalAction(pRenderContext);
397 SetAgain(true);
398 }
400
401 m_pWait.reset();
402
403 //Turbo-Action permitted again for all cases.
406
407 SetCheckPages( true );
408
409 m_bActionInProgress = false;
410}
411
413{
414 SwContentFrame *pCnt = pPage->FindFirstBodyContent();
415 SwContentFrame *pChk = pCnt;
416 bool bPageChgd = false;
417 while ( pCnt && pCnt->IsFollow() )
418 pCnt = pCnt->FindMaster();
419 if ( pCnt && pChk != pCnt )
420 { bPageChgd = true;
421 pPage = pCnt->FindPageFrame();
422 }
423
424 if ( !pPage->GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
425 {
426 SwFootnoteContFrame *pCont = pPage->FindFootnoteCont();
427 if ( pCont )
428 {
429 pCnt = pCont->ContainsContent();
430 pChk = pCnt;
431 while ( pCnt && pCnt->IsFollow() )
432 pCnt = static_cast<SwContentFrame*>(pCnt->FindPrev());
433 if ( pCnt && pCnt != pChk )
434 {
435 if ( bPageChgd )
436 {
437 // Use the 'topmost' page
438 SwPageFrame *pTmp = pCnt->FindPageFrame();
439 if ( pPage->GetPhyPageNum() > pTmp->GetPhyPageNum() )
440 pPage = pTmp;
441 }
442 else
443 pPage = pCnt->FindPageFrame();
444 }
445 }
446 }
447 return pPage;
448}
449
450// unlock position on start and end of page
451// layout process.
452static void unlockPositionOfObjects( SwPageFrame *pPageFrame )
453{
454 assert( pPageFrame );
455
456 SwSortedObjs* pObjs = pPageFrame->GetSortedObjs();
457 if ( pObjs )
458 {
459 for (SwAnchoredObject* pObj : *pObjs)
460 {
461 pObj->UnlockPosition();
462 }
463 }
464}
465
467{
468 OSL_ENSURE( m_pRoot->Lower()->IsPageFrame(), ":-( No page below the root.");
469
470 m_pRoot->Calc(pRenderContext);
471
472 // Figure out the first invalid page or the first one to be formatted,
473 // respectively. A complete-action means the first invalid page.
474 // However, the first page to be formatted might be the one having the
475 // number 1. If we're doing a fake formatting, the number of the first
476 // page is the number of the first visible page.
477 SwPageFrame *pPage = IsComplete() ? static_cast<SwPageFrame*>(m_pRoot->Lower()) :
478 m_pImp->GetFirstVisPage(pRenderContext);
479 if ( !pPage )
480 pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
481
482 // If there's a first-flow-Content in the first visible page that's also a Follow,
483 // we switch the page back to the original master of that Content.
484 if ( !IsComplete() )
485 pPage = CheckFirstVisPage( pPage );
486 sal_uInt16 nFirstPageNum = pPage->GetPhyPageNum();
487
488 while ( pPage && !pPage->IsInvalid() && !pPage->IsInvalidFly() )
489 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
490
492 const bool bNoLoop = pPage && SwLayouter::StartLoopControl(m_pRoot->GetFormat()->GetDoc(), pPage);
493 sal_uInt16 nPercentPageNum = 0;
494
495 auto lcl_isLayoutLooping = [&]()
496 {
497 const bool bAgain = this->IsAgain();
498 if (bAgain && bNoLoop)
499 rLayoutAccess.GetLayouter()->EndLoopControl();
500 return bAgain;
501 };
502
503 int nOuterLoopControlRuns = 0;
504 const int nOutermoopControlMax = 10000;
505 while ( (pPage && !IsInterrupt()) || m_nCheckPageNum != USHRT_MAX )
506 {
507 // Fix infinite loop in sw_ooxmlexport17 unit test
508 // When running the sw_ooxmlexport17 unit test on slower macOS Intel
509 // machines, This loop will never end even after 1M+ loops so set a
510 // maximum number of loops like is done in the nested while loops.
511 if (++nOuterLoopControlRuns > nOutermoopControlMax)
512 {
513 SAL_WARN("sw", "SwLayAction::InternalAction has run too many loops");
514 m_bInterrupt = true;
515 }
516
517 // note: this is the only place that consumes and resets m_nCheckPageNum
518 if ((IsInterrupt() || !pPage) && m_nCheckPageNum != USHRT_MAX)
519 {
520 if (!pPage || m_nCheckPageNum < pPage->GetPhyPageNum())
521 {
522 SwPageFrame *pPg = static_cast<SwPageFrame*>(m_pRoot->Lower());
523 while (pPg && pPg->GetPhyPageNum() < m_nCheckPageNum)
524 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
525 if (pPg)
526 pPage = pPg;
527 if (!pPage)
528 break;
529 }
530
531 SwPageFrame *pTmp = pPage->GetPrev() ?
532 static_cast<SwPageFrame*>(pPage->GetPrev()) : pPage;
533 SetCheckPages( true );
534 SwFrame::CheckPageDescs( pPage, true, &pTmp );
535 SetCheckPages( false );
536 m_nCheckPageNum = USHRT_MAX;
537 pPage = pTmp;
538 continue;
539 }
540
541 if ( m_nEndPage != USHRT_MAX && pPage->GetPhyPageNum() > nPercentPageNum )
542 {
543 nPercentPageNum = pPage->GetPhyPageNum();
544 ::SetProgressState( nPercentPageNum, m_pImp->GetShell()->GetDoc()->GetDocShell());
545 }
546 m_pOptTab = nullptr;
547
548 // No Shortcut for Idle or CalcLayout
549 const bool bTakeShortcut = !IsIdle() && !IsComplete() && IsShortCut(pPage);
550
553 if (lcl_isLayoutLooping()) return;
554
555 if (!bTakeShortcut)
556 {
557 while ( !IsInterrupt() && !IsNextCycle() &&
558 ((pPage->GetSortedObjs() && pPage->IsInvalidFly()) || pPage->IsInvalid()) )
559 {
561
562 SwObjectFormatter::FormatObjsAtFrame( *pPage, *pPage, this );
563 if ( !pPage->GetSortedObjs() )
564 {
565 // If there are no (more) Flys, the flags are superfluous.
566 pPage->ValidateFlyLayout();
567 pPage->ValidateFlyContent();
568 }
569 // change condition
570 while ( !IsInterrupt() && !IsNextCycle() &&
571 ( pPage->IsInvalid() ||
572 (pPage->GetSortedObjs() && pPage->IsInvalidFly()) ) )
573 {
574 PROTOCOL( pPage, PROT::FileInit, DbgAction::NONE, nullptr)
575 if (lcl_isLayoutLooping()) return;
576
577 // new loop control
578 int nLoopControlRuns_1 = 0;
579 const int nLoopControlMax = 20;
580
581 while ( !IsNextCycle() && pPage->IsInvalidLayout() )
582 {
583 pPage->ValidateLayout();
584
585 if ( ++nLoopControlRuns_1 > nLoopControlMax )
586 {
587 OSL_FAIL( "LoopControl_1 in SwLayAction::InternalAction" );
588 break;
589 }
590
591 FormatLayout( pRenderContext, pPage );
592 if (lcl_isLayoutLooping()) return;
593 }
594 // change condition
595 if ( !IsNextCycle() &&
596 ( pPage->IsInvalidContent() ||
597 (pPage->GetSortedObjs() && pPage->IsInvalidFly()) ) )
598 {
599 pPage->ValidateFlyInCnt();
600 pPage->ValidateContent();
601 pPage->ValidateFlyLayout();
602 pPage->ValidateFlyContent();
603 if ( !FormatContent( pPage ) )
604 {
605 if (lcl_isLayoutLooping()) return;
606 pPage->InvalidateContent();
607 pPage->InvalidateFlyInCnt();
608 pPage->InvalidateFlyLayout();
609 pPage->InvalidateFlyContent();
610 if ( IsBrowseActionStop() )
611 m_bInterrupt = true;
612 }
613 }
614 if( bNoLoop )
615 rLayoutAccess.GetLayouter()->LoopControl( pPage );
616 }
617
619 }
620
621 // A previous page may be invalid again.
622 if (lcl_isLayoutLooping()) return;
623 if ( !pPage->GetSortedObjs() )
624 {
625 // If there are no (more) Flys, the flags are superfluous.
626 pPage->ValidateFlyLayout();
627 pPage->ValidateFlyContent();
628 }
629 if ( !IsInterrupt() )
630 {
631 SetNextCycle( false );
632
633 if ( m_nPreInvaPage != USHRT_MAX )
634 {
635 if( !IsComplete() && m_nPreInvaPage + 2 < nFirstPageNum )
636 {
638 SwPageFrame *pTmpPage = m_pImp->GetFirstVisPage(pRenderContext);
639 nFirstPageNum = pTmpPage->GetPhyPageNum();
640 if( m_nPreInvaPage < nFirstPageNum )
641 {
642 m_nPreInvaPage = nFirstPageNum;
643 pPage = pTmpPage;
644 }
645 }
646 while ( pPage->GetPrev() && pPage->GetPhyPageNum() > m_nPreInvaPage )
647 pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
648 m_nPreInvaPage = USHRT_MAX;
649 }
650
651 while ( pPage->GetPrev() &&
652 ( static_cast<SwPageFrame*>(pPage->GetPrev())->IsInvalid() ||
653 ( static_cast<SwPageFrame*>(pPage->GetPrev())->GetSortedObjs() &&
654 static_cast<SwPageFrame*>(pPage->GetPrev())->IsInvalidFly())) &&
655 (static_cast<SwPageFrame*>(pPage->GetPrev())->GetPhyPageNum() >=
656 nFirstPageNum) )
657 {
658 pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
659 }
660
661 // Continue to the next invalid page
662 while ( pPage && !pPage->IsInvalid() &&
663 (!pPage->GetSortedObjs() || !pPage->IsInvalidFly()) )
664 {
665 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
666 }
667 if( bNoLoop )
668 rLayoutAccess.GetLayouter()->LoopControl( pPage );
669 }
670 CheckIdleEnd();
671 }
672
673 if ((bTakeShortcut || !pPage) && !IsInterrupt() &&
675 {
676 // tdf#139426 allow suppression of AssertFlyPages
678 {
680 }
681 if ( m_pRoot->IsSuperfluous() )
682 {
683 bool bOld = IsAgain();
685 SetAgain(bOld);
686 }
687 if (lcl_isLayoutLooping()) return;
688 pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
689 while ( pPage && !pPage->IsInvalid() && !pPage->IsInvalidFly() )
690 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
691 while ( pPage && pPage->GetNext() &&
692 pPage->GetPhyPageNum() < nFirstPageNum )
693 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
694 }
695 else if (bTakeShortcut)
696 break;
697 }
698 if ( IsInterrupt() && pPage )
699 {
700 // If we have input, we don't want to format content anymore, but
701 // we still should clean the layout.
702 // Otherwise, the following situation might arise:
703 // The user enters some text at the end of the paragraph of the last
704 // page, causing the paragraph to create a Follow for the next page.
705 // Meanwhile the user continues typing, so we have input while
706 // still formatting.
707 // The paragraph on the new page has already been partially formatted,
708 // and the new page has been fully formatted and is set to CompletePaint,
709 // but hasn't added itself to the area to be output. Then we paint,
710 // the CompletePaint of the page is reset because the new paragraph
711 // already added itself, but the borders of the page haven't been painted
712 // yet.
713 // Oh well, with the inevitable following LayAction, the page doesn't
714 // register itself, because it's (LayoutFrame) flags have been reset
715 // already - the border of the page will never be painted.
716 SwPageFrame *pPg = pPage;
717 if (lcl_isLayoutLooping()) return;
718 const SwRect &rVis = m_pImp->GetShell()->VisArea();
719
720 while( pPg && pPg->getFrameArea().Bottom() < rVis.Top() )
721 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
722 if( pPg != pPage )
723 pPg = pPg ? static_cast<SwPageFrame*>(pPg->GetPrev()) : pPage;
724
725 // set flag for interrupt content formatting
727 tools::Long nBottom = rVis.Bottom();
728 // #i42586# - format current page, if idle action is active
729 // This is an optimization for the case that the interrupt is created by
730 // the move of a form control object, which is represented by a window.
731 while ( pPg && ( pPg->getFrameArea().Top() < nBottom ||
732 ( IsIdle() && pPg == pPage ) ) )
733 {
735
736 if (lcl_isLayoutLooping()) return;
737
738 // new loop control
739 int nLoopControlRuns_2 = 0;
740 const int nLoopControlMax = 20;
741
742 // special case: interrupt content formatting
743 // conditions are incorrect and are too strict.
744 // adjust interrupt formatting to normal page formatting - see above.
745 while ( ( mbFormatContentOnInterrupt &&
746 ( pPg->IsInvalid() ||
747 ( pPg->GetSortedObjs() && pPg->IsInvalidFly() ) ) ) ||
749 {
750 if (lcl_isLayoutLooping()) return;
751 // format also at-page anchored objects
752 SwObjectFormatter::FormatObjsAtFrame( *pPg, *pPg, this );
753 if ( !pPg->GetSortedObjs() )
754 {
755 pPg->ValidateFlyLayout();
756 pPg->ValidateFlyContent();
757 }
758
759 // new loop control
760 int nLoopControlRuns_3 = 0;
761
762 while ( pPg->IsInvalidLayout() )
763 {
764 pPg->ValidateLayout();
765
766 if ( ++nLoopControlRuns_3 > nLoopControlMax )
767 {
768 OSL_FAIL( "LoopControl_3 in Interrupt formatting in SwLayAction::InternalAction" );
769 break;
770 }
771
772 FormatLayout( pRenderContext, pPg );
773 if (lcl_isLayoutLooping()) return;
774 }
775
777 ( pPg->IsInvalidContent() ||
778 ( pPg->GetSortedObjs() && pPg->IsInvalidFly() ) ) )
779 {
780 pPg->ValidateFlyInCnt();
781 pPg->ValidateContent();
782 pPg->ValidateFlyLayout();
783 pPg->ValidateFlyContent();
784
785 if ( ++nLoopControlRuns_2 > nLoopControlMax )
786 {
787 OSL_FAIL( "LoopControl_2 in Interrupt formatting in SwLayAction::InternalAction" );
788 break;
789 }
790
791 if ( !FormatContent( pPg ) )
792 {
793 if (lcl_isLayoutLooping()) return;
794 pPg->InvalidateContent();
795 pPg->InvalidateFlyInCnt();
796 pPg->InvalidateFlyLayout();
798 }
799 // we are satisfied if the content is formatted once complete.
800 else
801 {
802 break;
803 }
804 }
805 }
806
808 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
809 }
810 // reset flag for special interrupt content formatting.
812 }
813 m_pOptTab = nullptr;
814 if( bNoLoop )
815 rLayoutAccess.GetLayouter()->EndLoopControl();
816}
817
819{
820
821 const SwPageFrame *pPage = nullptr;
822 if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() || pCnt->IsRetouche() )
823 {
824 const SwRect aOldRect( pCnt->UnionFrame( true ) );
825 const tools::Long nOldBottom = pCnt->getFrameArea().Top() + pCnt->getFramePrintArea().Bottom();
826 pCnt->Calc(m_pImp->GetShell()->GetOut());
827 if ( pCnt->getFrameArea().Bottom() < aOldRect.Bottom() )
828 pCnt->SetRetouche();
829
830 pPage = pCnt->FindPageFrame();
831 PaintContent( pCnt, pPage, aOldRect, nOldBottom );
832
833 if ( !pCnt->GetValidLineNumFlag() && pCnt->IsTextFrame() )
834 {
835 const sal_Int32 nAllLines = static_cast<const SwTextFrame*>(pCnt)->GetAllLines();
836 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCnt))->RecalcAllLines();
837 if ( nAllLines != static_cast<const SwTextFrame*>(pCnt)->GetAllLines() )
838 {
839 if ( IsPaintExtraData() )
841 // This is to calculate the remaining LineNums on the page,
842 // and we don't stop processing here. To perform this inside RecalcAllLines
843 // would be expensive, because we would have to notify the page even
844 // in unnecessary cases (normal actions).
845 const SwContentFrame *pNxt = pCnt->GetNextContentFrame();
846 while ( pNxt &&
847 (pNxt->IsInTab() || pNxt->IsInDocBody() != pCnt->IsInDocBody()) )
848 pNxt = pNxt->GetNextContentFrame();
849 if ( pNxt )
850 pNxt->InvalidatePage();
851 }
852 return false;
853 }
854
855 if ( pPage->IsInvalidLayout() || (pPage->GetSortedObjs() && pPage->IsInvalidFly()) )
856 return false;
857 }
858 if ( !pPage )
859 pPage = pCnt->FindPageFrame();
860
861 // format floating screen objects at content frame.
862 if ( pCnt->IsTextFrame() &&
864 *pPage, this ) )
865 {
866 return false;
867 }
868
869 if ( pPage->IsInvalidContent() )
870 return false;
871 return true;
872}
873
875{
876 bool bRet = true;
877
878 if ( m_pRoot->GetTurbo() )
879 {
880 if ( !TurboAction_( m_pRoot->GetTurbo() ) )
881 {
882 CheckIdleEnd();
883 bRet = false;
884 }
886 }
887 else
888 bRet = false;
889 return bRet;
890}
891
892static bool lcl_IsInvaLay( const SwFrame *pFrame, tools::Long nBottom )
893{
894 return !pFrame->isFrameAreaDefinitionValid() ||
895 (pFrame->IsCompletePaint() && ( pFrame->getFrameArea().Top() < nBottom ) );
896}
897
898static const SwFrame *lcl_FindFirstInvaLay( const SwFrame *pFrame, tools::Long nBottom )
899{
900 OSL_ENSURE( pFrame->IsLayoutFrame(), "FindFirstInvaLay, no LayFrame" );
901
902 if (lcl_IsInvaLay(pFrame, nBottom))
903 return pFrame;
904 pFrame = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
905 while ( pFrame )
906 {
907 if ( pFrame->IsLayoutFrame() )
908 {
909 if (lcl_IsInvaLay(pFrame, nBottom))
910 return pFrame;
911 const SwFrame *pTmp = lcl_FindFirstInvaLay( pFrame, nBottom );
912 if ( nullptr != pTmp )
913 return pTmp;
914 }
915 pFrame = pFrame->GetNext();
916 }
917 return nullptr;
918}
919
920static const SwFrame *lcl_FindFirstInvaContent( const SwLayoutFrame *pLay, tools::Long nBottom,
921 const SwContentFrame *pFirst )
922{
923 const SwContentFrame *pCnt = pFirst ? pFirst->GetNextContentFrame() :
924 pLay->ContainsContent();
925 while ( pCnt )
926 {
927 if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() )
928 {
929 if ( pCnt->getFrameArea().Top() <= nBottom )
930 return pCnt;
931 }
932
933 if ( pCnt->GetDrawObjs() )
934 {
935 const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
936 for (SwAnchoredObject* pObj : rObjs)
937 {
938 if ( auto pFly = pObj->DynCastFlyFrame() )
939 {
940 if ( pFly->IsFlyInContentFrame() )
941 {
942 if ( static_cast<const SwFlyInContentFrame*>(pFly)->IsInvalid() ||
943 pFly->IsCompletePaint() )
944 {
945 if ( pFly->getFrameArea().Top() <= nBottom )
946 return pFly;
947 }
948 const SwFrame *pFrame = lcl_FindFirstInvaContent( pFly, nBottom, nullptr );
949 if ( pFrame && pFrame->getFrameArea().Bottom() <= nBottom )
950 return pFrame;
951 }
952 }
953 }
954 }
955 if ( pCnt->getFrameArea().Top() > nBottom && !pCnt->IsInTab() )
956 return nullptr;
957 pCnt = pCnt->GetNextContentFrame();
958 if ( !pLay->IsAnLower( pCnt ) )
959 break;
960 }
961 return nullptr;
962}
963
964// consider drawing objects
966 tools::Long _nBottom )
967{
968 OSL_ENSURE( _pPage->GetSortedObjs(), "FindFirstInvaObj, no Objs" );
969
970 for (SwAnchoredObject* pObj : *_pPage->GetSortedObjs())
971 {
972 if ( auto pFly = pObj->DynCastFlyFrame() )
973 {
974 if ( pFly->getFrameArea().Top() <= _nBottom )
975 {
976 if ( pFly->IsInvalid() || pFly->IsCompletePaint() )
977 return pFly;
978
979 const SwFrame* pTmp;
980 if ( nullptr != (pTmp = lcl_FindFirstInvaContent( pFly, _nBottom, nullptr )) &&
981 pTmp->getFrameArea().Top() <= _nBottom )
982 return pFly;
983 }
984 }
985 else if ( auto pDrawObject = dynamic_cast< const SwAnchoredDrawObject *>( pObj ) )
986 {
987 if ( !pDrawObject->IsValidPos() )
988 {
989 return pObj;
990 }
991 }
992 }
993 return nullptr;
994}
995
996/* Returns True if the page lies directly below or right of the visible area.
997 *
998 * It's possible for things to change in such a way that the processing
999 * (of the caller!) has to continue with the predecessor of the passed page.
1000 * The parameter might therefore get modified!
1001 * For BrowseMode, you may even activate the ShortCut if the invalid content
1002 * of the page lies below the visible area.
1003 */
1005{
1006 vcl::RenderContext* pRenderContext = m_pImp->GetShell()->GetOut();
1007 bool bRet = false;
1008 const SwViewShell *pSh = m_pRoot->GetCurrShell();
1009 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
1010
1011 // If the page is not valid, we quickly format it, otherwise
1012 // there's gonna be no end of trouble
1013 if ( !prPage->isFrameAreaDefinitionValid() )
1014 {
1015 if ( bBrowse )
1016 {
1017 // format complete page
1018 // Thus, loop on all lowers of the page <prPage>, instead of only
1019 // format its first lower.
1020 // NOTE: In online layout (bBrowse == true) a page can contain
1021 // a header frame and/or a footer frame beside the body frame.
1022 prPage->Calc(pRenderContext);
1023 SwFrame* pPageLowerFrame = prPage->Lower();
1024 while ( pPageLowerFrame )
1025 {
1026 pPageLowerFrame->Calc(pRenderContext);
1027 pPageLowerFrame = pPageLowerFrame->GetNext();
1028 }
1029 }
1030 else
1031 FormatLayout( pSh ? pSh->GetOut() : nullptr, prPage );
1032 if ( IsAgain() )
1033 return false;
1034 }
1035
1036 const SwRect &rVis = m_pImp->GetShell()->VisArea();
1037 if ( (prPage->getFrameArea().Top() >= rVis.Bottom()) ||
1038 (prPage->getFrameArea().Left()>= rVis.Right()) )
1039 {
1040 bRet = true;
1041
1042 // This is going to be a bit nasty: The first ContentFrame of this
1043 // page in the Body text needs formatting; if it changes the page during
1044 // that process, I need to start over a page further back, because we
1045 // have been processing a PageBreak.
1046 // Even more uncomfortable: The next ContentFrame must be formatted,
1047 // because it's possible for empty pages to exist temporarily (for example
1048 // a paragraph across multiple pages gets deleted or reduced in size).
1049
1050 // This is irrelevant for the browser, if the last Cnt above it
1051 // isn't visible anymore.
1052
1053 const SwPageFrame *p2ndPage = prPage;
1054 const SwContentFrame *pContent;
1055 const SwLayoutFrame* pBody = p2ndPage->FindBodyCont();
1056 if( p2ndPage->IsFootnotePage() && pBody )
1057 pBody = static_cast<const SwLayoutFrame*>(pBody->GetNext());
1058 pContent = pBody ? pBody->ContainsContent() : nullptr;
1059 while ( p2ndPage && !pContent )
1060 {
1061 p2ndPage = static_cast<const SwPageFrame*>(p2ndPage->GetNext());
1062 if( p2ndPage )
1063 {
1064 pBody = p2ndPage->FindBodyCont();
1065 if( p2ndPage->IsFootnotePage() && pBody )
1066 pBody = static_cast<const SwLayoutFrame*>(pBody->GetNext());
1067 pContent = pBody ? pBody->ContainsContent() : nullptr;
1068 }
1069 }
1070 if ( pContent )
1071 {
1072 bool bTstCnt = true;
1073 if ( bBrowse )
1074 {
1075 // Is the Cnt before already invisible?
1076 const SwFrame *pLst = pContent;
1077 if ( pLst->IsInTab() )
1078 pLst = pContent->FindTabFrame();
1079 if ( pLst->IsInSct() )
1080 pLst = pContent->FindSctFrame();
1081 pLst = pLst->FindPrev();
1082 if ( pLst &&
1083 (pLst->getFrameArea().Top() >= rVis.Bottom() ||
1084 pLst->getFrameArea().Left()>= rVis.Right()) )
1085 {
1086 bTstCnt = false;
1087 }
1088 }
1089
1090 if ( bTstCnt )
1091 {
1092 // check after each frame calculation,
1093 // if the content frame has changed the page. If yes, no other
1094 // frame calculation is performed
1095 bool bPageChg = false;
1096
1097 if ( pContent->IsInSct() )
1098 {
1099 const SwSectionFrame *pSct = const_cast<SwFrame*>(static_cast<SwFrame const *>(pContent))->ImplFindSctFrame();
1100 if ( !pSct->isFrameAreaDefinitionValid() )
1101 {
1102 pSct->Calc(pRenderContext);
1103 pSct->SetCompletePaint();
1104 if ( IsAgain() )
1105 return false;
1106
1107 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1108 prPage->GetPrev();
1109 }
1110 }
1111
1112 if ( !bPageChg && !pContent->isFrameAreaDefinitionValid() )
1113 {
1114 pContent->Calc(pRenderContext);
1115 pContent->SetCompletePaint();
1116 if ( IsAgain() )
1117 return false;
1118
1119 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1120 prPage->GetPrev();
1121 }
1122
1123 if ( !bPageChg && pContent->IsInTab() )
1124 {
1125 const SwTabFrame *pTab = const_cast<SwFrame*>(static_cast<SwFrame const *>(pContent))->ImplFindTabFrame();
1126 if ( !pTab->isFrameAreaDefinitionValid() )
1127 {
1128 pTab->Calc(pRenderContext);
1129 pTab->SetCompletePaint();
1130 if ( IsAgain() )
1131 return false;
1132
1133 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1134 prPage->GetPrev();
1135 }
1136 }
1137
1138 if ( !bPageChg && pContent->IsInSct() )
1139 {
1140 const SwSectionFrame *pSct = const_cast<SwFrame*>(static_cast<SwFrame const *>(pContent))->ImplFindSctFrame();
1141 if ( !pSct->isFrameAreaDefinitionValid() )
1142 {
1143 pSct->Calc(pRenderContext);
1144 pSct->SetCompletePaint();
1145 if ( IsAgain() )
1146 return false;
1147
1148 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1149 prPage->GetPrev();
1150 }
1151 }
1152
1153 if ( bPageChg )
1154 {
1155 bRet = false;
1156 const SwPageFrame* pTmp = pContent->FindPageFrame();
1157 if ( pTmp->GetPhyPageNum() < prPage->GetPhyPageNum() &&
1158 pTmp->IsInvalid() )
1159 {
1160 prPage = const_cast<SwPageFrame*>(pTmp);
1161 }
1162 else
1163 {
1164 prPage = static_cast<SwPageFrame*>(prPage->GetPrev());
1165 }
1166 }
1167 // no shortcut, if at previous page
1168 // an anchored object is registered, whose anchor is <pContent>.
1169 else if ( prPage->GetPrev() )
1170 {
1171 SwSortedObjs* pObjs =
1172 static_cast<SwPageFrame*>(prPage->GetPrev())->GetSortedObjs();
1173 if ( pObjs )
1174 {
1175 for (SwAnchoredObject* pObj : *pObjs)
1176 {
1177 if ( pObj->GetAnchorFrameContainingAnchPos() == pContent )
1178 {
1179 bRet = false;
1180 break;
1181 }
1182 }
1183 }
1184 }
1185 }
1186 }
1187 }
1188
1189 if ( !bRet && bBrowse )
1190 {
1191 const tools::Long nBottom = rVis.Bottom();
1192 const SwAnchoredObject* pObj( nullptr );
1193 if ( prPage->GetSortedObjs() &&
1194 (prPage->IsInvalidFlyLayout() || prPage->IsInvalidFlyContent()) &&
1195 nullptr != (pObj = lcl_FindFirstInvaObj( prPage, nBottom )) &&
1196 pObj->GetObjRect().Top() <= nBottom )
1197 {
1198 return false;
1199 }
1200 const SwFrame* pFrame( nullptr );
1201 if ( prPage->IsInvalidLayout() &&
1202 nullptr != (pFrame = lcl_FindFirstInvaLay( prPage, nBottom )) &&
1203 pFrame->getFrameArea().Top() <= nBottom )
1204 {
1205 return false;
1206 }
1207 if ( (prPage->IsInvalidContent() || prPage->IsInvalidFlyInCnt()) &&
1208 nullptr != (pFrame = lcl_FindFirstInvaContent( prPage, nBottom, nullptr )) &&
1209 pFrame->getFrameArea().Top() <= nBottom )
1210 {
1211 return false;
1212 }
1213 bRet = true;
1214 }
1215 return bRet;
1216}
1217
1218// introduce support for vertical layout
1219bool SwLayAction::FormatLayout( OutputDevice *pRenderContext, SwLayoutFrame *pLay, bool bAddRect )
1220{
1221 OSL_ENSURE( !IsAgain(), "Attention to the invalid page." );
1222 if ( IsAgain() )
1223 return false;
1224
1225 bool bChanged = false;
1226 bool bAlreadyPainted = false;
1227 // remember frame at complete paint
1228 SwRect aFrameAtCompletePaint;
1229
1230 if ( !pLay->isFrameAreaDefinitionValid() || pLay->IsCompletePaint() )
1231 {
1232 if ( pLay->GetPrev() && !pLay->GetPrev()->isFrameAreaDefinitionValid() )
1233 pLay->GetPrev()->SetCompletePaint();
1234
1235 SwRect aOldFrame( pLay->getFrameArea() );
1236 SwRect aOldRect( aOldFrame );
1237 if( pLay->IsPageFrame() )
1238 {
1239 aOldRect = static_cast<SwPageFrame*>(pLay)->GetBoundRect(pRenderContext);
1240 }
1241
1242 {
1243 SwFrameDeleteGuard aDeleteGuard(pLay);
1244 pLay->Calc(pRenderContext);
1245 }
1246
1247 if ( aOldFrame != pLay->getFrameArea() )
1248 bChanged = true;
1249
1250 bool bNoPaint = false;
1251 if ( pLay->IsPageBodyFrame() &&
1252 pLay->getFrameArea().Pos() == aOldRect.Pos() &&
1253 pLay->Lower() )
1254 {
1255 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
1256 // Limitations because of headers / footers
1257 if( pSh && pSh->GetViewOptions()->getBrowseMode() &&
1258 !( pLay->IsCompletePaint() && pLay->FindPageFrame()->FindFootnoteCont() ) )
1259 bNoPaint = true;
1260 }
1261
1262 if ( !bNoPaint && IsPaint() && bAddRect && (pLay->IsCompletePaint() || bChanged) )
1263 {
1264 SwRect aPaint( pLay->getFrameArea() );
1265 // consider border and shadow for
1266 // page frames -> enlarge paint rectangle correspondingly.
1267 if ( pLay->IsPageFrame() )
1268 {
1269 SwPageFrame* pPageFrame = static_cast<SwPageFrame*>(pLay);
1270 aPaint = pPageFrame->GetBoundRect(pRenderContext);
1271 }
1272
1273 bool bPageInBrowseMode = pLay->IsPageFrame();
1274 if( bPageInBrowseMode )
1275 {
1276 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
1277 if( !pSh || !pSh->GetViewOptions()->getBrowseMode() )
1278 bPageInBrowseMode = false;
1279 }
1280 if( bPageInBrowseMode )
1281 {
1282 // NOTE: no vertical layout in online layout
1283 // Is the change even visible?
1284 if ( pLay->IsCompletePaint() )
1285 {
1286 m_pImp->GetShell()->AddPaintRect( aPaint );
1287 bAddRect = false;
1288 }
1289 else
1290 {
1291 SwRegionRects aRegion( aOldRect );
1292 aRegion -= aPaint;
1293 for ( size_t i = 0; i < aRegion.size(); ++i )
1294 m_pImp->GetShell()->AddPaintRect( aRegion[i] );
1295 aRegion.ChangeOrigin( aPaint );
1296 aRegion.clear();
1297 aRegion.push_back( aPaint );
1298 aRegion -= aOldRect;
1299 for ( size_t i = 0; i < aRegion.size(); ++i )
1300 m_pImp->GetShell()->AddPaintRect( aRegion[i] );
1301 }
1302 }
1303 else
1304 {
1305 m_pImp->GetShell()->AddPaintRect( aPaint );
1306 bAlreadyPainted = true;
1307 // remember frame at complete paint
1308 aFrameAtCompletePaint = pLay->getFrameArea();
1309 }
1310
1311 // provide paint of spacing
1312 // between pages (not only for in online mode).
1313 if ( pLay->IsPageFrame() )
1314 {
1315 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
1316 const SwTwips nHalfDocBorder = pSh ? pSh->GetViewOptions()->GetGapBetweenPages()
1318 const bool bLeftToRightViewLayout = m_pRoot->IsLeftToRightViewLayout();
1319 const bool bPrev = bLeftToRightViewLayout ? pLay->GetPrev() : pLay->GetNext();
1320 const bool bNext = bLeftToRightViewLayout ? pLay->GetNext() : pLay->GetPrev();
1321 SwPageFrame* pPageFrame = static_cast<SwPageFrame*>(pLay);
1322 SwRect aPageRect( pLay->getFrameArea() );
1323
1324 if(pSh)
1325 {
1327 pRenderContext,
1328 aPageRect, pPageFrame->IsLeftShadowNeeded(), pPageFrame->IsRightShadowNeeded(),
1330 }
1331
1332 if ( bPrev )
1333 {
1334 // top
1335 SwRect aSpaceToPrevPage( aPageRect );
1336 aSpaceToPrevPage.Top( aSpaceToPrevPage.Top() - nHalfDocBorder );
1337 aSpaceToPrevPage.Bottom( pLay->getFrameArea().Top() );
1338 if(!aSpaceToPrevPage.IsEmpty())
1339 m_pImp->GetShell()->AddPaintRect( aSpaceToPrevPage );
1340
1341 // left
1342 aSpaceToPrevPage = aPageRect;
1343 aSpaceToPrevPage.Left( aSpaceToPrevPage.Left() - nHalfDocBorder );
1344 aSpaceToPrevPage.Right( pLay->getFrameArea().Left() );
1345 if(!aSpaceToPrevPage.IsEmpty())
1346 m_pImp->GetShell()->AddPaintRect( aSpaceToPrevPage );
1347 }
1348 if ( bNext )
1349 {
1350 // bottom
1351 SwRect aSpaceToNextPage( aPageRect );
1352 aSpaceToNextPage.Bottom( aSpaceToNextPage.Bottom() + nHalfDocBorder );
1353 aSpaceToNextPage.Top( pLay->getFrameArea().Bottom() );
1354 if(!aSpaceToNextPage.IsEmpty())
1355 m_pImp->GetShell()->AddPaintRect( aSpaceToNextPage );
1356
1357 // right
1358 aSpaceToNextPage = aPageRect;
1359 aSpaceToNextPage.Right( aSpaceToNextPage.Right() + nHalfDocBorder );
1360 aSpaceToNextPage.Left( pLay->getFrameArea().Right() );
1361 if(!aSpaceToNextPage.IsEmpty())
1362 m_pImp->GetShell()->AddPaintRect( aSpaceToNextPage );
1363 }
1364 }
1365 }
1366 pLay->ResetCompletePaint();
1367 }
1368
1369 if ( IsPaint() && bAddRect &&
1370 !pLay->GetNext() && pLay->IsRetoucheFrame() && pLay->IsRetouche() )
1371 {
1372 // vertical layout support
1373 SwRectFnSet aRectFnSet(pLay);
1374 SwRect aRect( pLay->GetUpper()->GetPaintArea() );
1375 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pLay) );
1376 if ( !m_pImp->GetShell()->AddPaintRect( aRect ) )
1377 pLay->ResetRetouche();
1378 }
1379
1380 if( bAlreadyPainted )
1381 bAddRect = false;
1382
1384
1385 if ( IsAgain() )
1386 return false;
1387
1388 // Now, deal with the lowers that are LayoutFrames
1389
1390 if ( pLay->IsFootnoteFrame() ) // no LayFrames as Lower
1391 return bChanged;
1392
1393 SwFrame *pLow = pLay->Lower();
1394 bool bTabChanged = false;
1395 while ( pLow && pLow->GetUpper() == pLay )
1396 {
1397 SwFrame* pNext = nullptr;
1398 if ( pLow->IsLayoutFrame() )
1399 {
1400 if ( pLow->IsTabFrame() )
1401 {
1402 // Remember what was the next of the lower. Formatting may move it to the previous
1403 // page, in which case it looses its next.
1404 pNext = pLow->GetNext();
1405
1406 if (pNext && pNext->IsTabFrame())
1407 {
1408 auto pTab = static_cast<SwTabFrame*>(pNext);
1409 if (pTab->IsFollow())
1410 {
1411 // The next frame is a follow of the previous frame, SwTabFrame::Join() will
1412 // delete this one as part of formatting, so forget about it.
1413 pNext = nullptr;
1414 }
1415 }
1416
1417 bTabChanged |= FormatLayoutTab( static_cast<SwTabFrame*>(pLow), bAddRect );
1418 }
1419 // Skip the ones already registered for deletion
1420 else if( !pLow->IsSctFrame() || static_cast<SwSectionFrame*>(pLow)->GetSection() )
1421 {
1422 PushFormatLayout(pLow);
1423 bChanged |= FormatLayout( pRenderContext, static_cast<SwLayoutFrame*>(pLow), bAddRect );
1425 }
1426 }
1427 else if ( m_pImp->GetShell()->IsPaintLocked() )
1428 // Shortcut to minimize the cycles. With Lock, the
1429 // paint is coming either way (primarily for browse)
1430 pLow->OptCalc();
1431
1432 if ( IsAgain() )
1433 return false;
1434 if (!pNext)
1435 {
1436 pNext = pLow->GetNext();
1437 }
1438 pLow = pNext;
1439 }
1440 // add complete frame area as paint area, if frame
1441 // area has been already added and after formatting its lowers the frame area
1442 // is enlarged.
1443 SwRect aBoundRect(pLay->IsPageFrame() ? static_cast<SwPageFrame*>(pLay)->GetBoundRect(pRenderContext) : pLay->getFrameArea() );
1444
1445 if ( bAlreadyPainted &&
1446 ( aBoundRect.Width() > aFrameAtCompletePaint.Width() ||
1447 aBoundRect.Height() > aFrameAtCompletePaint.Height() )
1448 )
1449 {
1450 m_pImp->GetShell()->AddPaintRect( aBoundRect );
1451 }
1452 return bChanged || bTabChanged;
1453}
1454
1456{
1457 vcl::RenderContext* pRenderContext = m_pImp->GetShell()->GetOut();
1458 OSL_ENSURE( !IsAgain(), "Attention to the invalid page." );
1459 if ( IsAgain() )
1460 return;
1461
1462 bool bChanged = false;
1463 bool bAddRect = true;
1464
1465 if ( !pFly->isFrameAreaDefinitionValid() || pFly->IsCompletePaint() || pFly->IsInvalid() )
1466 {
1467 // The Frame has changed, now it's getting formatted.
1468 const SwRect aOldRect( pFly->getFrameArea() );
1469 pFly->Calc(pRenderContext);
1470 bChanged = aOldRect != pFly->getFrameArea();
1471
1472 if ( IsPaint() && (pFly->IsCompletePaint() || bChanged) &&
1473 pFly->getFrameArea().Top() > 0 && pFly->getFrameArea().Left() > 0 )
1475
1476 if ( bChanged )
1477 pFly->Invalidate();
1478 else
1479 pFly->Validate();
1480
1481 bAddRect = false;
1482 pFly->ResetCompletePaint();
1483 }
1484
1485 if ( IsAgain() )
1486 return;
1487
1488 // Now, deal with the lowers that are LayoutFrames
1489 SwFrame *pLow = pFly->Lower();
1490 while ( pLow )
1491 {
1492 if ( pLow->IsLayoutFrame() )
1493 {
1494 if ( pLow->IsTabFrame() )
1495 FormatLayoutTab( static_cast<SwTabFrame*>(pLow), bAddRect );
1496 else
1497 FormatLayout( m_pImp->GetShell()->GetOut(), static_cast<SwLayoutFrame*>(pLow), bAddRect );
1498 }
1499 pLow = pLow->GetNext();
1500 }
1501}
1502
1503// Implement vertical layout support
1504bool SwLayAction::FormatLayoutTab( SwTabFrame *pTab, bool bAddRect )
1505{
1506 OSL_ENSURE( !IsAgain(), "8-) Attention to the invalid page." );
1507 if ( IsAgain() || !pTab->Lower() )
1508 return false;
1509
1510 vcl::RenderContext* pRenderContext = m_pImp->GetShell()->GetOut();
1512 rTimerAccess.BlockIdling();
1513
1514 bool bChanged = false;
1515 bool bPainted = false;
1516
1517 const SwPageFrame *pOldPage = pTab->FindPageFrame();
1518
1519 // vertical layout support
1520 SwRectFnSet aRectFnSet(pTab);
1521
1522 if ( !pTab->isFrameAreaDefinitionValid() || pTab->IsCompletePaint() || pTab->IsComplete() )
1523 {
1524 if ( pTab->GetPrev() && !pTab->GetPrev()->isFrameAreaDefinitionValid() )
1525 {
1526 pTab->GetPrev()->SetCompletePaint();
1527 }
1528
1529 const SwRect aOldRect( pTab->getFrameArea() );
1530 pTab->SetLowersFormatted( false );
1531 pTab->Calc(pRenderContext);
1532 if ( aOldRect != pTab->getFrameArea() )
1533 {
1534 bChanged = true;
1535 }
1536 const SwRect aPaintFrame = pTab->GetPaintArea();
1537
1538 if ( IsPaint() && bAddRect )
1539 {
1540 // add condition <pTab->getFrameArea().HasArea()>
1541 if ( !pTab->IsCompletePaint() &&
1542 pTab->IsComplete() &&
1543 ( pTab->getFrameArea().SSize() != pTab->getFramePrintArea().SSize() ||
1544 // vertical layout support
1545 aRectFnSet.GetLeftMargin(*pTab) ) &&
1546 pTab->getFrameArea().HasArea()
1547 )
1548 {
1549 // re-implement calculation of margin rectangles.
1550 SwRect aMarginRect;
1551
1552 SwTwips nLeftMargin = aRectFnSet.GetLeftMargin(*pTab);
1553 if ( nLeftMargin > 0)
1554 {
1555 aMarginRect = pTab->getFrameArea();
1556 aRectFnSet.SetWidth( aMarginRect, nLeftMargin );
1557 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1558 }
1559
1560 if ( aRectFnSet.GetRightMargin(*pTab) > 0)
1561 {
1562 aMarginRect = pTab->getFrameArea();
1563 aRectFnSet.SetLeft( aMarginRect, aRectFnSet.GetPrtRight(*pTab) );
1564 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1565 }
1566
1567 SwTwips nTopMargin = aRectFnSet.GetTopMargin(*pTab);
1568 if ( nTopMargin > 0)
1569 {
1570 aMarginRect = pTab->getFrameArea();
1571 aRectFnSet.SetHeight( aMarginRect, nTopMargin );
1572 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1573 }
1574
1575 if ( aRectFnSet.GetBottomMargin(*pTab) > 0)
1576 {
1577 aMarginRect = pTab->getFrameArea();
1578 aRectFnSet.SetTop( aMarginRect, aRectFnSet.GetPrtBottom(*pTab) );
1579 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1580 }
1581 }
1582 else if ( pTab->IsCompletePaint() )
1583 {
1584 m_pImp->GetShell()->AddPaintRect( aPaintFrame );
1585 bAddRect = false;
1586 bPainted = true;
1587 }
1588
1589 if ( pTab->IsRetouche() && !pTab->GetNext() )
1590 {
1591 SwRect aRect( pTab->GetUpper()->GetPaintArea() );
1592 // vertical layout support
1593 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pTab) );
1594 if ( !m_pImp->GetShell()->AddPaintRect( aRect ) )
1595 pTab->ResetRetouche();
1596 }
1597 }
1598 else
1599 bAddRect = false;
1600
1601 if ( pTab->IsCompletePaint() && !m_pOptTab )
1602 m_pOptTab = pTab;
1603 pTab->ResetCompletePaint();
1604 }
1605 if ( IsPaint() && bAddRect && pTab->IsRetouche() && !pTab->GetNext() )
1606 {
1607 // set correct rectangle for retouche: area between bottom of table frame
1608 // and bottom of paint area of the upper frame.
1609 SwRect aRect( pTab->GetUpper()->GetPaintArea() );
1610 // vertical layout support
1611 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pTab) );
1612 if ( !m_pImp->GetShell()->AddPaintRect( aRect ) )
1613 pTab->ResetRetouche();
1614 }
1615
1617
1618 rTimerAccess.UnblockIdling();
1619
1620 // Ugly shortcut!
1621 if ( pTab->IsLowersFormatted() &&
1622 (bPainted || !m_pImp->GetShell()->VisArea().Overlaps( pTab->getFrameArea())) )
1623 return false;
1624
1625 // Now, deal with the lowers
1626 if ( IsAgain() )
1627 return false;
1628
1629 // for safety reasons:
1630 // check page number before formatting lowers.
1631 if ( pOldPage->GetPhyPageNum() > (pTab->FindPageFrame()->GetPhyPageNum() + 1) )
1632 SetNextCycle( true );
1633
1634 // format lowers, only if table frame is valid
1635 if ( pTab->isFrameAreaDefinitionValid() )
1636 {
1637 FlowFrameJoinLockGuard tabG(pTab); // tdf#124675 prevent Join() if pTab becomes empty
1638 SwLayoutFrame *pLow = static_cast<SwLayoutFrame*>(pTab->Lower());
1639 while ( pLow )
1640 {
1641 SwFrameDeleteGuard rowG(pLow); // tdf#124675 prevent RemoveFollowFlowLine()
1642 bChanged |= FormatLayout( m_pImp->GetShell()->GetOut(), pLow, bAddRect );
1643 if ( IsAgain() )
1644 return false;
1645 pLow = static_cast<SwLayoutFrame*>(pLow->GetNext());
1646 }
1647 }
1648
1649 return bChanged;
1650}
1651
1653{
1654 ::comphelper::ScopeGuard g([this, pPage]() {
1655 if (IsAgain())
1656 {
1657 return; // pPage probably deleted
1658 }
1659 if (auto const* pObjs = pPage->GetSortedObjs())
1660 {
1661 std::vector<std::pair<SwAnchoredObject*, SwPageFrame*>> moved;
1662 for (auto const pObj : *pObjs)
1663 {
1664 assert(!pObj->AnchorFrame()->IsTextFrame()
1665 || !static_cast<SwTextFrame const*>(pObj->AnchorFrame())->IsFollow());
1666 SwPageFrame *const pAnchorPage(pObj->AnchorFrame()->FindPageFrame());
1667 assert(pAnchorPage);
1668 if (pAnchorPage != pPage
1669 && pPage->GetPhyPageNum() < pAnchorPage->GetPhyPageNum()
1670 && pObj->GetFrameFormat().GetAnchor().GetAnchorId()
1671 != RndStdIds::FLY_AS_CHAR)
1672 {
1673 moved.emplace_back(pObj, pAnchorPage);
1674 }
1675 }
1676 for (auto const& [pObj, pAnchorPage] : moved)
1677 {
1678 SAL_INFO("sw.layout", "SwLayAction::FormatContent: move anchored " << pObj << " from " << pPage->GetPhyPageNum() << " to " << pAnchorPage->GetPhyPageNum());
1679 pObj->RegisterAtPage(*pAnchorPage);
1680 // tdf#143239 if the position remains valid, it may not be
1681 // positioned again so would remain on the wrong page!
1682 pObj->InvalidateObjPos();
1683 ::Notify_Background(pObj->GetDrawObj(), pPage,
1684 pObj->GetObjRect(), PrepareHint::FlyFrameLeave, false);
1685 // tdf#148897 in case the fly moves back to this page before
1686 // being positioned again, the SwFlyNotify / ::Notify() could
1687 // conclude that it didn't move at all and not call
1688 // NotifyBackground(); note: pObj->SetObjTop(FAR_AWAY) results
1689 // in wrong positions, use different approach!
1690 pObj->SetForceNotifyNewBackground(true);
1691 }
1692 if (!moved.empty())
1693 {
1694 pPage->InvalidateFlyLayout();
1695 if (auto *const pContent = pPage->FindLastBodyContent())
1696 {
1697 pContent->InvalidateSize();
1698 }
1699 }
1700 }
1701 });
1702
1703 const SwContentFrame *pContent = pPage->ContainsContent();
1704 const SwViewShell *pSh = m_pRoot->GetCurrShell();
1705 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
1706
1707 while ( pContent && pPage->IsAnLower( pContent ) )
1708 {
1709 // If the content didn't change, we can use a few shortcuts.
1710 const bool bFull = !pContent->isFrameAreaDefinitionValid() || pContent->IsCompletePaint() ||
1711 pContent->IsRetouche() || pContent->GetDrawObjs();
1712 if ( bFull )
1713 {
1714 // We do this so we don't have to search later on.
1715 const bool bNxtCnt = IsCalcLayout() && !pContent->GetFollow();
1716 const SwContentFrame *pContentNext = bNxtCnt ? pContent->GetNextContentFrame() : nullptr;
1717 SwContentFrame* const pContentPrev = pContent->GetPrev() ? pContent->GetPrevContentFrame() : nullptr;
1718 std::optional<SfxDeleteListener> oPrevDeleteListener;
1719 if (pContentPrev)
1720 oPrevDeleteListener.emplace(*pContentPrev);
1721
1722 const SwLayoutFrame*pOldUpper = pContent->GetUpper();
1723 const SwTabFrame *pTab = pContent->FindTabFrame();
1724 const bool bInValid = !pContent->isFrameAreaDefinitionValid() || pContent->IsCompletePaint();
1725 const bool bOldPaint = IsPaint();
1726 m_bPaint = bOldPaint && !(pTab && pTab == m_pOptTab);
1727 FormatContent_( pContent, pPage );
1728 // reset <bPaint> before format objects
1729 m_bPaint = bOldPaint;
1730
1731 // format floating screen object at content frame.
1732 // No format, if action flag <bAgain> is set or action is interrupted.
1733 // allow format on interruption of action, if
1734 // it's the format for this interrupt
1735 // pass correct page frame
1736 // to the object formatter.
1737 if ( !IsAgain() &&
1738 ( !IsInterrupt() || mbFormatContentOnInterrupt ) &&
1739 pContent->IsTextFrame() &&
1740 !SwObjectFormatter::FormatObjsAtFrame( *const_cast<SwContentFrame*>(pContent),
1741 *(pContent->FindPageFrame()), this ) )
1742 {
1743 return false;
1744 }
1745
1746 if ( !pContent->GetValidLineNumFlag() && pContent->IsTextFrame() )
1747 {
1748 const sal_Int32 nAllLines = static_cast<const SwTextFrame*>(pContent)->GetAllLines();
1749 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pContent))->RecalcAllLines();
1750 if ( IsPaintExtraData() && IsPaint() &&
1751 nAllLines != static_cast<const SwTextFrame*>(pContent)->GetAllLines() )
1752 m_pImp->GetShell()->AddPaintRect( pContent->getFrameArea() );
1753 }
1754
1755 if ( IsAgain() )
1756 return false;
1757
1758 // Temporarily interrupt processing if layout or Flys become invalid again.
1759 // However not for the BrowseView: The layout is getting invalid
1760 // all the time because the page height gets adjusted.
1761 // The same applies if the user wants to continue working and at least one
1762 // paragraph has been processed.
1763 if (!pTab || !bInValid)
1764 {
1765 CheckIdleEnd();
1766 // consider interrupt formatting.
1767 if ( ( IsInterrupt() && !mbFormatContentOnInterrupt ) ||
1768 ( !bBrowse && pPage->IsInvalidLayout() ) ||
1769 // consider interrupt formatting
1770 ( pPage->GetSortedObjs() && pPage->IsInvalidFly() && !mbFormatContentOnInterrupt )
1771 )
1772 return false;
1773 }
1774 if ( pOldUpper != pContent->GetUpper() )
1775 {
1776 const sal_uInt16 nCurNum = pContent->FindPageFrame()->GetPhyPageNum();
1777 if ( nCurNum < pPage->GetPhyPageNum() )
1778 m_nPreInvaPage = nCurNum;
1779
1780 // If the frame flowed backwards more than one page, we need to
1781 // start over again from the beginning, so nothing gets left out.
1782 if ( !IsCalcLayout() && pPage->GetPhyPageNum() > nCurNum+1 )
1783 {
1784 SetNextCycle( true );
1785 // consider interrupt formatting
1786 if ( !mbFormatContentOnInterrupt )
1787 {
1788 return false;
1789 }
1790 }
1791 }
1792 // If the frame moved forwards to the next page, we re-run through
1793 // the predecessor.
1794 // This way, we catch predecessors which are now responsible for
1795 // retouching, but the footers will be touched also.
1796 bool bSetContent = true;
1797 if ( pContentPrev )
1798 {
1799 if (oPrevDeleteListener->WasDeleted())
1800 {
1801 SAL_WARN("sw", "ContentPrev was deleted");
1802 return false;
1803 }
1804
1805 if ( !pContentPrev->isFrameAreaDefinitionValid() && pPage->IsAnLower( pContentPrev ) )
1806 {
1807 pPage->InvalidateContent();
1808 }
1809
1810 if ( pOldUpper != pContent->GetUpper() &&
1811 pPage->GetPhyPageNum() < pContent->FindPageFrame()->GetPhyPageNum() )
1812 {
1813 pContent = pContentPrev;
1814 bSetContent = false;
1815 }
1816 }
1817 if ( bSetContent )
1818 {
1819 if ( bBrowse && !IsIdle() && !IsCalcLayout() && !IsComplete() &&
1820 pContent->getFrameArea().Top() > m_pImp->GetShell()->VisArea().Bottom())
1821 {
1822 const tools::Long nBottom = m_pImp->GetShell()->VisArea().Bottom();
1823 const SwFrame *pTmp = lcl_FindFirstInvaContent( pPage,
1824 nBottom, pContent );
1825 if ( !pTmp )
1826 {
1827 if ( (!(pPage->GetSortedObjs() && pPage->IsInvalidFly()) ||
1828 !lcl_FindFirstInvaObj( pPage, nBottom )) &&
1829 (!pPage->IsInvalidLayout() ||
1830 !lcl_FindFirstInvaLay( pPage, nBottom )))
1831 SetBrowseActionStop( true );
1832 // consider interrupt formatting.
1833 if ( !mbFormatContentOnInterrupt )
1834 {
1835 return false;
1836 }
1837 }
1838 }
1839 pContent = bNxtCnt ? pContentNext : pContent->GetNextContentFrame();
1840 }
1841
1842 if (IsReschedule())
1843 {
1844 ::RescheduleProgress(m_pImp->GetShell()->GetDoc()->GetDocShell());
1845 }
1846 }
1847 else
1848 {
1849 if ( !pContent->GetValidLineNumFlag() && pContent->IsTextFrame() )
1850 {
1851 const sal_Int32 nAllLines = static_cast<const SwTextFrame*>(pContent)->GetAllLines();
1852 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pContent))->RecalcAllLines();
1853 if ( IsPaintExtraData() && IsPaint() &&
1854 nAllLines != static_cast<const SwTextFrame*>(pContent)->GetAllLines() )
1855 m_pImp->GetShell()->AddPaintRect( pContent->getFrameArea() );
1856 }
1857
1858 // Do this if the frame has been formatted before.
1859 if ( pContent->IsTextFrame() && static_cast<const SwTextFrame*>(pContent)->HasRepaint() &&
1860 IsPaint() )
1861 PaintContent( pContent, pPage, pContent->getFrameArea(), pContent->getFrameArea().Bottom());
1862 if ( IsIdle() )
1863 {
1864 CheckIdleEnd();
1865 // consider interrupt formatting.
1866 if ( IsInterrupt() && !mbFormatContentOnInterrupt )
1867 return false;
1868 }
1869 if ( bBrowse && !IsIdle() && !IsCalcLayout() && !IsComplete() &&
1870 pContent->getFrameArea().Top() > m_pImp->GetShell()->VisArea().Bottom())
1871 {
1872 const tools::Long nBottom = m_pImp->GetShell()->VisArea().Bottom();
1873 const SwFrame *pTmp = lcl_FindFirstInvaContent( pPage,
1874 nBottom, pContent );
1875 if ( !pTmp )
1876 {
1877 if ( (!(pPage->GetSortedObjs() && pPage->IsInvalidFly()) ||
1878 !lcl_FindFirstInvaObj( pPage, nBottom )) &&
1879 (!pPage->IsInvalidLayout() ||
1880 !lcl_FindFirstInvaLay( pPage, nBottom )))
1881 SetBrowseActionStop( true );
1882 // consider interrupt formatting.
1883 if ( !mbFormatContentOnInterrupt )
1884 {
1885 return false;
1886 }
1887 }
1888 }
1889 pContent = pContent->GetNextContentFrame();
1890 }
1891 }
1892 CheckWaitCursor();
1893 // consider interrupt formatting.
1894 return !IsInterrupt() || mbFormatContentOnInterrupt;
1895}
1896
1897void SwLayAction::FormatContent_( const SwContentFrame *pContent, const SwPageFrame *pPage )
1898{
1899 // We probably only ended up here because the Content holds DrawObjects.
1900 const bool bDrawObjsOnly = pContent->isFrameAreaDefinitionValid() && !pContent->IsCompletePaint() && !pContent->IsRetouche();
1901 SwRectFnSet aRectFnSet(pContent);
1902 if ( !bDrawObjsOnly && IsPaint() )
1903 {
1904 const SwRect aOldRect( pContent->UnionFrame() );
1905 const tools::Long nOldBottom = aRectFnSet.GetPrtBottom(*pContent);
1906 pContent->OptCalc();
1907 if( IsAgain() )
1908 return;
1909 if( aRectFnSet.YDiff( aRectFnSet.GetBottom(pContent->getFrameArea()),
1910 aRectFnSet.GetBottom(aOldRect) ) < 0 )
1911 {
1912 pContent->SetRetouche();
1913 }
1914 PaintContent( pContent, pContent->FindPageFrame(), aOldRect, nOldBottom);
1915 }
1916 else
1917 {
1918 if ( IsPaint() && pContent->IsTextFrame() && static_cast<const SwTextFrame*>(pContent)->HasRepaint() )
1919 PaintContent( pContent, pPage, pContent->getFrameArea(),
1920 aRectFnSet.GetBottom(pContent->getFrameArea()) );
1921 pContent->OptCalc();
1922 }
1923}
1924
1926{
1927 const SwContentFrame *pContent = pFly->ContainsContent();
1928
1929 while ( pContent )
1930 {
1931 FormatContent_( pContent, pContent->FindPageFrame() );
1932
1933 // format floating screen objects at content text frame
1934 // pass correct page frame to the object formatter.
1935 if ( pContent->IsTextFrame() &&
1937 *const_cast<SwContentFrame*>(pContent),
1938 *(pContent->FindPageFrame()), this ) )
1939 {
1940 // restart format with first content
1941 pContent = pFly->ContainsContent();
1942 continue;
1943 }
1944
1945 if ( !pContent->GetValidLineNumFlag() && pContent->IsTextFrame() )
1946 {
1947 const sal_Int32 nAllLines = static_cast<const SwTextFrame*>(pContent)->GetAllLines();
1948 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pContent))->RecalcAllLines();
1949 if ( IsPaintExtraData() && IsPaint() &&
1950 nAllLines != static_cast<const SwTextFrame*>(pContent)->GetAllLines() )
1951 m_pImp->GetShell()->AddPaintRect( pContent->getFrameArea() );
1952 }
1953
1954 if ( IsAgain() )
1955 return;
1956
1957 // If there's input, we interrupt processing.
1958 if ( !pFly->IsFlyInContentFrame() )
1959 {
1960 CheckIdleEnd();
1961 // consider interrupt formatting.
1963 return;
1964 }
1965 pContent = pContent->GetNextContentFrame();
1966 }
1968}
1969
1971{
1972 OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
1973 // robust against misuse by e.g. #i52542#
1974 if( !pCnt->IsTextFrame() )
1975 return false;
1976
1977 SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pCnt));
1978 // sw_redlinehide: spell check only the nodes with visible content?
1979 SwTextNode* pTextNode = const_cast<SwTextNode*>(pTextFrame->GetTextNodeForParaProps());
1980
1981 bool bProcess = false;
1982 for (size_t i = 0; pTextNode; )
1983 {
1984 switch ( eJob )
1985 {
1987 bProcess = pTextNode->IsWrongDirty(); break;
1989 bProcess = pTextNode->IsAutoCompleteWordDirty(); break;
1991 bProcess = pTextNode->IsWordCountDirty(); break;
1993 bProcess = pTextNode->IsSmartTagDirty(); break;
1994 }
1995 if (bProcess)
1996 {
1997 break;
1998 }
1999 if (sw::MergedPara const* pMerged = pTextFrame->GetMergedPara())
2000 {
2001 while (true)
2002 {
2003 ++i;
2004 if (i < pMerged->extents.size())
2005 {
2006 if (pMerged->extents[i].pNode != pTextNode)
2007 {
2008 pTextNode = pMerged->extents[i].pNode;
2009 break;
2010 }
2011 }
2012 else
2013 {
2014 pTextNode = nullptr;
2015 break;
2016 }
2017 }
2018 }
2019 else
2020 pTextNode = nullptr;
2021 }
2022
2023 if( bProcess )
2024 {
2025 assert(pTextNode);
2026 SwViewShell *pSh = m_pImp->GetShell();
2028 {
2029 --m_nTextPos;
2030 if( auto pCursorShell = dynamic_cast<SwCursorShell *>( pSh ) )
2031 if( !pCursorShell->IsTableMode() )
2032 {
2033 SwPaM *pCursor = pCursorShell->GetCursor();
2034 if( !pCursor->HasMark() && !pCursor->IsMultiSelection() )
2035 {
2037 m_nTextPos = pCursor->GetPoint()->GetContentIndex();
2038 }
2039 }
2040 }
2041 sal_Int32 const nPos((m_pContentNode && pTextNode == m_pContentNode)
2042 ? m_nTextPos
2043 : COMPLETE_STRING);
2044
2045 switch ( eJob )
2046 {
2048 {
2049 SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->AutoSpell_(*pTextNode, nPos) );
2050 // PENDING should stop idle spell checking
2052 if ( aRepaint.HasArea() )
2053 m_pImp->GetShell()->InvalidateWindows( aRepaint );
2054 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
2055 return true;
2056 break;
2057 }
2059 const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
2060 // note: bPageValid remains true here even if the cursor
2061 // position is skipped, so no PENDING state needed currently
2062 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
2063 return true;
2064 break;
2066 {
2067 const sal_Int32 nEnd = pTextNode->GetText().getLength();
2068 SwDocStat aStat;
2069 pTextNode->CountWords( aStat, 0, nEnd );
2070 if ( Application::AnyInput() )
2071 return true;
2072 break;
2073 }
2075 {
2076 try {
2077 const SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->SmartTagScan(*pTextNode) );
2078 m_bPageValid = m_bPageValid && !pTextNode->IsSmartTagDirty();
2079 if ( aRepaint.HasArea() )
2080 m_pImp->GetShell()->InvalidateWindows( aRepaint );
2081 } catch( const css::uno::RuntimeException&) {
2082 // handle smarttag problems gracefully and provide diagnostics
2083 TOOLS_WARN_EXCEPTION( "sw.core", "SMART_TAGS");
2084 }
2085 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
2086 return true;
2087 break;
2088 }
2089 }
2090 }
2091
2092 // The Flys that are anchored to the paragraph need to be considered too.
2093 if ( pCnt->GetDrawObjs() )
2094 {
2095 const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
2096 for (SwAnchoredObject* pObj : rObjs)
2097 {
2098 if ( auto pFly = pObj->DynCastFlyFrame() )
2099 {
2100 if ( pFly->IsFlyInContentFrame() )
2101 {
2102 const SwContentFrame *pC = pFly->ContainsContent();
2103 while( pC )
2104 {
2105 if ( pC->IsTextFrame() )
2106 {
2107 if ( DoIdleJob_( pC, eJob ) )
2108 return true;
2109 }
2110 pC = pC->GetNextContentFrame();
2111 }
2112 }
2113 }
2114 }
2115 }
2116 return false;
2117}
2118
2120{
2121 switch (eJob)
2122 {
2124 {
2125 const SwViewOption* pViewOptions = pViewShell->GetViewOptions();
2126 return pViewOptions->IsOnlineSpell();
2127 }
2128
2130 {
2131 if (!SwViewOption::IsAutoCompleteWords() || SwDoc::GetAutoCompleteWords().IsLockWordLstLocked())
2132 return false;
2133 return true;
2134 }
2135
2137 {
2138 return pViewShell->getIDocumentStatistics().GetDocStat().bModified;
2139 }
2140
2142 {
2143 const SwDoc* pDoc = pViewShell->GetDoc();
2144 if (!pDoc->GetDocShell()->IsHelpDocument() || pDoc->isXForms() || !SwSmartTagMgr::Get().IsSmartTagsEnabled())
2145 return false;
2146 return true;
2147 }
2148 }
2149
2150 return false;
2151}
2152
2154{
2155 // Spellcheck all contents of the pages. Either only the
2156 // visible ones or all of them.
2157 const SwViewShell* pViewShell = m_pImp->GetShell();
2158
2159 // Check if job ius enabled and can run
2160 if (!isJobEnabled(eJob, pViewShell))
2161 return false;
2162
2163 SwPageFrame *pPage;
2164 if (eJobArea == IdleJobArea::VISIBLE)
2165 pPage = m_pImp->GetFirstVisPage(pViewShell->GetOut());
2166 else
2167 pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
2168
2169 m_pContentNode = nullptr;
2171
2172 while ( pPage )
2173 {
2174 m_bPageValid = true;
2175 const SwContentFrame* pContentFrame = pPage->ContainsContent();
2176 while (pContentFrame && pPage->IsAnLower(pContentFrame))
2177 {
2178 if (DoIdleJob_(pContentFrame, eJob))
2179 {
2180 SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
2181 return true;
2182 }
2183 pContentFrame = pContentFrame->GetNextContentFrame();
2184 }
2185 if ( pPage->GetSortedObjs() )
2186 {
2187 for ( size_t i = 0; pPage->GetSortedObjs() &&
2188 i < pPage->GetSortedObjs()->size(); ++i )
2189 {
2190 const SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i];
2191 if ( auto pFly = pObj->DynCastFlyFrame() )
2192 {
2193 const SwContentFrame *pC = pFly->ContainsContent();
2194 while( pC )
2195 {
2196 if ( pC->IsTextFrame() )
2197 {
2198 if ( DoIdleJob_( pC, eJob ) )
2199 {
2200 SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
2201 return true;
2202 }
2203 }
2204 pC = pC->GetNextContentFrame();
2205 }
2206 }
2207 }
2208 }
2209
2210 if( m_bPageValid )
2211 {
2212 switch (eJob)
2213 {
2215 pPage->ValidateSpelling();
2216 break;
2219 break;
2221 pPage->ValidateWordCount();
2222 break;
2224 pPage->ValidateSmartTags();
2225 break;
2226 }
2227 }
2228
2229 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
2230 if (pPage && eJobArea == IdleJobArea::VISIBLE &&
2231 !pPage->getFrameArea().Overlaps( m_pImp->GetShell()->VisArea()))
2232 {
2233 break;
2234 }
2235 }
2236 return false;
2237}
2238
2239#if HAVE_FEATURE_DESKTOP && defined DBG_UTIL
2240void SwLayIdle::ShowIdle( Color eColor )
2241{
2242 if ( m_bIndicator )
2243 return;
2244
2245 m_bIndicator = true;
2246 vcl::Window *pWin = m_pImp->GetShell()->GetWin();
2247 if (pWin && !pWin->SupportsDoubleBuffering()) // FIXME make this work with double-buffering
2248 {
2249 tools::Rectangle aRect( 0, 0, 5, 5 );
2250 aRect = pWin->PixelToLogic( aRect );
2251 // Depending on if idle layout is in progress or not, draw a "red square" or a "green square".
2253 pWin->GetOutDev()->SetFillColor( eColor );
2254 pWin->GetOutDev()->SetLineColor();
2255 pWin->GetOutDev()->DrawRect( aRect );
2256 pWin->GetOutDev()->Pop();
2257 }
2258}
2259#define SHOW_IDLE( Color ) ShowIdle( Color )
2260#else
2261#define SHOW_IDLE( Color )
2262#endif // DBG_UTIL
2263
2265 m_pRoot( pRt ),
2266 m_pImp( pI )
2267#ifdef DBG_UTIL
2268 , m_bIndicator( false )
2269#endif
2270{
2271 SAL_INFO("sw.idle", "SwLayIdle() entry");
2272
2273 m_pImp->m_pIdleAct = this;
2274
2276
2277 m_pImp->GetShell()->EnableSmooth( false );
2278
2279 // First, spellcheck the visible area. Only if there's nothing
2280 // to do there, we trigger the IdleFormat.
2284 {
2285 // Format, then register repaint rectangles with the SwViewShell if necessary.
2286 // This requires running artificial actions, so we don't get undesired
2287 // effects when for instance the page count gets changed.
2288 // We remember the shells where the cursor is visible, so we can make
2289 // it visible again if needed after a document change.
2290 std::vector<bool> aBools;
2292 {
2293 ++rSh.mnStartAction;
2294 bool bVis = false;
2295 if ( auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh) )
2296 {
2297 bVis = pCursorShell->GetCharRect().Overlaps(rSh.VisArea());
2298 }
2299 aBools.push_back( bVis );
2300 }
2301
2302 bool bInterrupt(false);
2303 {
2304 SwLayAction aAction( m_pRoot, m_pImp );
2305 aAction.SetInputType( VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER) );
2306 aAction.SetIdle( true );
2307 aAction.SetWaitAllowed( false );
2308 aAction.Action(m_pImp->GetShell()->GetOut());
2309 bInterrupt = aAction.IsInterrupt();
2310 }
2311
2312 // Further start/end actions only happen if there were paints started
2313 // somewhere or if the visibility of the CharRects has changed.
2314 bool bActions = false;
2315 size_t nBoolIdx = 0;
2317 {
2318 --rSh.mnStartAction;
2319
2320 if ( rSh.Imp()->HasPaintRegion() )
2321 bActions = true;
2322 else
2323 {
2324 SwRect aTmp( rSh.VisArea() );
2325 rSh.UISizeNotify();
2326
2327 // Are we supposed to crash if rSh isn't a cursor shell?!
2328 // bActions |= aTmp != rSh.VisArea() ||
2329 // aBools[nBoolIdx] != ((SwCursorShell*)&rSh)->GetCharRect().IsOver( rSh.VisArea() );
2330
2331 // aBools[ i ] is true, if the i-th shell is a cursor shell (!!!)
2332 // and the cursor is visible.
2333 bActions |= aTmp != rSh.VisArea();
2334 if ( aTmp == rSh.VisArea() )
2335 if ( auto pCursorShell = dynamic_cast< SwCursorShell*>( &rSh) )
2336 bActions |= aBools[nBoolIdx] != pCursorShell->GetCharRect().Overlaps( rSh.VisArea() );
2337 }
2338
2339 ++nBoolIdx;
2340 }
2341
2342 if ( bActions )
2343 {
2344 // Prepare start/end actions via CursorShell, so the cursor, selection
2345 // and VisArea can be set correctly.
2346 nBoolIdx = 0;
2348 {
2349 SwCursorShell* pCursorShell = dynamic_cast<SwCursorShell*>( &rSh);
2350
2351 if ( pCursorShell )
2352 pCursorShell->SttCursorMove();
2353
2354 // If there are accrued paints, it's best to simply invalidate
2355 // the whole window. Otherwise there would arise paint problems whose
2356 // solution would be disproportionally expensive.
2357 SwViewShellImp *pViewImp = rSh.Imp();
2358 bool bUnlock = false;
2359 if ( pViewImp->HasPaintRegion() )
2360 {
2361 SAL_INFO("sw.idle", "Disappointing full document invalidation");
2362 pViewImp->DeletePaintRegion();
2363
2364 // Cause a repaint with virtual device.
2365 rSh.LockPaint(LockPaintReason::SwLayIdle);
2366 bUnlock = true;
2367 }
2368
2369 if ( pCursorShell )
2370 // If the Cursor was visible, we need to make it visible again.
2371 // Otherwise, EndCursorMove with true for IdleEnd
2372 pCursorShell->EndCursorMove( !aBools[nBoolIdx] );
2373 if( bUnlock )
2374 {
2375 if( pCursorShell )
2376 {
2377 // UnlockPaint overwrite the selection from the
2378 // CursorShell and calls the virtual method paint
2379 // to fill the virtual device. This fill don't have
2380 // paint the selection! -> Set the focus flag at
2381 // CursorShell and it doesn't paint the selection.
2382 pCursorShell->ShellLoseFocus();
2383 pCursorShell->UnlockPaint( true );
2384 pCursorShell->ShellGetFocus();
2385 }
2386 else
2387 rSh.UnlockPaint( true );
2388 }
2389 ++nBoolIdx;
2390
2391 }
2392 }
2393
2394 if (!bInterrupt)
2395 {
2400 }
2401
2402 bool bInValid = false;
2403 const SwViewOption& rVOpt = *m_pImp->GetShell()->GetViewOptions();
2404 const SwViewShell* pViewShell = m_pImp->GetShell();
2405 // See conditions in DoIdleJob()
2406 const bool bSpell = rVOpt.IsOnlineSpell();
2407 const bool bACmplWrd = SwViewOption::IsAutoCompleteWords();
2408 const bool bWordCount = pViewShell->getIDocumentStatistics().GetDocStat().bModified;
2409 const bool bSmartTags = !pViewShell->GetDoc()->GetDocShell()->IsHelpDocument() &&
2410 !pViewShell->GetDoc()->isXForms() &&
2412
2413 SwPageFrame *pPg = static_cast<SwPageFrame*>(m_pRoot->Lower());
2414 do
2415 {
2416 bInValid = pPg->IsInvalidContent() || pPg->IsInvalidLayout() ||
2417 pPg->IsInvalidFlyContent() || pPg->IsInvalidFlyLayout() ||
2418 pPg->IsInvalidFlyInCnt() ||
2419 (bSpell && pPg->IsInvalidSpelling()) ||
2420 (bACmplWrd && pPg->IsInvalidAutoCompleteWords()) ||
2421 (bWordCount && pPg->IsInvalidWordCount()) ||
2422 (bSmartTags && pPg->IsInvalidSmartTags());
2423
2424 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
2425
2426 } while ( pPg && !bInValid );
2427
2428 if ( !bInValid )
2429 {
2431 SfxObjectShell* pDocShell = m_pImp->GetShell()->GetDoc()->GetDocShell();
2432 pDocShell->Broadcast( SfxEventHint( SfxEventHintId::SwEventLayoutFinished, SwDocShell::GetEventName(STR_SW_EVENT_LAYOUT_FINISHED), pDocShell ) );
2433 }
2434 }
2435
2436 m_pImp->GetShell()->EnableSmooth( true );
2437
2438#if !ENABLE_WASM_STRIP_ACCESSIBILITY
2439 if( m_pImp->IsAccessible() )
2441#endif
2442
2443 SAL_INFO("sw.idle", "SwLayIdle() return");
2444
2445#ifdef DBG_UTIL
2446 if ( m_bIndicator && m_pImp->GetShell()->GetWin() )
2447 {
2448 // Do not invalidate indicator, this may cause an endless loop. Instead, just repaint it
2449 // This should be replaced by an overlay object in the future, anyways. Since it's only for debug
2450 // purposes, it is not urgent.
2452 }
2453#endif
2454}
2455
2457{
2458 m_pImp->m_pIdleAct = nullptr;
2459}
2460
2461/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool AnyInput(VclInputFlags nType=VCL_INPUT_ANY)
virtual SdrLayerID GetHellId() const =0
virtual bool IsVisibleLayerId(SdrLayerID _nLayerId) const =0
method to determine, if a layer ID belongs to the visible ones.
Provides access to the layout of a document.
virtual SwLayouter * GetLayouter()=0
virtual const SwDocStat & GetDocStat() const =0
Document - Statistics.
Handle the background jobs of a Writer document.
virtual void BlockIdling()=0
Increment block count.
virtual void UnblockIdling()=0
Decrement block count.
void DrawRect(const tools::Rectangle &rRect)
void SetLineColor()
void SetFillColor()
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
sal_uInt32 GetOrdNumDirect() const
virtual SdrLayerID GetLayer() const
bool IsHelpDocument() const
bool IsSmartTagsEnabled() const
class for the positioning of drawing objects
wrapper class for the positioning of Writer fly frames and drawing objects
virtual const SwFlyFrame * DynCastFlyFrame() const
virtual SwRect GetObjRect() const =0
SwContentFrame is the layout for content nodes: a common base class for text (paragraph) and non-text...
Definition: cntfrm.hxx:59
SwContentFrame * GetNextContentFrame() const
Definition: cntfrm.hxx:120
SwTextFrame * FindMaster() const
Definition: flowfrm.cxx:762
void SttCursorMove()
Definition: crsrsh.cxx:301
void ShellGetFocus()
Definition: crsrsh.cxx:2758
void ShellLoseFocus()
Definition: crsrsh.cxx:2751
void EndCursorMove(const bool bIdleEnd=false)
Definition: crsrsh.cxx:310
static OUString GetEventName(sal_Int32 nId)
Definition: docsh.cxx:1327
Definition: doc.hxx:197
static SwAutoCompleteWord & GetAutoCompleteWords()
Definition: doc.hxx:1558
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:649
bool isXForms() const
Definition: docxforms.cxx:44
SwDocShell * GetDocShell()
Definition: doc.hxx:1370
general base class for all free-flowing frames
Definition: flyfrm.hxx:79
void Validate() const
Definition: flyfrm.hxx:212
const SwVirtFlyDrawObj * GetVirtDrawObj() const
Definition: fly.cxx:3025
virtual const SwFlyFrameFormat * GetFormat() const override
Definition: fly.cxx:3119
bool IsBackgroundTransparent() const
SwFlyFrame::IsBackgroundTransparent.
Definition: paintfrm.cxx:3904
bool IsLowerOf(const SwLayoutFrame *pUpper) const
Definition: fly.cxx:2392
bool IsInvalid() const
Definition: flyfrm.hxx:210
bool IsFlyInContentFrame() const
Definition: flyfrm.hxx:217
void Invalidate() const
Definition: flyfrm.hxx:211
virtual void Calc(vcl::RenderContext *pRenderContext) const override
Definition: fly.cxx:3156
Flys that are anchored as a character in the content.
Definition: flyfrms.hxx:210
SwLayoutFrame * FindBodyCont()
Searches the first ContentFrame in BodyText below the page.
Definition: findfrm.cxx:48
SwFootnoteContFrame * FindFootnoteCont()
Definition: ftnfrm.cxx:1038
bool IsContour() const
Definition: fmtsrnd.hxx:53
IDocumentTimerAccess & getIDocumentTimerAccess()
Provides access to the document idle timer interface.
Definition: format.cxx:716
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:139
const SvxOpaqueItem & GetOpaque(bool=true) const
Definition: frmatr.hxx:104
const IDocumentDrawModelAccess & getIDocumentDrawModelAccess() const
Provides access to the document draw model interface.
Definition: format.cxx:712
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
const IDocumentLayoutAccess & getIDocumentLayoutAccess() const
Provides access to the document layout interface.
Definition: format.cxx:714
const SwRect & getFrameArea() const
Definition: frame.hxx:179
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:171
const SwRect & getFramePrintArea() const
Definition: frame.hxx:180
Base class of the Writer layout elements.
Definition: frame.hxx:315
SwRect GetPaintArea() const
|* The paintarea is the area, in which the content of a frame is allowed |* to be displayed.
Definition: ssfrm.cxx:595
SwSectionFrame * ImplFindSctFrame()
Definition: findfrm.cxx:566
bool IsTextFrame() const
Definition: frame.hxx:1240
bool GetValidLineNumFlag() const
Definition: frame.hxx:768
bool IsInDocBody() const
Definition: frame.hxx:949
SwFlyFrame * FindFlyFrame()
Definition: frame.hxx:1117
SwSectionFrame * FindSctFrame()
Definition: frame.hxx:1121
SwTabFrame * FindTabFrame()
Definition: frame.hxx:1105
SwFrame * GetNext()
Definition: frame.hxx:682
void ResetCompletePaint() const
Definition: frame.hxx:1004
bool IsPageFrame() const
Definition: frame.hxx:1184
SwTabFrame * ImplFindTabFrame()
Definition: findfrm.cxx:554
void OptCalc() const
Definition: frame.hxx:1086
bool IsTabFrame() const
Definition: frame.hxx:1224
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1799
bool IsRetoucheFrame() const
Definition: frame.hxx:1252
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:568
bool IsInTab() const
Definition: frame.hxx:961
void ResetRetouche() const
Definition: frame.hxx:1013
SwFrame * FindPrev()
Definition: frame.hxx:1161
static void CheckPageDescs(SwPageFrame *pStart, bool bNotifyFields=true, SwPageFrame **ppPrev=nullptr)
Check all pages (starting from the given one) if they use the appropriate frame format.
Definition: pagechg.cxx:1078
bool IsPageBodyFrame() const
Definition: layfrm.hxx:215
SwRect UnionFrame(bool bBorder=false) const
|* The unionframe is the framearea (getFrameArea()) of a frame expanded by the |* printarea,...
Definition: ssfrm.cxx:703
bool IsFootnoteFrame() const
Definition: frame.hxx:1208
SwLayoutFrame * GetUpper()
Definition: frame.hxx:684
bool IsCompletePaint() const
Definition: frame.hxx:605
void InvalidatePage(const SwPageFrame *pPage=nullptr) const
Invalidates the page in which the Frame is currently placed.
Definition: wsfrm.cxx:618
SwRootFrame * getRootFrame()
Definition: frame.hxx:685
bool IsNoTextFrame() const
Definition: frame.hxx:1244
bool IsRetouche() const
Definition: frame.hxx:609
void SetCompletePaint() const
Definition: frame.hxx:1000
SwFrame * GetPrev()
Definition: frame.hxx:683
bool IsSctFrame() const
Definition: frame.hxx:1220
SwPageFrame * FindPageFrame()
Definition: frame.hxx:686
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:390
void SetRetouche() const
Definition: frame.hxx:1009
bool IsLayoutFrame() const
Definition: frame.hxx:1176
bool IsInSct() const
Definition: frame.hxx:973
The usage of LayAction is always the same:
Definition: layact.hxx:59
void FormatLayoutFly(SwFlyFrame *)
Definition: layact.cxx:1455
bool m_bActionInProgress
Definition: layact.hxx:101
bool m_bNextCycle
Definition: layact.hxx:92
bool m_bIdle
Definition: layact.hxx:94
bool m_bPaintExtraData
Definition: layact.hxx:100
SwLayAction(SwRootFrame *pRt, SwViewShellImp *pImp)
Definition: layact.cxx:249
std::clock_t m_nStartTicks
Definition: layact.hxx:80
void Reset()
Definition: layact.cxx:276
bool IsAgain() const
Definition: layact.hxx:170
bool m_bBrowseActionStop
Definition: layact.hxx:98
const SwTabFrame * m_pOptTab
Definition: layact.hxx:68
bool m_bPaint
Definition: layact.hxx:88
void Action(OutputDevice *pRenderContext)
Definition: layact.cxx:363
void CheckIdleEnd()
Definition: layact.cxx:86
std::unique_ptr< SwWait > m_pWait
Definition: layact.hxx:70
sal_uInt16 m_nPreInvaPage
Definition: layact.hxx:78
SwViewShellImp * m_pImp
Definition: layact.hxx:61
void SetAgain(bool bAgain)
Definition: layact.cxx:316
bool m_bCalcLayout
Definition: layact.hxx:90
void FormatFlyContent(const SwFlyFrame *)
Definition: layact.cxx:1925
bool m_bWaitAllowed
Definition: layact.hxx:99
bool IsNextCycle() const
Definition: layact.hxx:143
void SetInputType(VclInputFlags nNew)
Definition: layact.hxx:156
VclInputFlags GetInputType() const
Definition: layact.hxx:150
bool m_bCheckPages
Definition: layact.hxx:96
bool m_bUpdateExpFields
Definition: layact.hxx:97
void SetCheckPages(bool bNew)
Definition: layact.hxx:138
bool m_bReschedule
Definition: layact.hxx:95
void PaintContent(const SwContentFrame *, const SwPageFrame *, const SwRect &rOldRect, tools::Long nOldBottom)
Depending of the type, the Content is output according to its changes, or the area to be outputted is...
Definition: layact.cxx:199
bool FormatLayoutTab(SwTabFrame *, bool bAddRect)
Definition: layact.cxx:1504
bool IsComplete() const
Definition: layact.hxx:171
bool TurboAction_(const SwContentFrame *)
Definition: layact.cxx:818
bool m_bInterrupt
Definition: layact.hxx:93
bool IsWaitAllowed() const
Definition: layact.hxx:142
sal_uInt16 m_nCheckPageNum
Definition: layact.hxx:85
void SetWaitAllowed(bool bNew)
Definition: layact.hxx:159
void CheckWaitCursor()
Definition: layact.cxx:72
bool IsReschedule() const
Definition: layact.hxx:146
void PopFormatLayout()
Definition: layact.cxx:357
void PushFormatLayout(SwFrame *pLow)
Definition: layact.cxx:343
bool PaintWithoutFlys(const SwRect &, const SwContentFrame *, const SwPageFrame *)
Definition: layact.cxx:103
bool IsIdle() const
Definition: layact.hxx:145
void InternalAction(OutputDevice *pRenderContext)
Definition: layact.cxx:466
sal_uInt16 m_nEndPage
Definition: layact.hxx:84
bool IsPaint() const
Definition: layact.hxx:144
std::vector< SwFrame * > m_aFrameStack
Definition: layact.hxx:72
bool FormatContent(SwPageFrame *pPage)
Definition: layact.cxx:1652
bool IsShortCut(SwPageFrame *&)
Definition: layact.cxx:1004
bool m_bComplete
Definition: layact.hxx:89
~SwLayAction()
Definition: layact.cxx:270
bool IsBrowseActionStop() const
Definition: layact.hxx:175
bool RemoveEmptyBrowserPages()
Definition: layact.cxx:288
bool TurboAction()
Definition: layact.cxx:874
bool IsInterrupt() const
Definition: layact.hxx:148
std::vector< std::unique_ptr< SwFrameDeleteGuard > > m_aFrameDeleteGuards
Definition: layact.hxx:73
void SetIdle(bool bNew)
Definition: layact.hxx:137
void SetStatBar(bool bNew)
Definition: layact.cxx:92
void SetNextCycle(bool bNew)
Definition: layact.hxx:140
SwRootFrame * m_pRoot
Definition: layact.hxx:60
bool IsPaintExtraData() const
Definition: layact.hxx:147
bool PaintContent_(const SwContentFrame *, const SwPageFrame *, const SwRect &)
Definition: layact.cxx:181
void FormatContent_(const SwContentFrame *pContent, const SwPageFrame *pPage)
Definition: layact.cxx:1897
bool m_bAgain
Definition: layact.hxx:91
bool IsCalcLayout() const
Definition: layact.hxx:173
bool FormatLayout(OutputDevice *pRenderContext, SwLayoutFrame *, bool bAddRect=true)
Definition: layact.cxx:1219
bool mbFormatContentOnInterrupt
Definition: layact.hxx:104
static SwPageFrame * CheckFirstVisPage(SwPageFrame *pPage)
Definition: layact.cxx:412
VclInputFlags m_nInputType
Definition: layact.hxx:83
SwViewShellImp * m_pImp
Definition: layact.hxx:208
SwContentNode * m_pContentNode
Definition: layact.hxx:209
~SwLayIdle()
Definition: layact.cxx:2456
sal_Int32 m_nTextPos
Definition: layact.hxx:210
bool DoIdleJob_(const SwContentFrame *, IdleJobType)
Definition: layact.cxx:1970
SwRootFrame * m_pRoot
Definition: layact.hxx:207
bool m_bPageValid
Definition: layact.hxx:211
bool m_bIndicator
Definition: layact.hxx:213
bool DoIdleJob(IdleJobType eJobType, IdleJobArea eJobArea)
Definition: layact.cxx:2153
static bool isJobEnabled(IdleJobType eJob, const SwViewShell *pViewShell)
Definition: layact.cxx:2119
void ShowIdle(Color eName)
SwLayIdle(SwRootFrame *pRt, SwViewShellImp *pImp)
Definition: layact.cxx:2264
A layout frame is a frame that contains other frames (m_pLower), e.g. SwPageFrame or SwTabFrame.
Definition: layfrm.hxx:36
bool IsAnLower(const SwFrame *) const
Definition: findfrm.cxx:233
virtual const SwFrameFormat * GetFormat() const
Definition: ssfrm.cxx:401
const SwContentFrame * ContainsContent() const
Checks if the frame contains one or more ContentFrame's anywhere in his subsidiary structure; if so t...
Definition: findfrm.cxx:72
const SwFrame * Lower() const
Definition: layfrm.hxx:101
static bool StartLoopControl(SwDoc *pDoc, SwPageFrame const *pPage)
Definition: layouter.cxx:287
void EndLoopControl()
Definition: layouter.cxx:258
void LoopControl(SwPageFrame *pPage)
Definition: layouter.cxx:235
static bool FormatObjsAtFrame(SwFrame &_rAnchorFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction=nullptr)
method to format all floating screen objects at the given anchor frame
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:188
bool IsMultiSelection() const
Definition: pam.hxx:322
SwContentNode * GetPointContentNode() const
Definition: pam.hxx:279
const SwPosition * GetPoint() const
Definition: pam.hxx:253
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:251
A page of the document layout.
Definition: pagefrm.hxx:60
bool IsInvalidWordCount() const
Definition: pagefrm.hxx:244
void InvalidateContent() const
Definition: pagefrm.hxx:389
void ValidateFlyInCnt() const
Definition: pagefrm.hxx:418
SwContentFrame * FindLastBodyContent()
Searches the last ContentFrame in BodyText below the page.
Definition: findfrm.cxx:57
void ValidateContent() const
Definition: pagefrm.hxx:426
bool IsInvalid() const
Definition: pagefrm.hxx:448
void InvalidateFlyLayout() const
Validate, invalidate and query the Page status Layout/Content and Fly/non-Fly respectively are inspec...
Definition: pagefrm.hxx:373
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:209
void ValidateSmartTags() const
Definition: pagefrm.hxx:435
static void GetBorderAndShadowBoundRect(const SwRect &_rPageRect, const SwViewShell *_pViewShell, OutputDevice const *pRenderContext, SwRect &_orBorderAndShadowBoundRect, const bool bLeftShadow, const bool bRightShadow, const bool bRightSidebar)
get bound rectangle of border and shadow for repaints
Definition: paintfrm.cxx:6413
bool IsInvalidFlyContent() const
Definition: pagefrm.hxx:237
void InvalidateFlyInCnt() const
Definition: pagefrm.hxx:381
const SwSortedObjs * GetSortedObjs() const
Definition: pagefrm.hxx:136
bool IsInvalidFlyLayout() const
Definition: pagefrm.hxx:236
bool IsLeftShadowNeeded() const
Definition: paintfrm.cxx:6028
SwContentFrame * FindFirstBodyContent()
Definition: pagefrm.hxx:359
sw::sidebarwindows::SidebarPosition SidebarPosition() const
asks the page on which side a margin should be shown, e.g for notes returns true for left side,...
Definition: pagechg.cxx:1462
bool IsInvalidSmartTags() const
Definition: pagefrm.hxx:242
void ValidateFlyLayout() const
Definition: pagefrm.hxx:410
bool IsFootnotePage() const
Foot note interface.
Definition: pagefrm.hxx:204
bool IsInvalidContent() const
Definition: pagefrm.hxx:240
void InvalidateFlyContent() const
Definition: pagefrm.hxx:377
bool IsInvalidSpelling() const
Definition: pagefrm.hxx:241
bool IsInvalidAutoCompleteWords() const
Definition: pagefrm.hxx:243
SwRect GetBoundRect(OutputDevice const *pOutputDevice) const
Definition: paintfrm.cxx:6440
void ValidateWordCount() const
Definition: pagefrm.hxx:443
bool IsInvalidFlyInCnt() const
Definition: pagefrm.hxx:238
virtual void Cut() override
Definition: pagechg.cxx:858
void ValidateSpelling() const
Definition: pagefrm.hxx:430
bool IsInvalidFly() const
Definition: pagefrm.hxx:452
void ValidateAutoCompleteWords() const
Definition: pagefrm.hxx:439
bool IsRightShadowNeeded() const
Definition: paintfrm.cxx:6015
void ValidateLayout() const
Definition: pagefrm.hxx:422
bool IsInvalidLayout() const
Definition: pagefrm.hxx:239
void ValidateFlyContent() const
Definition: pagefrm.hxx:414
tools::Long GetHeight(const SwRect &rRect) const
Definition: frame.hxx:1387
void SetWidth(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1395
tools::Long GetRightMargin(const SwFrame &rFrame) const
Definition: frame.hxx:1411
tools::Long GetTopMargin(const SwFrame &rFrame) const
Definition: frame.hxx:1408
void SetHeight(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1396
tools::Long GetPrtRight(const SwFrame &rFrame) const
Definition: frame.hxx:1417
tools::Long GetBottomMargin(const SwFrame &rFrame) const
Definition: frame.hxx:1409
tools::Long YDiff(tools::Long n1, tools::Long n2) const
Definition: frame.hxx:1428
tools::Long GetLeftMargin(const SwFrame &rFrame) const
Definition: frame.hxx:1410
tools::Long GetBottom(const SwRect &rRect) const
Definition: frame.hxx:1383
void SetTop(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1391
tools::Long GetPrtBottom(const SwFrame &rFrame) const
Definition: frame.hxx:1415
void SetLeft(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1393
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
void Height(tools::Long nNew)
Definition: swrect.hxx:193
bool IsEmpty() const
Definition: swrect.hxx:304
bool HasArea() const
Definition: swrect.hxx:300
void Top(const tools::Long nTop)
Definition: swrect.hxx:206
void Right(const tools::Long nRight)
Definition: swrect.hxx:202
void Bottom(const tools::Long nBottom)
Definition: swrect.hxx:211
void Pos(const Point &rNew)
Definition: swrect.hxx:171
void SSize(const Size &rNew)
Definition: swrect.hxx:180
bool Overlaps(const SwRect &rRect) const
Definition: swrect.hxx:374
void Left(const tools::Long nLeft)
Definition: swrect.hxx:197
void Width(tools::Long nNew)
Definition: swrect.hxx:189
void ChangeOrigin(const SwRect &rRect)
Definition: swregion.hxx:63
The root element of a Writer document layout.
Definition: rootfrm.hxx:85
bool IsAssertFlyPages() const
Definition: rootfrm.hxx:288
bool IsLeftToRightViewLayout() const
Definition: pagechg.cxx:2460
void DeleteEmptySct()
Definition: rootfrm.hxx:392
void ResetTurboFlag() const
Definition: rootfrm.hxx:357
bool IsSuperfluous() const
Definition: rootfrm.hxx:311
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:215
const SwContentFrame * GetTurbo() const
Definition: rootfrm.hxx:361
sal_uInt16 GetPageNum() const
Definition: rootfrm.hxx:321
bool IsTableUpdateInProgress() const
Definition: rootfrm.hxx:291
void ResetIdleFormat()
Definition: rootfrm.hxx:268
void RemoveSuperfluous()
remove pages that are not needed at all
Definition: pagechg.cxx:1518
void DisallowTurbo() const
Definition: rootfrm.hxx:356
void ResetTurbo()
Definition: rootfrm.hxx:360
void DeleteEmptyFlys()
Definition: rootfrm.hxx:393
void AssertFlyPages()
Ensures that enough pages exist, so that all page bound frames and draw objects can be placed.
Definition: pagechg.cxx:1566
SwSection * GetSection()
Definition: sectfrm.hxx:97
static SwSmartTagMgr & Get()
class for collecting anchored objects
Definition: sortedobjs.hxx:49
size_t size() const
Definition: sortedobjs.cxx:43
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:49
bool IsComplete() const
Definition: tabfrm.hxx:165
void SetLowersFormatted(bool b)
Definition: tabfrm.hxx:170
bool IsLowersFormatted() const
Definition: tabfrm.hxx:169
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:168
sal_Int32 GetAllLines() const
For displaying the line numbers.
Definition: txtfrm.hxx:685
sw::MergedPara * GetMergedPara()
Definition: txtfrm.hxx:465
bool HasRepaint() const
Definition: txtfrm.hxx:546
SwRect GetPaintSwRect()
Page number etc.
Definition: frmpaint.cxx:456
void RecalcAllLines()
Definition: txtfrm.cxx:3985
SwTextNode const * GetTextNodeForParaProps() const
Definition: txtfrm.cxx:1390
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
bool IsSmartTagDirty() const
Definition: txtedt.cxx:2375
bool IsAutoCompleteWordDirty() const
Definition: txtedt.cxx:2385
bool CountWords(SwDocStat &rStat, sal_Int32 nStart, sal_Int32 nEnd) const
count words in given range - returns true if we refreshed out count
Definition: txtedt.cxx:2096
bool IsWordCountDirty() const
Definition: txtedt.cxx:2340
sw::WrongState GetWrongDirty() const
Definition: txtedt.cxx:2350
bool IsWrongDirty() const
Definition: txtedt.cxx:2355
const OUString & GetText() const
Definition: ndtxt.hxx:244
static bool IsAutoCompleteWords()
Definition: viewopt.cxx:402
sal_uInt16 GetGapBetweenPages() const
Definition: viewopt.hxx:621
static constexpr sal_uInt16 defGapBetweenPages
Definition: viewopt.hxx:616
bool getBrowseMode() const
Definition: viewopt.hxx:636
bool IsOnlineSpell() const
Definition: viewopt.hxx:537
SwLayAction * m_pLayAction
Definition: viewimp.hxx:72
const SwPageFrame * GetFirstVisPage(OutputDevice const *pRenderContext) const
Management of the first visible Page.
Definition: viewimp.cxx:315
bool HasPaintRegion()
Definition: viewimp.hxx:154
void SetFirstVisPageInvalid()
Definition: viewimp.hxx:149
void DeletePaintRegion()
Definition: viewimp.hxx:157
const SwViewShell * GetShell() const
Only for SwViewShell::Init()
Definition: viewimp.hxx:141
void FireAccessibleEvents()
Fire all accessible events that have been collected so far.
Definition: viewimp.cxx:521
bool IsAccessible() const
Is this view accessible?
Definition: viewimp.hxx:228
SwLayIdle * m_pIdleAct
Definition: viewimp.hxx:74
vcl::RenderContext * GetOut() const
Definition: viewsh.hxx:365
const IDocumentStatistics & getIDocumentStatistics() const
Provides access to the document statistics interface.
Definition: viewsh.cxx:2831
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:452
void UnlockPaint(bool bVirDev=false)
Definition: viewsh.hxx:639
void EnableSmooth(bool b)
Definition: viewsh.hxx:274
bool AddPaintRect(const SwRect &rRect)
Definition: viewsh.cxx:552
vcl::Window * GetWin() const
Definition: viewsh.hxx:364
const SwRect & VisArea() const
Definition: viewsh.cxx:642
void InvalidateWindows(const SwRect &rRect)
Definition: viewsh.cxx:568
SwDoc * GetDoc() const
Definition: viewsh.hxx:308
bool IsPaintLocked() const
Definition: viewsh.hxx:497
SwFlyFrame * GetFlyFrame()
Definition: dflyobj.hxx:135
bool empty() const
ring_container GetRingContainer()
Definition: ring.hxx:240
bool SupportsDoubleBuffering() const
::OutputDevice const * GetOutDev() const
Point PixelToLogic(const Point &rDevicePt) const
constexpr ::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
constexpr ::Color COL_LIGHTGREEN(0x00, 0xFF, 0x00)
int nCount
#define PROTOCOL(pFrame, nFunc, nAct, pPar)
Definition: dbg_lay.hxx:88
@ FileInit
#define TOOLS_WARN_EXCEPTION(area, stream)
void Notify_Background(const SdrObject *pObj, SwPageFrame *pPage, const SwRect &rRect, const PrepareHint eHint, const bool bInva)
Definition: frmtool.cxx:3412
bool IsExtraData(const SwDoc *pDoc)
Definition: frmtool.cxx:3913
VclInputFlags
#define VCL_INPUT_ANY
static const SwFrame * lcl_FindFirstInvaLay(const SwFrame *pFrame, tools::Long nBottom)
Definition: layact.cxx:898
static bool lcl_IsInvaLay(const SwFrame *pFrame, tools::Long nBottom)
Definition: layact.cxx:892
static void unlockPositionOfObjects(SwPageFrame *pPageFrame)
Definition: layact.cxx:452
static const SwFrame * lcl_FindFirstInvaContent(const SwLayoutFrame *pLay, tools::Long nBottom, const SwContentFrame *pFirst)
Definition: layact.cxx:920
static const SwAnchoredObject * lcl_FindFirstInvaObj(const SwPageFrame *_pPage, tools::Long _nBottom)
Definition: layact.cxx:965
#define SHOW_IDLE(Color)
Definition: layact.cxx:2261
IdleJobArea
Definition: layact.hxx:200
IdleJobType
Definition: layact.hxx:192
sal_uInt16 nPos
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
void RescheduleProgress(SwDocShell const *pDocShell)
Definition: mainwn.cxx:123
void SetProgressState(tools::Long nPosition, SwDocShell const *pDocShell)
Definition: mainwn.cxx:82
tools::Long const nTopMargin
tools::Long const nLeftMargin
size
int i
long Long
bool bModified
Definition: docstat.hxx:40
sal_Int32 GetContentIndex() const
Definition: pam.hxx:85
Describes parts of multiple text nodes, which will form a text frame, even when redlines are hidden a...
Definition: txtfrm.hxx:991
#define STR_SW_EVENT_LAYOUT_FINISHED
Definition: swevent.hxx:32
tools::Long SwTwips
Definition: swtypes.hxx:51
constexpr sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:57