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