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
552 if (lcl_isLayoutLooping()) return;
553
554 if (!bTakeShortcut)
555 {
556 while ( !IsInterrupt() && !IsNextCycle() &&
557 ((pPage->GetSortedObjs() && pPage->IsInvalidFly()) || pPage->IsInvalid()) )
558 {
560
561 SwObjectFormatter::FormatObjsAtFrame( *pPage, *pPage, this );
562 if ( !pPage->GetSortedObjs() )
563 {
564 // If there are no (more) Flys, the flags are superfluous.
565 pPage->ValidateFlyLayout();
566 pPage->ValidateFlyContent();
567 }
568 // change condition
569 while ( !IsInterrupt() && !IsNextCycle() &&
570 ( pPage->IsInvalid() ||
571 (pPage->GetSortedObjs() && pPage->IsInvalidFly()) ) )
572 {
573 PROTOCOL( pPage, PROT::FileInit, DbgAction::NONE, nullptr)
574 if (lcl_isLayoutLooping()) return;
575
576 // new loop control
577 int nLoopControlRuns_1 = 0;
578 const int nLoopControlMax = 20;
579
580 while ( !IsNextCycle() && pPage->IsInvalidLayout() )
581 {
582 pPage->ValidateLayout();
583
584 if ( ++nLoopControlRuns_1 > nLoopControlMax )
585 {
586 OSL_FAIL( "LoopControl_1 in SwLayAction::InternalAction" );
587 break;
588 }
589
590 FormatLayout( pRenderContext, pPage );
591 if (lcl_isLayoutLooping()) return;
592 }
593 // change condition
594 if ( !IsNextCycle() &&
595 ( pPage->IsInvalidContent() ||
596 (pPage->GetSortedObjs() && pPage->IsInvalidFly()) ) )
597 {
598 pPage->ValidateFlyInCnt();
599 pPage->ValidateContent();
600 pPage->ValidateFlyLayout();
601 pPage->ValidateFlyContent();
602 if ( !FormatContent( pPage ) )
603 {
604 if (lcl_isLayoutLooping()) return;
605 pPage->InvalidateContent();
606 pPage->InvalidateFlyInCnt();
607 pPage->InvalidateFlyLayout();
608 pPage->InvalidateFlyContent();
609 if ( IsBrowseActionStop() )
610 m_bInterrupt = true;
611 }
612 }
613 if( bNoLoop )
614 rLayoutAccess.GetLayouter()->LoopControl( pPage );
615 }
616
618 }
619
620 // A previous page may be invalid again.
621 if (lcl_isLayoutLooping()) return;
622 if ( !pPage->GetSortedObjs() )
623 {
624 // If there are no (more) Flys, the flags are superfluous.
625 pPage->ValidateFlyLayout();
626 pPage->ValidateFlyContent();
627 }
628 if ( !IsInterrupt() )
629 {
630 SetNextCycle( false );
631
632 if ( m_nPreInvaPage != USHRT_MAX )
633 {
634 if( !IsComplete() && m_nPreInvaPage + 2 < nFirstPageNum )
635 {
637 SwPageFrame *pTmpPage = m_pImp->GetFirstVisPage(pRenderContext);
638 nFirstPageNum = pTmpPage->GetPhyPageNum();
639 if( m_nPreInvaPage < nFirstPageNum )
640 {
641 m_nPreInvaPage = nFirstPageNum;
642 pPage = pTmpPage;
643 }
644 }
645 while ( pPage->GetPrev() && pPage->GetPhyPageNum() > m_nPreInvaPage )
646 pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
647 m_nPreInvaPage = USHRT_MAX;
648 }
649
650 while ( pPage->GetPrev() &&
651 ( static_cast<SwPageFrame*>(pPage->GetPrev())->IsInvalid() ||
652 ( static_cast<SwPageFrame*>(pPage->GetPrev())->GetSortedObjs() &&
653 static_cast<SwPageFrame*>(pPage->GetPrev())->IsInvalidFly())) &&
654 (static_cast<SwPageFrame*>(pPage->GetPrev())->GetPhyPageNum() >=
655 nFirstPageNum) )
656 {
657 pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
658 }
659
660 // Continue to the next invalid page
661 while ( pPage && !pPage->IsInvalid() &&
662 (!pPage->GetSortedObjs() || !pPage->IsInvalidFly()) )
663 {
664 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
665 }
666 if( bNoLoop )
667 rLayoutAccess.GetLayouter()->LoopControl( pPage );
668 }
669 CheckIdleEnd();
670 }
671
672 if ((bTakeShortcut || !pPage) && !IsInterrupt() &&
674 {
675 // tdf#139426 allow suppression of AssertFlyPages
677 {
679 }
680 if ( m_pRoot->IsSuperfluous() )
681 {
682 bool bOld = IsAgain();
684 SetAgain(bOld);
685 }
686 if (lcl_isLayoutLooping()) return;
687 pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
688 while ( pPage && !pPage->IsInvalid() && !pPage->IsInvalidFly() )
689 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
690 while ( pPage && pPage->GetNext() &&
691 pPage->GetPhyPageNum() < nFirstPageNum )
692 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
693 }
694 else if (bTakeShortcut)
695 break;
696 }
697 if ( IsInterrupt() && pPage )
698 {
699 // If we have input, we don't want to format content anymore, but
700 // we still should clean the layout.
701 // Otherwise, the following situation might arise:
702 // The user enters some text at the end of the paragraph of the last
703 // page, causing the paragraph to create a Follow for the next page.
704 // Meanwhile the user continues typing, so we have input while
705 // still formatting.
706 // The paragraph on the new page has already been partially formatted,
707 // and the new page has been fully formatted and is set to CompletePaint,
708 // but hasn't added itself to the area to be output. Then we paint,
709 // the CompletePaint of the page is reset because the new paragraph
710 // already added itself, but the borders of the page haven't been painted
711 // yet.
712 // Oh well, with the inevitable following LayAction, the page doesn't
713 // register itself, because it's (LayoutFrame) flags have been reset
714 // already - the border of the page will never be painted.
715 SwPageFrame *pPg = pPage;
716 if (lcl_isLayoutLooping()) return;
717 const SwRect &rVis = m_pImp->GetShell()->VisArea();
718
719 while( pPg && pPg->getFrameArea().Bottom() < rVis.Top() )
720 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
721 if( pPg != pPage )
722 pPg = pPg ? static_cast<SwPageFrame*>(pPg->GetPrev()) : pPage;
723
724 // set flag for interrupt content formatting
726 tools::Long nBottom = rVis.Bottom();
727 // #i42586# - format current page, if idle action is active
728 // This is an optimization for the case that the interrupt is created by
729 // the move of a form control object, which is represented by a window.
730 while ( pPg && ( pPg->getFrameArea().Top() < nBottom ||
731 ( IsIdle() && pPg == pPage ) ) )
732 {
734
735 if (lcl_isLayoutLooping()) return;
736
737 // new loop control
738 int nLoopControlRuns_2 = 0;
739 const int nLoopControlMax = 20;
740
741 // special case: interrupt content formatting
742 // conditions are incorrect and are too strict.
743 // adjust interrupt formatting to normal page formatting - see above.
744 while ( ( mbFormatContentOnInterrupt &&
745 ( pPg->IsInvalid() ||
746 ( pPg->GetSortedObjs() && pPg->IsInvalidFly() ) ) ) ||
748 {
749 if (lcl_isLayoutLooping()) return;
750 // format also at-page anchored objects
751 SwObjectFormatter::FormatObjsAtFrame( *pPg, *pPg, this );
752 if ( !pPg->GetSortedObjs() )
753 {
754 pPg->ValidateFlyLayout();
755 pPg->ValidateFlyContent();
756 }
757
758 // new loop control
759 int nLoopControlRuns_3 = 0;
760
761 while ( pPg->IsInvalidLayout() )
762 {
763 pPg->ValidateLayout();
764
765 if ( ++nLoopControlRuns_3 > nLoopControlMax )
766 {
767 OSL_FAIL( "LoopControl_3 in Interrupt formatting in SwLayAction::InternalAction" );
768 break;
769 }
770
771 FormatLayout( pRenderContext, pPg );
772 if (lcl_isLayoutLooping()) return;
773 }
774
776 ( pPg->IsInvalidContent() ||
777 ( pPg->GetSortedObjs() && pPg->IsInvalidFly() ) ) )
778 {
779 pPg->ValidateFlyInCnt();
780 pPg->ValidateContent();
781 pPg->ValidateFlyLayout();
782 pPg->ValidateFlyContent();
783
784 if ( ++nLoopControlRuns_2 > nLoopControlMax )
785 {
786 OSL_FAIL( "LoopControl_2 in Interrupt formatting in SwLayAction::InternalAction" );
787 break;
788 }
789
790 if ( !FormatContent( pPg ) )
791 {
792 if (lcl_isLayoutLooping()) return;
793 pPg->InvalidateContent();
794 pPg->InvalidateFlyInCnt();
795 pPg->InvalidateFlyLayout();
797 }
798 // we are satisfied if the content is formatted once complete.
799 else
800 {
801 break;
802 }
803 }
804 }
805
807 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
808 }
809 // reset flag for special interrupt content formatting.
811 }
812 m_pOptTab = nullptr;
813 if( bNoLoop )
814 rLayoutAccess.GetLayouter()->EndLoopControl();
815}
816
818{
819
820 const SwPageFrame *pPage = nullptr;
821 if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() || pCnt->IsRetouche() )
822 {
823 const SwRect aOldRect( pCnt->UnionFrame( true ) );
824 const tools::Long nOldBottom = pCnt->getFrameArea().Top() + pCnt->getFramePrintArea().Bottom();
825 pCnt->Calc(m_pImp->GetShell()->GetOut());
826 if ( pCnt->getFrameArea().Bottom() < aOldRect.Bottom() )
827 pCnt->SetRetouche();
828
829 pPage = pCnt->FindPageFrame();
830 PaintContent( pCnt, pPage, aOldRect, nOldBottom );
831
832 if ( !pCnt->GetValidLineNumFlag() && pCnt->IsTextFrame() )
833 {
834 const sal_uLong nAllLines = static_cast<const SwTextFrame*>(pCnt)->GetAllLines();
835 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCnt))->RecalcAllLines();
836 if ( nAllLines != static_cast<const SwTextFrame*>(pCnt)->GetAllLines() )
837 {
838 if ( IsPaintExtraData() )
840 // This is to calculate the remaining LineNums on the page,
841 // and we don't stop processing here. To perform this inside RecalcAllLines
842 // would be expensive, because we would have to notify the page even
843 // in unnecessary cases (normal actions).
844 const SwContentFrame *pNxt = pCnt->GetNextContentFrame();
845 while ( pNxt &&
846 (pNxt->IsInTab() || pNxt->IsInDocBody() != pCnt->IsInDocBody()) )
847 pNxt = pNxt->GetNextContentFrame();
848 if ( pNxt )
849 pNxt->InvalidatePage();
850 }
851 return false;
852 }
853
854 if ( pPage->IsInvalidLayout() || (pPage->GetSortedObjs() && pPage->IsInvalidFly()) )
855 return false;
856 }
857 if ( !pPage )
858 pPage = pCnt->FindPageFrame();
859
860 // format floating screen objects at content frame.
861 if ( pCnt->IsTextFrame() &&
863 *pPage, this ) )
864 {
865 return false;
866 }
867
868 if ( pPage->IsInvalidContent() )
869 return false;
870 return true;
871}
872
874{
875 bool bRet = true;
876
877 if ( m_pRoot->GetTurbo() )
878 {
879 if ( !TurboAction_( m_pRoot->GetTurbo() ) )
880 {
881 CheckIdleEnd();
882 bRet = false;
883 }
885 }
886 else
887 bRet = false;
888 return bRet;
889}
890
891static bool lcl_IsInvaLay( const SwFrame *pFrame, tools::Long nBottom )
892{
893 return !pFrame->isFrameAreaDefinitionValid() ||
894 (pFrame->IsCompletePaint() && ( pFrame->getFrameArea().Top() < nBottom ) );
895}
896
897static const SwFrame *lcl_FindFirstInvaLay( const SwFrame *pFrame, tools::Long nBottom )
898{
899 OSL_ENSURE( pFrame->IsLayoutFrame(), "FindFirstInvaLay, no LayFrame" );
900
901 if (lcl_IsInvaLay(pFrame, nBottom))
902 return pFrame;
903 pFrame = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
904 while ( pFrame )
905 {
906 if ( pFrame->IsLayoutFrame() )
907 {
908 if (lcl_IsInvaLay(pFrame, nBottom))
909 return pFrame;
910 const SwFrame *pTmp = lcl_FindFirstInvaLay( pFrame, nBottom );
911 if ( nullptr != pTmp )
912 return pTmp;
913 }
914 pFrame = pFrame->GetNext();
915 }
916 return nullptr;
917}
918
919static const SwFrame *lcl_FindFirstInvaContent( const SwLayoutFrame *pLay, tools::Long nBottom,
920 const SwContentFrame *pFirst )
921{
922 const SwContentFrame *pCnt = pFirst ? pFirst->GetNextContentFrame() :
923 pLay->ContainsContent();
924 while ( pCnt )
925 {
926 if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() )
927 {
928 if ( pCnt->getFrameArea().Top() <= nBottom )
929 return pCnt;
930 }
931
932 if ( pCnt->GetDrawObjs() )
933 {
934 const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
935 for (SwAnchoredObject* pObj : rObjs)
936 {
937 if ( auto pFly = pObj->DynCastFlyFrame() )
938 {
939 if ( pFly->IsFlyInContentFrame() )
940 {
941 if ( static_cast<const SwFlyInContentFrame*>(pFly)->IsInvalid() ||
942 pFly->IsCompletePaint() )
943 {
944 if ( pFly->getFrameArea().Top() <= nBottom )
945 return pFly;
946 }
947 const SwFrame *pFrame = lcl_FindFirstInvaContent( pFly, nBottom, nullptr );
948 if ( pFrame && pFrame->getFrameArea().Bottom() <= nBottom )
949 return pFrame;
950 }
951 }
952 }
953 }
954 if ( pCnt->getFrameArea().Top() > nBottom && !pCnt->IsInTab() )
955 return nullptr;
956 pCnt = pCnt->GetNextContentFrame();
957 if ( !pLay->IsAnLower( pCnt ) )
958 break;
959 }
960 return nullptr;
961}
962
963// consider drawing objects
965 tools::Long _nBottom )
966{
967 OSL_ENSURE( _pPage->GetSortedObjs(), "FindFirstInvaObj, no Objs" );
968
969 for (SwAnchoredObject* pObj : *_pPage->GetSortedObjs())
970 {
971 if ( auto pFly = pObj->DynCastFlyFrame() )
972 {
973 if ( pFly->getFrameArea().Top() <= _nBottom )
974 {
975 if ( pFly->IsInvalid() || pFly->IsCompletePaint() )
976 return pFly;
977
978 const SwFrame* pTmp;
979 if ( nullptr != (pTmp = lcl_FindFirstInvaContent( pFly, _nBottom, nullptr )) &&
980 pTmp->getFrameArea().Top() <= _nBottom )
981 return pFly;
982 }
983 }
984 else if ( auto pDrawObject = dynamic_cast< const SwAnchoredDrawObject *>( pObj ) )
985 {
986 if ( !pDrawObject->IsValidPos() )
987 {
988 return pObj;
989 }
990 }
991 }
992 return nullptr;
993}
994
995/* Returns True if the page lies directly below or right of the visible area.
996 *
997 * It's possible for things to change in such a way that the processing
998 * (of the caller!) has to continue with the predecessor of the passed page.
999 * The parameter might therefore get modified!
1000 * For BrowseMode, you may even activate the ShortCut if the invalid content
1001 * of the page lies below the visible area.
1002 */
1004{
1005 vcl::RenderContext* pRenderContext = m_pImp->GetShell()->GetOut();
1006 bool bRet = false;
1007 const SwViewShell *pSh = m_pRoot->GetCurrShell();
1008 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
1009
1010 // If the page is not valid, we quickly format it, otherwise
1011 // there's gonna be no end of trouble
1012 if ( !prPage->isFrameAreaDefinitionValid() )
1013 {
1014 if ( bBrowse )
1015 {
1016 // format complete page
1017 // Thus, loop on all lowers of the page <prPage>, instead of only
1018 // format its first lower.
1019 // NOTE: In online layout (bBrowse == true) a page can contain
1020 // a header frame and/or a footer frame beside the body frame.
1021 prPage->Calc(pRenderContext);
1022 SwFrame* pPageLowerFrame = prPage->Lower();
1023 while ( pPageLowerFrame )
1024 {
1025 pPageLowerFrame->Calc(pRenderContext);
1026 pPageLowerFrame = pPageLowerFrame->GetNext();
1027 }
1028 }
1029 else
1030 FormatLayout( pSh ? pSh->GetOut() : nullptr, prPage );
1031 if ( IsAgain() )
1032 return false;
1033 }
1034
1035 const SwRect &rVis = m_pImp->GetShell()->VisArea();
1036 if ( (prPage->getFrameArea().Top() >= rVis.Bottom()) ||
1037 (prPage->getFrameArea().Left()>= rVis.Right()) )
1038 {
1039 bRet = true;
1040
1041 // This is going to be a bit nasty: The first ContentFrame of this
1042 // page in the Body text needs formatting; if it changes the page during
1043 // that process, I need to start over a page further back, because we
1044 // have been processing a PageBreak.
1045 // Even more uncomfortable: The next ContentFrame must be formatted,
1046 // because it's possible for empty pages to exist temporarily (for example
1047 // a paragraph across multiple pages gets deleted or reduced in size).
1048
1049 // This is irrelevant for the browser, if the last Cnt above it
1050 // isn't visible anymore.
1051
1052 const SwPageFrame *p2ndPage = prPage;
1053 const SwContentFrame *pContent;
1054 const SwLayoutFrame* pBody = p2ndPage->FindBodyCont();
1055 if( p2ndPage->IsFootnotePage() && pBody )
1056 pBody = static_cast<const SwLayoutFrame*>(pBody->GetNext());
1057 pContent = pBody ? pBody->ContainsContent() : nullptr;
1058 while ( p2ndPage && !pContent )
1059 {
1060 p2ndPage = static_cast<const SwPageFrame*>(p2ndPage->GetNext());
1061 if( p2ndPage )
1062 {
1063 pBody = p2ndPage->FindBodyCont();
1064 if( p2ndPage->IsFootnotePage() && pBody )
1065 pBody = static_cast<const SwLayoutFrame*>(pBody->GetNext());
1066 pContent = pBody ? pBody->ContainsContent() : nullptr;
1067 }
1068 }
1069 if ( pContent )
1070 {
1071 bool bTstCnt = true;
1072 if ( bBrowse )
1073 {
1074 // Is the Cnt before already invisible?
1075 const SwFrame *pLst = pContent;
1076 if ( pLst->IsInTab() )
1077 pLst = pContent->FindTabFrame();
1078 if ( pLst->IsInSct() )
1079 pLst = pContent->FindSctFrame();
1080 pLst = pLst->FindPrev();
1081 if ( pLst &&
1082 (pLst->getFrameArea().Top() >= rVis.Bottom() ||
1083 pLst->getFrameArea().Left()>= rVis.Right()) )
1084 {
1085 bTstCnt = false;
1086 }
1087 }
1088
1089 if ( bTstCnt )
1090 {
1091 // check after each frame calculation,
1092 // if the content frame has changed the page. If yes, no other
1093 // frame calculation is performed
1094 bool bPageChg = false;
1095
1096 if ( pContent->IsInSct() )
1097 {
1098 const SwSectionFrame *pSct = const_cast<SwFrame*>(static_cast<SwFrame const *>(pContent))->ImplFindSctFrame();
1099 if ( !pSct->isFrameAreaDefinitionValid() )
1100 {
1101 pSct->Calc(pRenderContext);
1102 pSct->SetCompletePaint();
1103 if ( IsAgain() )
1104 return false;
1105
1106 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1107 prPage->GetPrev();
1108 }
1109 }
1110
1111 if ( !bPageChg && !pContent->isFrameAreaDefinitionValid() )
1112 {
1113 pContent->Calc(pRenderContext);
1114 pContent->SetCompletePaint();
1115 if ( IsAgain() )
1116 return false;
1117
1118 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1119 prPage->GetPrev();
1120 }
1121
1122 if ( !bPageChg && pContent->IsInTab() )
1123 {
1124 const SwTabFrame *pTab = const_cast<SwFrame*>(static_cast<SwFrame const *>(pContent))->ImplFindTabFrame();
1125 if ( !pTab->isFrameAreaDefinitionValid() )
1126 {
1127 pTab->Calc(pRenderContext);
1128 pTab->SetCompletePaint();
1129 if ( IsAgain() )
1130 return false;
1131
1132 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1133 prPage->GetPrev();
1134 }
1135 }
1136
1137 if ( !bPageChg && pContent->IsInSct() )
1138 {
1139 const SwSectionFrame *pSct = const_cast<SwFrame*>(static_cast<SwFrame const *>(pContent))->ImplFindSctFrame();
1140 if ( !pSct->isFrameAreaDefinitionValid() )
1141 {
1142 pSct->Calc(pRenderContext);
1143 pSct->SetCompletePaint();
1144 if ( IsAgain() )
1145 return false;
1146
1147 bPageChg = pContent->FindPageFrame() != p2ndPage &&
1148 prPage->GetPrev();
1149 }
1150 }
1151
1152 if ( bPageChg )
1153 {
1154 bRet = false;
1155 const SwPageFrame* pTmp = pContent->FindPageFrame();
1156 if ( pTmp->GetPhyPageNum() < prPage->GetPhyPageNum() &&
1157 pTmp->IsInvalid() )
1158 {
1159 prPage = const_cast<SwPageFrame*>(pTmp);
1160 }
1161 else
1162 {
1163 prPage = static_cast<SwPageFrame*>(prPage->GetPrev());
1164 }
1165 }
1166 // no shortcut, if at previous page
1167 // an anchored object is registered, whose anchor is <pContent>.
1168 else if ( prPage->GetPrev() )
1169 {
1170 SwSortedObjs* pObjs =
1171 static_cast<SwPageFrame*>(prPage->GetPrev())->GetSortedObjs();
1172 if ( pObjs )
1173 {
1174 for (SwAnchoredObject* pObj : *pObjs)
1175 {
1176 if ( pObj->GetAnchorFrameContainingAnchPos() == pContent )
1177 {
1178 bRet = false;
1179 break;
1180 }
1181 }
1182 }
1183 }
1184 }
1185 }
1186 }
1187
1188 if ( !bRet && bBrowse )
1189 {
1190 const tools::Long nBottom = rVis.Bottom();
1191 const SwAnchoredObject* pObj( nullptr );
1192 if ( prPage->GetSortedObjs() &&
1193 (prPage->IsInvalidFlyLayout() || prPage->IsInvalidFlyContent()) &&
1194 nullptr != (pObj = lcl_FindFirstInvaObj( prPage, nBottom )) &&
1195 pObj->GetObjRect().Top() <= nBottom )
1196 {
1197 return false;
1198 }
1199 const SwFrame* pFrame( nullptr );
1200 if ( prPage->IsInvalidLayout() &&
1201 nullptr != (pFrame = lcl_FindFirstInvaLay( prPage, nBottom )) &&
1202 pFrame->getFrameArea().Top() <= nBottom )
1203 {
1204 return false;
1205 }
1206 if ( (prPage->IsInvalidContent() || prPage->IsInvalidFlyInCnt()) &&
1207 nullptr != (pFrame = lcl_FindFirstInvaContent( prPage, nBottom, nullptr )) &&
1208 pFrame->getFrameArea().Top() <= nBottom )
1209 {
1210 return false;
1211 }
1212 bRet = true;
1213 }
1214 return bRet;
1215}
1216
1217// introduce support for vertical layout
1218bool SwLayAction::FormatLayout( OutputDevice *pRenderContext, SwLayoutFrame *pLay, bool bAddRect )
1219{
1220 OSL_ENSURE( !IsAgain(), "Attention to the invalid page." );
1221 if ( IsAgain() )
1222 return false;
1223
1224 bool bChanged = false;
1225 bool bAlreadyPainted = false;
1226 // remember frame at complete paint
1227 SwRect aFrameAtCompletePaint;
1228
1229 if ( !pLay->isFrameAreaDefinitionValid() || pLay->IsCompletePaint() )
1230 {
1231 if ( pLay->GetPrev() && !pLay->GetPrev()->isFrameAreaDefinitionValid() )
1232 pLay->GetPrev()->SetCompletePaint();
1233
1234 SwRect aOldFrame( pLay->getFrameArea() );
1235 SwRect aOldRect( aOldFrame );
1236 if( pLay->IsPageFrame() )
1237 {
1238 aOldRect = static_cast<SwPageFrame*>(pLay)->GetBoundRect(pRenderContext);
1239 }
1240
1241 {
1242 SwFrameDeleteGuard aDeleteGuard(pLay);
1243 pLay->Calc(pRenderContext);
1244 }
1245
1246 if ( aOldFrame != pLay->getFrameArea() )
1247 bChanged = true;
1248
1249 bool bNoPaint = false;
1250 if ( pLay->IsPageBodyFrame() &&
1251 pLay->getFrameArea().Pos() == aOldRect.Pos() &&
1252 pLay->Lower() )
1253 {
1254 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
1255 // Limitations because of headers / footers
1256 if( pSh && pSh->GetViewOptions()->getBrowseMode() &&
1257 !( pLay->IsCompletePaint() && pLay->FindPageFrame()->FindFootnoteCont() ) )
1258 bNoPaint = true;
1259 }
1260
1261 if ( !bNoPaint && IsPaint() && bAddRect && (pLay->IsCompletePaint() || bChanged) )
1262 {
1263 SwRect aPaint( pLay->getFrameArea() );
1264 // consider border and shadow for
1265 // page frames -> enlarge paint rectangle correspondingly.
1266 if ( pLay->IsPageFrame() )
1267 {
1268 SwPageFrame* pPageFrame = static_cast<SwPageFrame*>(pLay);
1269 aPaint = pPageFrame->GetBoundRect(pRenderContext);
1270 }
1271
1272 bool bPageInBrowseMode = pLay->IsPageFrame();
1273 if( bPageInBrowseMode )
1274 {
1275 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
1276 if( !pSh || !pSh->GetViewOptions()->getBrowseMode() )
1277 bPageInBrowseMode = false;
1278 }
1279 if( bPageInBrowseMode )
1280 {
1281 // NOTE: no vertical layout in online layout
1282 // Is the change even visible?
1283 if ( pLay->IsCompletePaint() )
1284 {
1285 m_pImp->GetShell()->AddPaintRect( aPaint );
1286 bAddRect = false;
1287 }
1288 else
1289 {
1290 SwRegionRects aRegion( aOldRect );
1291 aRegion -= aPaint;
1292 for ( size_t i = 0; i < aRegion.size(); ++i )
1293 m_pImp->GetShell()->AddPaintRect( aRegion[i] );
1294 aRegion.ChangeOrigin( aPaint );
1295 aRegion.clear();
1296 aRegion.push_back( aPaint );
1297 aRegion -= aOldRect;
1298 for ( size_t i = 0; i < aRegion.size(); ++i )
1299 m_pImp->GetShell()->AddPaintRect( aRegion[i] );
1300 }
1301 }
1302 else
1303 {
1304 m_pImp->GetShell()->AddPaintRect( aPaint );
1305 bAlreadyPainted = true;
1306 // remember frame at complete paint
1307 aFrameAtCompletePaint = pLay->getFrameArea();
1308 }
1309
1310 // provide paint of spacing
1311 // between pages (not only for in online mode).
1312 if ( pLay->IsPageFrame() )
1313 {
1314 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
1315 const SwTwips nHalfDocBorder = pSh ? pSh->GetViewOptions()->GetGapBetweenPages()
1317 const bool bLeftToRightViewLayout = m_pRoot->IsLeftToRightViewLayout();
1318 const bool bPrev = bLeftToRightViewLayout ? pLay->GetPrev() : pLay->GetNext();
1319 const bool bNext = bLeftToRightViewLayout ? pLay->GetNext() : pLay->GetPrev();
1320 SwPageFrame* pPageFrame = static_cast<SwPageFrame*>(pLay);
1321 SwRect aPageRect( pLay->getFrameArea() );
1322
1323 if(pSh)
1324 {
1326 pRenderContext,
1327 aPageRect, pPageFrame->IsLeftShadowNeeded(), pPageFrame->IsRightShadowNeeded(),
1329 }
1330
1331 if ( bPrev )
1332 {
1333 // top
1334 SwRect aSpaceToPrevPage( aPageRect );
1335 aSpaceToPrevPage.Top( aSpaceToPrevPage.Top() - nHalfDocBorder );
1336 aSpaceToPrevPage.Bottom( pLay->getFrameArea().Top() );
1337 if(!aSpaceToPrevPage.IsEmpty())
1338 m_pImp->GetShell()->AddPaintRect( aSpaceToPrevPage );
1339
1340 // left
1341 aSpaceToPrevPage = aPageRect;
1342 aSpaceToPrevPage.Left( aSpaceToPrevPage.Left() - nHalfDocBorder );
1343 aSpaceToPrevPage.Right( pLay->getFrameArea().Left() );
1344 if(!aSpaceToPrevPage.IsEmpty())
1345 m_pImp->GetShell()->AddPaintRect( aSpaceToPrevPage );
1346 }
1347 if ( bNext )
1348 {
1349 // bottom
1350 SwRect aSpaceToNextPage( aPageRect );
1351 aSpaceToNextPage.Bottom( aSpaceToNextPage.Bottom() + nHalfDocBorder );
1352 aSpaceToNextPage.Top( pLay->getFrameArea().Bottom() );
1353 if(!aSpaceToNextPage.IsEmpty())
1354 m_pImp->GetShell()->AddPaintRect( aSpaceToNextPage );
1355
1356 // right
1357 aSpaceToNextPage = aPageRect;
1358 aSpaceToNextPage.Right( aSpaceToNextPage.Right() + nHalfDocBorder );
1359 aSpaceToNextPage.Left( pLay->getFrameArea().Right() );
1360 if(!aSpaceToNextPage.IsEmpty())
1361 m_pImp->GetShell()->AddPaintRect( aSpaceToNextPage );
1362 }
1363 }
1364 }
1365 pLay->ResetCompletePaint();
1366 }
1367
1368 if ( IsPaint() && bAddRect &&
1369 !pLay->GetNext() && pLay->IsRetoucheFrame() && pLay->IsRetouche() )
1370 {
1371 // vertical layout support
1372 SwRectFnSet aRectFnSet(pLay);
1373 SwRect aRect( pLay->GetUpper()->GetPaintArea() );
1374 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pLay) );
1375 if ( !m_pImp->GetShell()->AddPaintRect( aRect ) )
1376 pLay->ResetRetouche();
1377 }
1378
1379 if( bAlreadyPainted )
1380 bAddRect = false;
1381
1383
1384 if ( IsAgain() )
1385 return false;
1386
1387 // Now, deal with the lowers that are LayoutFrames
1388
1389 if ( pLay->IsFootnoteFrame() ) // no LayFrames as Lower
1390 return bChanged;
1391
1392 SwFrame *pLow = pLay->Lower();
1393 bool bTabChanged = false;
1394 while ( pLow && pLow->GetUpper() == pLay )
1395 {
1396 SwFrame* pNext = nullptr;
1397 if ( pLow->IsLayoutFrame() )
1398 {
1399 if ( pLow->IsTabFrame() )
1400 {
1401 // Remember what was the next of the lower. Formatting may move it to the previous
1402 // page, in which case it looses its next.
1403 pNext = pLow->GetNext();
1404
1405 if (pNext && pNext->IsTabFrame())
1406 {
1407 auto pTab = static_cast<SwTabFrame*>(pNext);
1408 if (pTab->IsFollow())
1409 {
1410 // The next frame is a follow of the previous frame, SwTabFrame::Join() will
1411 // delete this one as part of formatting, so forget about it.
1412 pNext = nullptr;
1413 }
1414 }
1415
1416 bTabChanged |= FormatLayoutTab( static_cast<SwTabFrame*>(pLow), bAddRect );
1417 }
1418 // Skip the ones already registered for deletion
1419 else if( !pLow->IsSctFrame() || static_cast<SwSectionFrame*>(pLow)->GetSection() )
1420 {
1421 PushFormatLayout(pLow);
1422 bChanged |= FormatLayout( pRenderContext, static_cast<SwLayoutFrame*>(pLow), bAddRect );
1424 }
1425 }
1426 else if ( m_pImp->GetShell()->IsPaintLocked() )
1427 // Shortcut to minimize the cycles. With Lock, the
1428 // paint is coming either way (primarily for browse)
1429 pLow->OptCalc();
1430
1431 if ( IsAgain() )
1432 return false;
1433 if (!pNext)
1434 {
1435 pNext = pLow->GetNext();
1436 }
1437 pLow = pNext;
1438 }
1439 // add complete frame area as paint area, if frame
1440 // area has been already added and after formatting its lowers the frame area
1441 // is enlarged.
1442 SwRect aBoundRect(pLay->IsPageFrame() ? static_cast<SwPageFrame*>(pLay)->GetBoundRect(pRenderContext) : pLay->getFrameArea() );
1443
1444 if ( bAlreadyPainted &&
1445 ( aBoundRect.Width() > aFrameAtCompletePaint.Width() ||
1446 aBoundRect.Height() > aFrameAtCompletePaint.Height() )
1447 )
1448 {
1449 m_pImp->GetShell()->AddPaintRect( aBoundRect );
1450 }
1451 return bChanged || bTabChanged;
1452}
1453
1455{
1456 vcl::RenderContext* pRenderContext = m_pImp->GetShell()->GetOut();
1457 OSL_ENSURE( !IsAgain(), "Attention to the invalid page." );
1458 if ( IsAgain() )
1459 return;
1460
1461 bool bChanged = false;
1462 bool bAddRect = true;
1463
1464 if ( !pFly->isFrameAreaDefinitionValid() || pFly->IsCompletePaint() || pFly->IsInvalid() )
1465 {
1466 // The Frame has changed, now it's getting formatted.
1467 const SwRect aOldRect( pFly->getFrameArea() );
1468 pFly->Calc(pRenderContext);
1469 bChanged = aOldRect != pFly->getFrameArea();
1470
1471 if ( IsPaint() && (pFly->IsCompletePaint() || bChanged) &&
1472 pFly->getFrameArea().Top() > 0 && pFly->getFrameArea().Left() > 0 )
1474
1475 if ( bChanged )
1476 pFly->Invalidate();
1477 else
1478 pFly->Validate();
1479
1480 bAddRect = false;
1481 pFly->ResetCompletePaint();
1482 }
1483
1484 if ( IsAgain() )
1485 return;
1486
1487 // Now, deal with the lowers that are LayoutFrames
1488 SwFrame *pLow = pFly->Lower();
1489 while ( pLow )
1490 {
1491 if ( pLow->IsLayoutFrame() )
1492 {
1493 if ( pLow->IsTabFrame() )
1494 FormatLayoutTab( static_cast<SwTabFrame*>(pLow), bAddRect );
1495 else
1496 FormatLayout( m_pImp->GetShell()->GetOut(), static_cast<SwLayoutFrame*>(pLow), bAddRect );
1497 }
1498 pLow = pLow->GetNext();
1499 }
1500}
1501
1502// Implement vertical layout support
1503bool SwLayAction::FormatLayoutTab( SwTabFrame *pTab, bool bAddRect )
1504{
1505 OSL_ENSURE( !IsAgain(), "8-) Attention to the invalid page." );
1506 if ( IsAgain() || !pTab->Lower() )
1507 return false;
1508
1509 vcl::RenderContext* pRenderContext = m_pImp->GetShell()->GetOut();
1511 rTimerAccess.BlockIdling();
1512
1513 bool bChanged = false;
1514 bool bPainted = false;
1515
1516 const SwPageFrame *pOldPage = pTab->FindPageFrame();
1517
1518 // vertical layout support
1519 SwRectFnSet aRectFnSet(pTab);
1520
1521 if ( !pTab->isFrameAreaDefinitionValid() || pTab->IsCompletePaint() || pTab->IsComplete() )
1522 {
1523 if ( pTab->GetPrev() && !pTab->GetPrev()->isFrameAreaDefinitionValid() )
1524 {
1525 pTab->GetPrev()->SetCompletePaint();
1526 }
1527
1528 const SwRect aOldRect( pTab->getFrameArea() );
1529 pTab->SetLowersFormatted( false );
1530 pTab->Calc(pRenderContext);
1531 if ( aOldRect != pTab->getFrameArea() )
1532 {
1533 bChanged = true;
1534 }
1535 const SwRect aPaintFrame = pTab->GetPaintArea();
1536
1537 if ( IsPaint() && bAddRect )
1538 {
1539 // add condition <pTab->getFrameArea().HasArea()>
1540 if ( !pTab->IsCompletePaint() &&
1541 pTab->IsComplete() &&
1542 ( pTab->getFrameArea().SSize() != pTab->getFramePrintArea().SSize() ||
1543 // vertical layout support
1544 aRectFnSet.GetLeftMargin(*pTab) ) &&
1545 pTab->getFrameArea().HasArea()
1546 )
1547 {
1548 // re-implement calculation of margin rectangles.
1549 SwRect aMarginRect;
1550
1551 SwTwips nLeftMargin = aRectFnSet.GetLeftMargin(*pTab);
1552 if ( nLeftMargin > 0)
1553 {
1554 aMarginRect = pTab->getFrameArea();
1555 aRectFnSet.SetWidth( aMarginRect, nLeftMargin );
1556 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1557 }
1558
1559 if ( aRectFnSet.GetRightMargin(*pTab) > 0)
1560 {
1561 aMarginRect = pTab->getFrameArea();
1562 aRectFnSet.SetLeft( aMarginRect, aRectFnSet.GetPrtRight(*pTab) );
1563 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1564 }
1565
1566 SwTwips nTopMargin = aRectFnSet.GetTopMargin(*pTab);
1567 if ( nTopMargin > 0)
1568 {
1569 aMarginRect = pTab->getFrameArea();
1570 aRectFnSet.SetHeight( aMarginRect, nTopMargin );
1571 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1572 }
1573
1574 if ( aRectFnSet.GetBottomMargin(*pTab) > 0)
1575 {
1576 aMarginRect = pTab->getFrameArea();
1577 aRectFnSet.SetTop( aMarginRect, aRectFnSet.GetPrtBottom(*pTab) );
1578 m_pImp->GetShell()->AddPaintRect( aMarginRect );
1579 }
1580 }
1581 else if ( pTab->IsCompletePaint() )
1582 {
1583 m_pImp->GetShell()->AddPaintRect( aPaintFrame );
1584 bAddRect = false;
1585 bPainted = true;
1586 }
1587
1588 if ( pTab->IsRetouche() && !pTab->GetNext() )
1589 {
1590 SwRect aRect( pTab->GetUpper()->GetPaintArea() );
1591 // vertical layout support
1592 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pTab) );
1593 if ( !m_pImp->GetShell()->AddPaintRect( aRect ) )
1594 pTab->ResetRetouche();
1595 }
1596 }
1597 else
1598 bAddRect = false;
1599
1600 if ( pTab->IsCompletePaint() && !m_pOptTab )
1601 m_pOptTab = pTab;
1602 pTab->ResetCompletePaint();
1603 }
1604 if ( IsPaint() && bAddRect && pTab->IsRetouche() && !pTab->GetNext() )
1605 {
1606 // set correct rectangle for retouche: area between bottom of table frame
1607 // and bottom of paint area of the upper frame.
1608 SwRect aRect( pTab->GetUpper()->GetPaintArea() );
1609 // vertical layout support
1610 aRectFnSet.SetTop( aRect, aRectFnSet.GetPrtBottom(*pTab) );
1611 if ( !m_pImp->GetShell()->AddPaintRect( aRect ) )
1612 pTab->ResetRetouche();
1613 }
1614
1616
1617 rTimerAccess.UnblockIdling();
1618
1619 // Ugly shortcut!
1620 if ( pTab->IsLowersFormatted() &&
1621 (bPainted || !m_pImp->GetShell()->VisArea().Overlaps( pTab->getFrameArea())) )
1622 return false;
1623
1624 // Now, deal with the lowers
1625 if ( IsAgain() )
1626 return false;
1627
1628 // for safety reasons:
1629 // check page number before formatting lowers.
1630 if ( pOldPage->GetPhyPageNum() > (pTab->FindPageFrame()->GetPhyPageNum() + 1) )
1631 SetNextCycle( true );
1632
1633 // format lowers, only if table frame is valid
1634 if ( pTab->isFrameAreaDefinitionValid() )
1635 {
1636 FlowFrameJoinLockGuard tabG(pTab); // tdf#124675 prevent Join() if pTab becomes empty
1637 SwLayoutFrame *pLow = static_cast<SwLayoutFrame*>(pTab->Lower());
1638 while ( pLow )
1639 {
1640 SwFrameDeleteGuard rowG(pLow); // tdf#124675 prevent RemoveFollowFlowLine()
1641 bChanged |= FormatLayout( m_pImp->GetShell()->GetOut(), pLow, bAddRect );
1642 if ( IsAgain() )
1643 return false;
1644 pLow = static_cast<SwLayoutFrame*>(pLow->GetNext());
1645 }
1646 }
1647
1648 return bChanged;
1649}
1650
1652{
1653 ::comphelper::ScopeGuard g([this, pPage]() {
1654 if (IsAgain())
1655 {
1656 return; // pPage probably deleted
1657 }
1658 if (auto const* pObjs = pPage->GetSortedObjs())
1659 {
1660 std::vector<std::pair<SwAnchoredObject*, SwPageFrame*>> moved;
1661 for (auto const pObj : *pObjs)
1662 {
1663 assert(!pObj->AnchorFrame()->IsTextFrame()
1664 || !static_cast<SwTextFrame const*>(pObj->AnchorFrame())->IsFollow());
1665 SwPageFrame *const pAnchorPage(pObj->AnchorFrame()->FindPageFrame());
1666 assert(pAnchorPage);
1667 if (pAnchorPage != pPage
1668 && pPage->GetPhyPageNum() < pAnchorPage->GetPhyPageNum()
1669 && pObj->GetFrameFormat().GetAnchor().GetAnchorId()
1670 != RndStdIds::FLY_AS_CHAR)
1671 {
1672 moved.emplace_back(pObj, pAnchorPage);
1673 }
1674 }
1675 for (auto const& [pObj, pAnchorPage] : moved)
1676 {
1677 SAL_INFO("sw.layout", "SwLayAction::FormatContent: move anchored " << pObj << " from " << pPage->GetPhyPageNum() << " to " << pAnchorPage->GetPhyPageNum());
1678 pObj->RegisterAtPage(*pAnchorPage);
1679 // tdf#143239 if the position remains valid, it may not be
1680 // positioned again so would remain on the wrong page!
1681 pObj->InvalidateObjPos();
1682 ::Notify_Background(pObj->GetDrawObj(), pPage,
1683 pObj->GetObjRect(), PrepareHint::FlyFrameLeave, false);
1684 }
1685 if (!moved.empty())
1686 {
1687 pPage->InvalidateFlyLayout();
1688 if (auto *const pContent = pPage->FindLastBodyContent())
1689 {
1690 pContent->InvalidateSize();
1691 }
1692 }
1693 }
1694 });
1695
1696 const SwContentFrame *pContent = pPage->ContainsContent();
1697 const SwViewShell *pSh = m_pRoot->GetCurrShell();
1698 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
1699
1700 while ( pContent && pPage->IsAnLower( pContent ) )
1701 {
1702 // If the content didn't change, we can use a few shortcuts.
1703 const bool bFull = !pContent->isFrameAreaDefinitionValid() || pContent->IsCompletePaint() ||
1704 pContent->IsRetouche() || pContent->GetDrawObjs();
1705 if ( bFull )
1706 {
1707 // We do this so we don't have to search later on.
1708 const bool bNxtCnt = IsCalcLayout() && !pContent->GetFollow();
1709 const SwContentFrame *pContentNext = bNxtCnt ? pContent->GetNextContentFrame() : nullptr;
1710 SwContentFrame* const pContentPrev = pContent->GetPrev() ? pContent->GetPrevContentFrame() : nullptr;
1711 std::optional<SfxDeleteListener> oPrevDeleteListener;
1712 if (pContentPrev)
1713 oPrevDeleteListener.emplace(*pContentPrev);
1714
1715 const SwLayoutFrame*pOldUpper = pContent->GetUpper();
1716 const SwTabFrame *pTab = pContent->FindTabFrame();
1717 const bool bInValid = !pContent->isFrameAreaDefinitionValid() || pContent->IsCompletePaint();
1718 const bool bOldPaint = IsPaint();
1719 m_bPaint = bOldPaint && !(pTab && pTab == m_pOptTab);
1720 FormatContent_( pContent, pPage );
1721 // reset <bPaint> before format objects
1722 m_bPaint = bOldPaint;
1723
1724 // format floating screen object at content frame.
1725 // No format, if action flag <bAgain> is set or action is interrupted.
1726 // allow format on interruption of action, if
1727 // it's the format for this interrupt
1728 // pass correct page frame
1729 // to the object formatter.
1730 if ( !IsAgain() &&
1731 ( !IsInterrupt() || mbFormatContentOnInterrupt ) &&
1732 pContent->IsTextFrame() &&
1733 !SwObjectFormatter::FormatObjsAtFrame( *const_cast<SwContentFrame*>(pContent),
1734 *(pContent->FindPageFrame()), this ) )
1735 {
1736 return false;
1737 }
1738
1739 if ( !pContent->GetValidLineNumFlag() && pContent->IsTextFrame() )
1740 {
1741 const sal_uLong nAllLines = static_cast<const SwTextFrame*>(pContent)->GetAllLines();
1742 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pContent))->RecalcAllLines();
1743 if ( IsPaintExtraData() && IsPaint() &&
1744 nAllLines != static_cast<const SwTextFrame*>(pContent)->GetAllLines() )
1745 m_pImp->GetShell()->AddPaintRect( pContent->getFrameArea() );
1746 }
1747
1748 if ( IsAgain() )
1749 return false;
1750
1751 // Temporarily interrupt processing if layout or Flys become invalid again.
1752 // However not for the BrowseView: The layout is getting invalid
1753 // all the time because the page height gets adjusted.
1754 // The same applies if the user wants to continue working and at least one
1755 // paragraph has been processed.
1756 if (!pTab || !bInValid)
1757 {
1758 CheckIdleEnd();
1759 // consider interrupt formatting.
1760 if ( ( IsInterrupt() && !mbFormatContentOnInterrupt ) ||
1761 ( !bBrowse && pPage->IsInvalidLayout() ) ||
1762 // consider interrupt formatting
1763 ( pPage->GetSortedObjs() && pPage->IsInvalidFly() && !mbFormatContentOnInterrupt )
1764 )
1765 return false;
1766 }
1767 if ( pOldUpper != pContent->GetUpper() )
1768 {
1769 const sal_uInt16 nCurNum = pContent->FindPageFrame()->GetPhyPageNum();
1770 if ( nCurNum < pPage->GetPhyPageNum() )
1771 m_nPreInvaPage = nCurNum;
1772
1773 // If the frame flowed backwards more than one page, we need to
1774 // start over again from the beginning, so nothing gets left out.
1775 if ( !IsCalcLayout() && pPage->GetPhyPageNum() > nCurNum+1 )
1776 {
1777 SetNextCycle( true );
1778 // consider interrupt formatting
1779 if ( !mbFormatContentOnInterrupt )
1780 {
1781 return false;
1782 }
1783 }
1784 }
1785 // If the frame moved forwards to the next page, we re-run through
1786 // the predecessor.
1787 // This way, we catch predecessors which are now responsible for
1788 // retouching, but the footers will be touched also.
1789 bool bSetContent = true;
1790 if ( pContentPrev )
1791 {
1792 if (oPrevDeleteListener->WasDeleted())
1793 {
1794 SAL_WARN("sw", "ContentPrev was deleted");
1795 return false;
1796 }
1797
1798 if ( !pContentPrev->isFrameAreaDefinitionValid() && pPage->IsAnLower( pContentPrev ) )
1799 {
1800 pPage->InvalidateContent();
1801 }
1802
1803 if ( pOldUpper != pContent->GetUpper() &&
1804 pPage->GetPhyPageNum() < pContent->FindPageFrame()->GetPhyPageNum() )
1805 {
1806 pContent = pContentPrev;
1807 bSetContent = false;
1808 }
1809 }
1810 if ( bSetContent )
1811 {
1812 if ( bBrowse && !IsIdle() && !IsCalcLayout() && !IsComplete() &&
1813 pContent->getFrameArea().Top() > m_pImp->GetShell()->VisArea().Bottom())
1814 {
1815 const tools::Long nBottom = m_pImp->GetShell()->VisArea().Bottom();
1816 const SwFrame *pTmp = lcl_FindFirstInvaContent( pPage,
1817 nBottom, pContent );
1818 if ( !pTmp )
1819 {
1820 if ( (!(pPage->GetSortedObjs() && pPage->IsInvalidFly()) ||
1821 !lcl_FindFirstInvaObj( pPage, nBottom )) &&
1822 (!pPage->IsInvalidLayout() ||
1823 !lcl_FindFirstInvaLay( pPage, nBottom )))
1824 SetBrowseActionStop( true );
1825 // consider interrupt formatting.
1826 if ( !mbFormatContentOnInterrupt )
1827 {
1828 return false;
1829 }
1830 }
1831 }
1832 pContent = bNxtCnt ? pContentNext : pContent->GetNextContentFrame();
1833 }
1834
1835 if (IsReschedule())
1836 {
1837 ::RescheduleProgress(m_pImp->GetShell()->GetDoc()->GetDocShell());
1838 }
1839 }
1840 else
1841 {
1842 if ( !pContent->GetValidLineNumFlag() && pContent->IsTextFrame() )
1843 {
1844 const sal_uLong nAllLines = static_cast<const SwTextFrame*>(pContent)->GetAllLines();
1845 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pContent))->RecalcAllLines();
1846 if ( IsPaintExtraData() && IsPaint() &&
1847 nAllLines != static_cast<const SwTextFrame*>(pContent)->GetAllLines() )
1848 m_pImp->GetShell()->AddPaintRect( pContent->getFrameArea() );
1849 }
1850
1851 // Do this if the frame has been formatted before.
1852 if ( pContent->IsTextFrame() && static_cast<const SwTextFrame*>(pContent)->HasRepaint() &&
1853 IsPaint() )
1854 PaintContent( pContent, pPage, pContent->getFrameArea(), pContent->getFrameArea().Bottom());
1855 if ( IsIdle() )
1856 {
1857 CheckIdleEnd();
1858 // consider interrupt formatting.
1859 if ( IsInterrupt() && !mbFormatContentOnInterrupt )
1860 return false;
1861 }
1862 if ( bBrowse && !IsIdle() && !IsCalcLayout() && !IsComplete() &&
1863 pContent->getFrameArea().Top() > m_pImp->GetShell()->VisArea().Bottom())
1864 {
1865 const tools::Long nBottom = m_pImp->GetShell()->VisArea().Bottom();
1866 const SwFrame *pTmp = lcl_FindFirstInvaContent( pPage,
1867 nBottom, pContent );
1868 if ( !pTmp )
1869 {
1870 if ( (!(pPage->GetSortedObjs() && pPage->IsInvalidFly()) ||
1871 !lcl_FindFirstInvaObj( pPage, nBottom )) &&
1872 (!pPage->IsInvalidLayout() ||
1873 !lcl_FindFirstInvaLay( pPage, nBottom )))
1874 SetBrowseActionStop( true );
1875 // consider interrupt formatting.
1876 if ( !mbFormatContentOnInterrupt )
1877 {
1878 return false;
1879 }
1880 }
1881 }
1882 pContent = pContent->GetNextContentFrame();
1883 }
1884 }
1885 CheckWaitCursor();
1886 // consider interrupt formatting.
1887 return !IsInterrupt() || mbFormatContentOnInterrupt;
1888}
1889
1890void SwLayAction::FormatContent_( const SwContentFrame *pContent, const SwPageFrame *pPage )
1891{
1892 // We probably only ended up here because the Content holds DrawObjects.
1893 const bool bDrawObjsOnly = pContent->isFrameAreaDefinitionValid() && !pContent->IsCompletePaint() && !pContent->IsRetouche();
1894 SwRectFnSet aRectFnSet(pContent);
1895 if ( !bDrawObjsOnly && IsPaint() )
1896 {
1897 const SwRect aOldRect( pContent->UnionFrame() );
1898 const tools::Long nOldBottom = aRectFnSet.GetPrtBottom(*pContent);
1899 pContent->OptCalc();
1900 if( IsAgain() )
1901 return;
1902 if( aRectFnSet.YDiff( aRectFnSet.GetBottom(pContent->getFrameArea()),
1903 aRectFnSet.GetBottom(aOldRect) ) < 0 )
1904 {
1905 pContent->SetRetouche();
1906 }
1907 PaintContent( pContent, pContent->FindPageFrame(), aOldRect, nOldBottom);
1908 }
1909 else
1910 {
1911 if ( IsPaint() && pContent->IsTextFrame() && static_cast<const SwTextFrame*>(pContent)->HasRepaint() )
1912 PaintContent( pContent, pPage, pContent->getFrameArea(),
1913 aRectFnSet.GetBottom(pContent->getFrameArea()) );
1914 pContent->OptCalc();
1915 }
1916}
1917
1919{
1920 const SwContentFrame *pContent = pFly->ContainsContent();
1921
1922 while ( pContent )
1923 {
1924 FormatContent_( pContent, pContent->FindPageFrame() );
1925
1926 // format floating screen objects at content text frame
1927 // pass correct page frame to the object formatter.
1928 if ( pContent->IsTextFrame() &&
1930 *const_cast<SwContentFrame*>(pContent),
1931 *(pContent->FindPageFrame()), this ) )
1932 {
1933 // restart format with first content
1934 pContent = pFly->ContainsContent();
1935 continue;
1936 }
1937
1938 if ( !pContent->GetValidLineNumFlag() && pContent->IsTextFrame() )
1939 {
1940 const sal_uLong nAllLines = static_cast<const SwTextFrame*>(pContent)->GetAllLines();
1941 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pContent))->RecalcAllLines();
1942 if ( IsPaintExtraData() && IsPaint() &&
1943 nAllLines != static_cast<const SwTextFrame*>(pContent)->GetAllLines() )
1944 m_pImp->GetShell()->AddPaintRect( pContent->getFrameArea() );
1945 }
1946
1947 if ( IsAgain() )
1948 return;
1949
1950 // If there's input, we interrupt processing.
1951 if ( !pFly->IsFlyInContentFrame() )
1952 {
1953 CheckIdleEnd();
1954 // consider interrupt formatting.
1956 return;
1957 }
1958 pContent = pContent->GetNextContentFrame();
1959 }
1961}
1962
1964{
1965 OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
1966 // robust against misuse by e.g. #i52542#
1967 if( !pCnt->IsTextFrame() )
1968 return false;
1969
1970 SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pCnt));
1971 // sw_redlinehide: spell check only the nodes with visible content?
1972 SwTextNode* pTextNode = const_cast<SwTextNode*>(pTextFrame->GetTextNodeForParaProps());
1973
1974 bool bProcess = false;
1975 for (size_t i = 0; pTextNode; )
1976 {
1977 switch ( eJob )
1978 {
1980 bProcess = pTextNode->IsWrongDirty(); break;
1982 bProcess = pTextNode->IsAutoCompleteWordDirty(); break;
1984 bProcess = pTextNode->IsWordCountDirty(); break;
1986 bProcess = pTextNode->IsSmartTagDirty(); break;
1987 }
1988 if (bProcess)
1989 {
1990 break;
1991 }
1992 if (sw::MergedPara const* pMerged = pTextFrame->GetMergedPara())
1993 {
1994 while (true)
1995 {
1996 ++i;
1997 if (i < pMerged->extents.size())
1998 {
1999 if (pMerged->extents[i].pNode != pTextNode)
2000 {
2001 pTextNode = pMerged->extents[i].pNode;
2002 break;
2003 }
2004 }
2005 else
2006 {
2007 pTextNode = nullptr;
2008 break;
2009 }
2010 }
2011 }
2012 else
2013 pTextNode = nullptr;
2014 }
2015
2016 if( bProcess )
2017 {
2018 assert(pTextNode);
2019 SwViewShell *pSh = m_pImp->GetShell();
2021 {
2022 --m_nTextPos;
2023 if( auto pCursorShell = dynamic_cast<SwCursorShell *>( pSh ) )
2024 if( !pCursorShell->IsTableMode() )
2025 {
2026 SwPaM *pCursor = pCursorShell->GetCursor();
2027 if( !pCursor->HasMark() && !pCursor->IsMultiSelection() )
2028 {
2030 m_nTextPos = pCursor->GetPoint()->GetContentIndex();
2031 }
2032 }
2033 }
2034 sal_Int32 const nPos((m_pContentNode && pTextNode == m_pContentNode)
2035 ? m_nTextPos
2036 : COMPLETE_STRING);
2037
2038 switch ( eJob )
2039 {
2041 {
2042 SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->AutoSpell_(*pTextNode, nPos) );
2043 // PENDING should stop idle spell checking
2045 if ( aRepaint.HasArea() )
2046 m_pImp->GetShell()->InvalidateWindows( aRepaint );
2047 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
2048 return true;
2049 break;
2050 }
2052 const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
2053 // note: bPageValid remains true here even if the cursor
2054 // position is skipped, so no PENDING state needed currently
2055 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
2056 return true;
2057 break;
2059 {
2060 const sal_Int32 nEnd = pTextNode->GetText().getLength();
2061 SwDocStat aStat;
2062 pTextNode->CountWords( aStat, 0, nEnd );
2063 if ( Application::AnyInput() )
2064 return true;
2065 break;
2066 }
2068 {
2069 try {
2070 const SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->SmartTagScan(*pTextNode) );
2071 m_bPageValid = m_bPageValid && !pTextNode->IsSmartTagDirty();
2072 if ( aRepaint.HasArea() )
2073 m_pImp->GetShell()->InvalidateWindows( aRepaint );
2074 } catch( const css::uno::RuntimeException&) {
2075 // handle smarttag problems gracefully and provide diagnostics
2076 TOOLS_WARN_EXCEPTION( "sw.core", "SMART_TAGS");
2077 }
2078 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
2079 return true;
2080 break;
2081 }
2082 }
2083 }
2084
2085 // The Flys that are anchored to the paragraph need to be considered too.
2086 if ( pCnt->GetDrawObjs() )
2087 {
2088 const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
2089 for (SwAnchoredObject* pObj : rObjs)
2090 {
2091 if ( auto pFly = pObj->DynCastFlyFrame() )
2092 {
2093 if ( pFly->IsFlyInContentFrame() )
2094 {
2095 const SwContentFrame *pC = pFly->ContainsContent();
2096 while( pC )
2097 {
2098 if ( pC->IsTextFrame() )
2099 {
2100 if ( DoIdleJob_( pC, eJob ) )
2101 return true;
2102 }
2103 pC = pC->GetNextContentFrame();
2104 }
2105 }
2106 }
2107 }
2108 }
2109 return false;
2110}
2111
2113{
2114 switch (eJob)
2115 {
2117 {
2118 const SwViewOption* pViewOptions = pViewShell->GetViewOptions();
2119 return pViewOptions->IsOnlineSpell();
2120 }
2121
2123 {
2124 if (!SwViewOption::IsAutoCompleteWords() || SwDoc::GetAutoCompleteWords().IsLockWordLstLocked())
2125 return false;
2126 return true;
2127 }
2128
2130 {
2131 return pViewShell->getIDocumentStatistics().GetDocStat().bModified;
2132 }
2133
2135 {
2136 const SwDoc* pDoc = pViewShell->GetDoc();
2137 if (!pDoc->GetDocShell()->IsHelpDocument() || pDoc->isXForms() || !SwSmartTagMgr::Get().IsSmartTagsEnabled())
2138 return false;
2139 return true;
2140 }
2141 }
2142
2143 return false;
2144}
2145
2147{
2148 // Spellcheck all contents of the pages. Either only the
2149 // visible ones or all of them.
2150 const SwViewShell* pViewShell = m_pImp->GetShell();
2151
2152 // Check if job ius enabled and can run
2153 if (!isJobEnabled(eJob, pViewShell))
2154 return false;
2155
2156 SwPageFrame *pPage;
2157 if (eJobArea == IdleJobArea::VISIBLE)
2158 pPage = m_pImp->GetFirstVisPage(pViewShell->GetOut());
2159 else
2160 pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
2161
2162 m_pContentNode = nullptr;
2164
2165 while ( pPage )
2166 {
2167 m_bPageValid = true;
2168 const SwContentFrame* pContentFrame = pPage->ContainsContent();
2169 while (pContentFrame && pPage->IsAnLower(pContentFrame))
2170 {
2171 if (DoIdleJob_(pContentFrame, eJob))
2172 {
2173 SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
2174 return true;
2175 }
2176 pContentFrame = pContentFrame->GetNextContentFrame();
2177 }
2178 if ( pPage->GetSortedObjs() )
2179 {
2180 for ( size_t i = 0; pPage->GetSortedObjs() &&
2181 i < pPage->GetSortedObjs()->size(); ++i )
2182 {
2183 const SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i];
2184 if ( auto pFly = pObj->DynCastFlyFrame() )
2185 {
2186 const SwContentFrame *pC = pFly->ContainsContent();
2187 while( pC )
2188 {
2189 if ( pC->IsTextFrame() )
2190 {
2191 if ( DoIdleJob_( pC, eJob ) )
2192 {
2193 SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
2194 return true;
2195 }
2196 }
2197 pC = pC->GetNextContentFrame();
2198 }
2199 }
2200 }
2201 }
2202
2203 if( m_bPageValid )
2204 {
2205 switch (eJob)
2206 {
2208 pPage->ValidateSpelling();
2209 break;
2212 break;
2214 pPage->ValidateWordCount();
2215 break;
2217 pPage->ValidateSmartTags();
2218 break;
2219 }
2220 }
2221
2222 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
2223 if (pPage && eJobArea == IdleJobArea::VISIBLE &&
2224 !pPage->getFrameArea().Overlaps( m_pImp->GetShell()->VisArea()))
2225 {
2226 break;
2227 }
2228 }
2229 return false;
2230}
2231
2232#if HAVE_FEATURE_DESKTOP && defined DBG_UTIL
2233void SwLayIdle::ShowIdle( Color eColor )
2234{
2235 if ( m_bIndicator )
2236 return;
2237
2238 m_bIndicator = true;
2239 vcl::Window *pWin = m_pImp->GetShell()->GetWin();
2240 if (pWin && !pWin->SupportsDoubleBuffering()) // FIXME make this work with double-buffering
2241 {
2242 tools::Rectangle aRect( 0, 0, 5, 5 );
2243 aRect = pWin->PixelToLogic( aRect );
2244 // Depending on if idle layout is in progress or not, draw a "red square" or a "green square".
2246 pWin->GetOutDev()->SetFillColor( eColor );
2247 pWin->GetOutDev()->SetLineColor();
2248 pWin->GetOutDev()->DrawRect( aRect );
2249 pWin->GetOutDev()->Pop();
2250 }
2251}
2252#define SHOW_IDLE( Color ) ShowIdle( Color )
2253#else
2254#define SHOW_IDLE( Color )
2255#endif // DBG_UTIL
2256
2258 m_pRoot( pRt ),
2259 m_pImp( pI )
2260#ifdef DBG_UTIL
2261 , m_bIndicator( false )
2262#endif
2263{
2264 SAL_INFO("sw.idle", "SwLayIdle() entry");
2265
2266 m_pImp->m_pIdleAct = this;
2267
2269
2270 m_pImp->GetShell()->EnableSmooth( false );
2271
2272 // First, spellcheck the visible area. Only if there's nothing
2273 // to do there, we trigger the IdleFormat.
2277 {
2278 // Format, then register repaint rectangles with the SwViewShell if necessary.
2279 // This requires running artificial actions, so we don't get undesired
2280 // effects when for instance the page count gets changed.
2281 // We remember the shells where the cursor is visible, so we can make
2282 // it visible again if needed after a document change.
2283 std::vector<bool> aBools;
2285 {
2286 ++rSh.mnStartAction;
2287 bool bVis = false;
2288 if ( auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh) )
2289 {
2290 bVis = pCursorShell->GetCharRect().Overlaps(rSh.VisArea());
2291 }
2292 aBools.push_back( bVis );
2293 }
2294
2295 bool bInterrupt(false);
2296 {
2297 SwLayAction aAction( m_pRoot, m_pImp );
2298 aAction.SetInputType( VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER) );
2299 aAction.SetIdle( true );
2300 aAction.SetWaitAllowed( false );
2301 aAction.Action(m_pImp->GetShell()->GetOut());
2302 bInterrupt = aAction.IsInterrupt();
2303 }
2304
2305 // Further start/end actions only happen if there were paints started
2306 // somewhere or if the visibility of the CharRects has changed.
2307 bool bActions = false;
2308 size_t nBoolIdx = 0;
2310 {
2311 --rSh.mnStartAction;
2312
2313 if ( rSh.Imp()->HasPaintRegion() )
2314 bActions = true;
2315 else
2316 {
2317 SwRect aTmp( rSh.VisArea() );
2318 rSh.UISizeNotify();
2319
2320 // Are we supposed to crash if rSh isn't a cursor shell?!
2321 // bActions |= aTmp != rSh.VisArea() ||
2322 // aBools[nBoolIdx] != ((SwCursorShell*)&rSh)->GetCharRect().IsOver( rSh.VisArea() );
2323
2324 // aBools[ i ] is true, if the i-th shell is a cursor shell (!!!)
2325 // and the cursor is visible.
2326 bActions |= aTmp != rSh.VisArea();
2327 if ( aTmp == rSh.VisArea() )
2328 if ( auto pCursorShell = dynamic_cast< SwCursorShell*>( &rSh) )
2329 bActions |= aBools[nBoolIdx] != pCursorShell->GetCharRect().Overlaps( rSh.VisArea() );
2330 }
2331
2332 ++nBoolIdx;
2333 }
2334
2335 if ( bActions )
2336 {
2337 // Prepare start/end actions via CursorShell, so the cursor, selection
2338 // and VisArea can be set correctly.
2339 nBoolIdx = 0;
2341 {
2342 SwCursorShell* pCursorShell = dynamic_cast<SwCursorShell*>( &rSh);
2343
2344 if ( pCursorShell )
2345 pCursorShell->SttCursorMove();
2346
2347 // If there are accrued paints, it's best to simply invalidate
2348 // the whole window. Otherwise there would arise paint problems whose
2349 // solution would be disproportionally expensive.
2350 SwViewShellImp *pViewImp = rSh.Imp();
2351 bool bUnlock = false;
2352 if ( pViewImp->HasPaintRegion() )
2353 {
2354 pViewImp->DeletePaintRegion();
2355
2356 // Cause a repaint with virtual device.
2357 rSh.LockPaint();
2358 bUnlock = true;
2359 }
2360
2361 if ( pCursorShell )
2362 // If the Cursor was visible, we need to make it visible again.
2363 // Otherwise, EndCursorMove with true for IdleEnd
2364 pCursorShell->EndCursorMove( !aBools[nBoolIdx] );
2365 if( bUnlock )
2366 {
2367 if( pCursorShell )
2368 {
2369 // UnlockPaint overwrite the selection from the
2370 // CursorShell and calls the virtual method paint
2371 // to fill the virtual device. This fill don't have
2372 // paint the selection! -> Set the focus flag at
2373 // CursorShell and it doesn't paint the selection.
2374 pCursorShell->ShellLoseFocus();
2375 pCursorShell->UnlockPaint( true );
2376 pCursorShell->ShellGetFocus();
2377 }
2378 else
2379 rSh.UnlockPaint( true );
2380 }
2381 ++nBoolIdx;
2382
2383 }
2384 }
2385
2386 if (!bInterrupt)
2387 {
2392 }
2393
2394 bool bInValid = false;
2395 const SwViewOption& rVOpt = *m_pImp->GetShell()->GetViewOptions();
2396 const SwViewShell* pViewShell = m_pImp->GetShell();
2397 // See conditions in DoIdleJob()
2398 const bool bSpell = rVOpt.IsOnlineSpell();
2399 const bool bACmplWrd = SwViewOption::IsAutoCompleteWords();
2400 const bool bWordCount = pViewShell->getIDocumentStatistics().GetDocStat().bModified;
2401 const bool bSmartTags = !pViewShell->GetDoc()->GetDocShell()->IsHelpDocument() &&
2402 !pViewShell->GetDoc()->isXForms() &&
2404
2405 SwPageFrame *pPg = static_cast<SwPageFrame*>(m_pRoot->Lower());
2406 do
2407 {
2408 bInValid = pPg->IsInvalidContent() || pPg->IsInvalidLayout() ||
2409 pPg->IsInvalidFlyContent() || pPg->IsInvalidFlyLayout() ||
2410 pPg->IsInvalidFlyInCnt() ||
2411 (bSpell && pPg->IsInvalidSpelling()) ||
2412 (bACmplWrd && pPg->IsInvalidAutoCompleteWords()) ||
2413 (bWordCount && pPg->IsInvalidWordCount()) ||
2414 (bSmartTags && pPg->IsInvalidSmartTags());
2415
2416 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
2417
2418 } while ( pPg && !bInValid );
2419
2420 if ( !bInValid )
2421 {
2423 SfxObjectShell* pDocShell = m_pImp->GetShell()->GetDoc()->GetDocShell();
2424 pDocShell->Broadcast( SfxEventHint( SfxEventHintId::SwEventLayoutFinished, SwDocShell::GetEventName(STR_SW_EVENT_LAYOUT_FINISHED), pDocShell ) );
2425 }
2426 }
2427
2428 m_pImp->GetShell()->EnableSmooth( true );
2429
2430#if !ENABLE_WASM_STRIP_ACCESSIBILITY
2431 if( m_pImp->IsAccessible() )
2433#endif
2434
2435 SAL_INFO("sw.idle", "SwLayIdle() return");
2436
2437#ifdef DBG_UTIL
2438 if ( m_bIndicator && m_pImp->GetShell()->GetWin() )
2439 {
2440 // Do not invalidate indicator, this may cause an endless loop. Instead, just repaint it
2441 // This should be replaced by an overlay object in the future, anyways. Since it's only for debug
2442 // purposes, it is not urgent.
2444 }
2445#endif
2446}
2447
2449{
2450 m_pImp->m_pIdleAct = nullptr;
2451}
2452
2453/* 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:737
void SttCursorMove()
Definition: crsrsh.cxx:301
void ShellGetFocus()
Definition: crsrsh.cxx:2484
void ShellLoseFocus()
Definition: crsrsh.cxx:2477
void EndCursorMove(const bool bIdleEnd=false)
Definition: crsrsh.cxx:310
static OUString GetEventName(sal_Int32 nId)
Definition: docsh.cxx:1329
Definition: doc.hxx:195
static SwAutoCompleteWord & GetAutoCompleteWords()
Definition: doc.hxx:1552
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:645
bool isXForms() const
Definition: docxforms.cxx:44
SwDocShell * GetDocShell()
Definition: doc.hxx:1364
general base class for all free-flowing frames
Definition: flyfrm.hxx:79
void Validate() const
Definition: flyfrm.hxx:213
const SwVirtFlyDrawObj * GetVirtDrawObj() const
Definition: fly.cxx:2964
virtual const SwFlyFrameFormat * GetFormat() const override
Definition: fly.cxx:3058
bool IsBackgroundTransparent() const
SwFlyFrame::IsBackgroundTransparent.
Definition: paintfrm.cxx:3880
bool IsLowerOf(const SwLayoutFrame *pUpper) const
Definition: fly.cxx:2331
bool IsInvalid() const
Definition: flyfrm.hxx:211
bool IsFlyInContentFrame() const
Definition: flyfrm.hxx:218
void Invalidate() const
Definition: flyfrm.hxx:212
virtual void Calc(vcl::RenderContext *pRenderContext) const override
Definition: fly.cxx:3068
SwLayoutFrame * FindBodyCont()
Searches the first ContentFrame in BodyText below the page.
Definition: findfrm.cxx:48
SwFootnoteContFrame * FindFootnoteCont()
Definition: ftnfrm.cxx:1036
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:1066
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:1454
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:1918
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:1503
bool IsComplete() const
Definition: layact.hxx:171
bool TurboAction_(const SwContentFrame *)
Definition: layact.cxx:817
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:1651
bool IsShortCut(SwPageFrame *&)
Definition: layact.cxx:1003
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:873
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:1890
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:1218
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:2448
sal_Int32 m_nTextPos
Definition: layact.hxx:210
bool DoIdleJob_(const SwContentFrame *, IdleJobType)
Definition: layact.cxx:1963
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:2146
static bool isJobEnabled(IdleJobType eJob, const SwViewShell *pViewShell)
Definition: layact.cxx:2112
void ShowIdle(Color eName)
SwLayIdle(SwRootFrame *pRt, SwViewShellImp *pImp)
Definition: layact.cxx:2257
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:291
void EndLoopControl()
Definition: layouter.cxx:262
void LoopControl(SwPageFrame *pPage)
Definition: layouter.cxx:237
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:187
bool IsMultiSelection() const
Definition: pam.hxx:328
SwContentNode * GetPointContentNode() const
Definition: pam.hxx:287
const SwPosition * GetPoint() const
Definition: pam.hxx:261
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:259
A page of the document layout.
Definition: pagefrm.hxx:59
bool IsInvalidWordCount() const
Definition: pagefrm.hxx:240
void InvalidateContent() const
Definition: pagefrm.hxx:383
void ValidateFlyInCnt() const
Definition: pagefrm.hxx:412
SwContentFrame * FindLastBodyContent()
Searches the last ContentFrame in BodyText below the page.
Definition: findfrm.cxx:57
void ValidateContent() const
Definition: pagefrm.hxx:420
bool IsInvalid() const
Definition: pagefrm.hxx:442
void InvalidateFlyLayout() const
Validate, invalidate and query the Page status Layout/Content and Fly/non-Fly respectively are inspec...
Definition: pagefrm.hxx:367
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:205
void ValidateSmartTags() const
Definition: pagefrm.hxx:429
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:6293
bool IsInvalidFlyContent() const
Definition: pagefrm.hxx:233
void InvalidateFlyInCnt() const
Definition: pagefrm.hxx:375
const SwSortedObjs * GetSortedObjs() const
Definition: pagefrm.hxx:133
bool IsInvalidFlyLayout() const
Definition: pagefrm.hxx:232
bool IsLeftShadowNeeded() const
Definition: paintfrm.cxx:5908
SwContentFrame * FindFirstBodyContent()
Definition: pagefrm.hxx:353
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:1450
bool IsInvalidSmartTags() const
Definition: pagefrm.hxx:238
void ValidateFlyLayout() const
Definition: pagefrm.hxx:404
bool IsFootnotePage() const
Foot note interface.
Definition: pagefrm.hxx:200
bool IsInvalidContent() const
Definition: pagefrm.hxx:236
void InvalidateFlyContent() const
Definition: pagefrm.hxx:371
bool IsInvalidSpelling() const
Definition: pagefrm.hxx:237
bool IsInvalidAutoCompleteWords() const
Definition: pagefrm.hxx:239
SwRect GetBoundRect(OutputDevice const *pOutputDevice) const
Definition: paintfrm.cxx:6320
void ValidateWordCount() const
Definition: pagefrm.hxx:437
bool IsInvalidFlyInCnt() const
Definition: pagefrm.hxx:234
virtual void Cut() override
Definition: pagechg.cxx:846
void ValidateSpelling() const
Definition: pagefrm.hxx:424
bool IsInvalidFly() const
Definition: pagefrm.hxx:446
void ValidateAutoCompleteWords() const
Definition: pagefrm.hxx:433
bool IsRightShadowNeeded() const
Definition: paintfrm.cxx:5895
void ValidateLayout() const
Definition: pagefrm.hxx:416
bool IsInvalidLayout() const
Definition: pagefrm.hxx:235
void ValidateFlyContent() const
Definition: pagefrm.hxx:408
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:83
bool IsAssertFlyPages() const
Definition: rootfrm.hxx:283
bool IsLeftToRightViewLayout() const
Definition: pagechg.cxx:2451
void DeleteEmptySct()
Definition: rootfrm.hxx:384
void ResetTurboFlag() const
Definition: rootfrm.hxx:352
bool IsSuperfluous() const
Definition: rootfrm.hxx:306
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:210
const SwContentFrame * GetTurbo() const
Definition: rootfrm.hxx:356
sal_uInt16 GetPageNum() const
Definition: rootfrm.hxx:316
bool IsTableUpdateInProgress() const
Definition: rootfrm.hxx:286
void ResetIdleFormat()
Definition: rootfrm.hxx:263
void RemoveSuperfluous()
remove pages that are not needed at all
Definition: pagechg.cxx:1506
void DisallowTurbo() const
Definition: rootfrm.hxx:351
void ResetTurbo()
Definition: rootfrm.hxx:355
void AssertFlyPages()
Ensures that enough pages exist, so that all page bound frames and draw objects can be placed.
Definition: pagechg.cxx:1554
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:163
void SetLowersFormatted(bool b)
Definition: tabfrm.hxx:168
bool IsLowersFormatted() const
Definition: tabfrm.hxx:167
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:166
sal_uLong GetAllLines() const
For displaying the line numbers.
Definition: txtfrm.hxx:677
sw::MergedPara * GetMergedPara()
Definition: txtfrm.hxx:460
bool HasRepaint() const
Definition: txtfrm.hxx:538
SwRect GetPaintSwRect()
Page number etc.
Definition: frmpaint.cxx:456
void RecalcAllLines()
Definition: txtfrm.cxx:3913
SwTextNode const * GetTextNodeForParaProps() const
Definition: txtfrm.cxx:1303
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
bool IsSmartTagDirty() const
Definition: txtedt.cxx:2327
bool IsAutoCompleteWordDirty() const
Definition: txtedt.cxx:2337
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:2048
bool IsWordCountDirty() const
Definition: txtedt.cxx:2292
sw::WrongState GetWrongDirty() const
Definition: txtedt.cxx:2302
bool IsWrongDirty() const
Definition: txtedt.cxx:2307
const OUString & GetText() const
Definition: ndtxt.hxx:244
static bool IsAutoCompleteWords()
Definition: viewopt.cxx:402
sal_uInt16 GetGapBetweenPages() const
Definition: viewopt.hxx:623
static constexpr sal_uInt16 defGapBetweenPages
Definition: viewopt.hxx:618
bool getBrowseMode() const
Definition: viewopt.hxx:638
bool IsOnlineSpell() const
Definition: viewopt.hxx:539
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:347
const IDocumentStatistics & getIDocumentStatistics() const
Provides access to the document statistics interface.
Definition: viewsh.cxx:2823
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:434
void UnlockPaint(bool bVirDev=false)
Definition: viewsh.hxx:620
void EnableSmooth(bool b)
Definition: viewsh.hxx:256
bool AddPaintRect(const SwRect &rRect)
Definition: viewsh.cxx:540
vcl::Window * GetWin() const
Definition: viewsh.hxx:346
const SwRect & VisArea() const
Definition: viewsh.cxx:630
void InvalidateWindows(const SwRect &rRect)
Definition: viewsh.cxx:556
SwDoc * GetDoc() const
Definition: viewsh.hxx:290
bool IsPaintLocked() const
Definition: viewsh.hxx:479
SwFlyFrame * GetFlyFrame()
Definition: dflyobj.hxx:134
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:897
static bool lcl_IsInvaLay(const SwFrame *pFrame, tools::Long nBottom)
Definition: layact.cxx:891
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:919
static const SwAnchoredObject * lcl_FindFirstInvaObj(const SwPageFrame *_pPage, tools::Long _nBottom)
Definition: layact.cxx:964
#define SHOW_IDLE(Color)
Definition: layact.cxx:2254
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
sal_uIntPtr sal_uLong
bool bModified
Definition: docstat.hxx:39
sal_Int32 GetContentIndex() const
Definition: pam.hxx:84
Describes parts of multiple text nodes, which will form a text frame, even when redlines are hidden a...
Definition: txtfrm.hxx:971
#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