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