sw/source/core/inc/layact.hxx    |   24 +++++++++------
 sw/source/core/layout/layact.cxx |   60 +++++++++++++++++++++------------------
 sw/source/core/view/viewsh.cxx   |    1 
 3 files changed, 49 insertions(+), 36 deletions(-)

New commits:
commit 0fedac18214a6025401c4c426466a5166553e8ec
Author:     Luke Deller <l...@deller.id.au>
AuthorDate: Fri Apr 9 09:08:37 2021 +1000
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Apr 14 08:25:05 2021 +0200

    tdf#141556 Fix 100% CPU usage in Writer idle loop
    
    Do not interrupt the idle layout processing unnecessarily, because if it
    is continually interrupted before making enough progress then it will
    keep resuming at the same page, never finishing, constantly using CPU.
    
    This is achieved with two changes:
    
     - Revert "tdf#123583 use TaskStopwatch for Writer Idle loop"
       (commit 383032c50a3e3354f04200ce984a47ab9d2c5c67) which
       introduced a stopwatch timer to interrupt idle processing every 50ms.
       This reversion restores the previous behaviour where idle processing
       is interrupted only when there is an input event.
    
     - Filter out TIMER events so that they do not interrupt the idle loop;
       this fixes both tdf#123583 and tdf#141556
    
    Conflicts:
            sw/source/core/inc/layact.hxx
            sw/source/core/layout/layact.cxx
    
    Change-Id: Ic989631e5f32199209d64b66b72059253fc0167a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113825
    Tested-by: Jenkins
    Reviewed-by: Jan-Marek Glogowski <glo...@fbihome.de>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index 4729ea85ebff..f46c090dbb20 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -21,7 +21,7 @@
 
 #include <sal/config.h>
 
-#include <vcl/TaskStopwatch.hxx>
+#include <vcl/inputtypes.hxx>
 #include <tools/color.hxx>
 
 #include <ctime>
@@ -56,7 +56,6 @@ class SwLayAction
 {
     SwRootFrame  *m_pRoot;
     SwViewShellImp  *m_pImp; // here the action logs in and off
-    TaskStopwatch* m_pWatch;
 
     // For the sake of optimization, so that the tables stick a bit better to
     // the Cursor when hitting return/backspace in front of one.
@@ -75,6 +74,7 @@ class SwLayAction
     std::clock_t m_nStartTicks;      // The Action's starting time; if too 
much time passes the
                                 // WaitCursor can be enabled via 
CheckWaitCursor()
 
+    VclInputFlags m_nInputType;   // Which input should terminate processing
     sal_uInt16 m_nEndPage;        // StatBar control
     sal_uInt16 m_nCheckPageNum;   // CheckPageDesc() was delayed if != 
USHRT_MAX
                                 // check from this page onwards
@@ -84,8 +84,9 @@ class SwLayAction
     bool m_bCalcLayout;    // Complete reformatting?
     bool m_bAgain;         // For the automatically repeated Action if Pages 
are deleted
     bool m_bNextCycle;     // Reset on the first invalid Page
+    bool m_bInput;         // For terminating processing on input
+    bool m_bIdle;          // True if the LayAction was triggered by the Idler
     bool m_bReschedule;    // Call Reschedule depending on Progress?
-    bool m_bInterrupt;     // For termination the layouting
     bool m_bCheckPages;    // Run CheckPageDescs() or delay it
     bool m_bUpdateExpFields; // Is set if, after Formatting, we need to do 
another round for ExpField
     bool m_bBrowseActionStop; // Terminate Action early (as per bInput) and 
leave the rest to the Idler
@@ -123,26 +124,33 @@ class SwLayAction
 
     bool RemoveEmptyBrowserPages();
 
+    inline void CheckIdleEnd();
+
 public:
-    SwLayAction(SwRootFrame *pRt, SwViewShellImp *pImp, TaskStopwatch* pWatch 
= nullptr);
+    SwLayAction( SwRootFrame *pRt, SwViewShellImp *pImp );
     ~SwLayAction();
 
+    void SetIdle            ( bool bNew )   { m_bIdle = bNew; }
     void SetCheckPages      ( bool bNew )   { m_bCheckPages = bNew; }
     void SetBrowseActionStop( bool bNew )   { m_bBrowseActionStop = bNew; }
     void SetNextCycle       ( bool bNew )   { m_bNextCycle = bNew; }
 
     bool IsWaitAllowed()        const       { return m_bWaitAllowed; }
     bool IsNextCycle()          const       { return m_bNextCycle; }
+    bool IsInput()              const       { return m_bInput; }
     bool IsPaint()              const       { return m_bPaint; }
+    bool IsIdle()               const       { return m_bIdle;  }
     bool IsReschedule()         const       { return m_bReschedule;  }
-    bool IsIdle()               const       { return m_pWatch != nullptr; }
-    bool IsPaintExtraData()     const       { return m_bPaintExtraData; }
-    bool IsInterrupt();
+    bool IsPaintExtraData()     const       { return m_bPaintExtraData;}
+    bool IsInterrupt()          const       { return IsInput(); }
+
+    VclInputFlags GetInputType()    const { return m_nInputType; }
 
     // adjusting Action to the wanted behaviour
     void SetPaint       ( bool bNew )   { m_bPaint = bNew; }
     void SetComplete    ( bool bNew )   { m_bComplete = bNew; }
     void SetStatBar     ( bool bNew );
+    void SetInputType   ( VclInputFlags nNew ) { m_nInputType = nNew; }
     void SetCalcLayout  ( bool bNew )   { m_bCalcLayout = bNew; }
     void SetReschedule  ( bool bNew )   { m_bReschedule = bNew; }
     void SetWaitAllowed ( bool bNew )   { m_bWaitAllowed = bNew; }
@@ -179,7 +187,6 @@ public:
 
 class SwLayIdle
 {
-    TaskStopwatch m_aWatch;
     SwRootFrame *m_pRoot;
     SwViewShellImp  *m_pImp;           // The Idler registers and deregisters 
here
     SwContentNode *m_pContentNode;    // The current cursor position is saved 
here
@@ -191,7 +198,6 @@ class SwLayIdle
     void ShowIdle( Color eName );
 #endif
 
-    bool IsInterrupt();
     enum IdleJobType{ ONLINE_SPELLING, AUTOCOMPLETE_WORDS, WORD_COUNT, 
SMART_TAGS };
     bool DoIdleJob_( const SwContentFrame*, IdleJobType );
     bool DoIdleJob( IdleJobType, bool bVisAreaOnly );
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 249d63e15b6d..c75dd034978c 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -39,6 +39,7 @@
 #include <sfx2/event.hxx>
 
 #include <ftnidx.hxx>
+#include <vcl/svapp.hxx>
 #include <editeng/opaqitem.hxx>
 #include <SwSmartTagMgr.hxx>
 #include <sal/log.hxx>
@@ -87,6 +88,13 @@ void SwLayAction::CheckWaitCursor()
     }
 }
 
+// Time over already?
+inline void SwLayAction::CheckIdleEnd()
+{
+    if ( !IsInput() )
+        m_bInput = bool(GetInputType()) && Application::AnyInput( 
GetInputType() );
+}
+
 void SwLayAction::SetStatBar( bool bNew )
 {
     if ( bNew )
@@ -244,13 +252,13 @@ void SwLayAction::PaintContent( const SwContentFrame 
*pCnt,
         pCnt->ResetRetouche();
 }
 
-SwLayAction::SwLayAction(SwRootFrame *pRt, SwViewShellImp *pI, TaskStopwatch* 
pWatch)
-    : m_pRoot(pRt),
+SwLayAction::SwLayAction( SwRootFrame *pRt, SwViewShellImp *pI ) :
+    m_pRoot( pRt ),
     m_pImp( pI ),
-    m_pWatch(pWatch),
     m_pOptTab( nullptr ),
     m_nPreInvaPage( USHRT_MAX ),
     m_nStartTicks( std::clock() ),
+    m_nInputType( VclInputFlags::NONE ),
     m_nEndPage( USHRT_MAX ),
     m_nCheckPageNum( USHRT_MAX ),
     m_pCurPage( nullptr ),
@@ -259,7 +267,7 @@ SwLayAction::SwLayAction(SwRootFrame *pRt, SwViewShellImp 
*pI, TaskStopwatch* pW
 {
     m_bPaintExtraData = ::IsExtraData( m_pImp->GetShell()->GetDoc() );
     m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
-    m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+    m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle = 
m_bReschedule =
     m_bUpdateExpFields = m_bBrowseActionStop = m_bActionInProgress = false;
     // init new flag <mbFormatContentOnInterrupt>.
     mbFormatContentOnInterrupt = false;
@@ -274,18 +282,14 @@ SwLayAction::~SwLayAction()
     m_pImp->m_pLayAction = nullptr;      // unregister
 }
 
-bool SwLayAction::IsInterrupt()
-{
-    return m_bInterrupt || (m_pWatch && m_pWatch->exceededRuntime());
-}
-
 void SwLayAction::Reset()
 {
     m_pOptTab = nullptr;
     m_nStartTicks = std::clock();
+    m_nInputType = VclInputFlags::NONE;
     m_nEndPage = m_nPreInvaPage = m_nCheckPageNum = USHRT_MAX;
     m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
-    m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+    m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle = 
m_bReschedule =
     m_bUpdateExpFields = m_bBrowseActionStop = false;
     m_pCurPage = nullptr;
 }
@@ -445,7 +449,7 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
     IDocumentLayoutAccess& rLayoutAccess = 
m_pRoot->GetFormat()->getIDocumentLayoutAccess();
     bool bNoLoop = pPage && SwLayouter::StartLoopControl( 
m_pRoot->GetFormat()->GetDoc(), pPage );
     sal_uInt16 nPercentPageNum = 0;
-    while ((!IsInterrupt() && pPage) || (m_nCheckPageNum != USHRT_MAX))
+    while ( (pPage && !IsInterrupt()) || m_nCheckPageNum != USHRT_MAX )
     {
         // note: this is the only place that consumes and resets 
m_nCheckPageNum
         if ((IsInterrupt() || !pPage) && m_nCheckPageNum != USHRT_MAX)
@@ -569,7 +573,7 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
                             pPage->InvalidateFlyLayout();
                             pPage->InvalidateFlyContent();
                             if ( IsBrowseActionStop() )
-                                m_bInterrupt = true;
+                                m_bInput = true;
                         }
                     }
                     if( bNoLoop )
@@ -587,8 +591,7 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
                 pPage->ValidateFlyLayout();
                 pPage->ValidateFlyContent();
             }
-
-            if (!IsInterrupt())
+            if ( !IsInterrupt() )
             {
                 SetNextCycle( false );
 
@@ -629,8 +632,8 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
                 if( bNoLoop )
                     rLayoutAccess.GetLayouter()->LoopControl( pPage );
             }
+            CheckIdleEnd();
         }
-
         if ( !pPage && !IsInterrupt() &&
              (m_pRoot->IsSuperfluous() || m_pRoot->IsAssertFlyPages()) )
         {
@@ -656,7 +659,6 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
                 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
         }
     }
-
     if ( IsInterrupt() && pPage )
     {
         // If we have input, we don't want to format content anymore, but
@@ -685,7 +687,7 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
             pPg = pPg ? static_cast<SwPageFrame*>(pPg->GetPrev()) : pPage;
 
         // set flag for interrupt content formatting
-        mbFormatContentOnInterrupt = IsInterrupt();
+        mbFormatContentOnInterrupt = IsInput();
         tools::Long nBottom = rVis.Bottom();
         // #i42586# - format current page, if idle action is active
         // This is an optimization for the case that the interrupt is created 
by
@@ -779,6 +781,7 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
 
 bool SwLayAction::TurboAction_( const SwContentFrame *pCnt )
 {
+
     const SwPageFrame *pPage = nullptr;
     if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() || 
pCnt->IsRetouche() )
     {
@@ -839,7 +842,10 @@ bool SwLayAction::TurboAction()
     if ( m_pRoot->GetTurbo() )
     {
         if ( !TurboAction_( m_pRoot->GetTurbo() ) )
+        {
+            CheckIdleEnd();
             bRet = false;
+        }
         m_pRoot->ResetTurbo();
     }
     else
@@ -1679,6 +1685,7 @@ bool SwLayAction::FormatContent( const SwPageFrame *pPage 
)
             // paragraph has been processed.
             if (!pTab || !bInValid)
             {
+                CheckIdleEnd();
                 // consider interrupt formatting.
                 if ( ( IsInterrupt() && !mbFormatContentOnInterrupt ) ||
                      ( !bBrowse && pPage->IsInvalidLayout() ) ||
@@ -1771,6 +1778,7 @@ bool SwLayAction::FormatContent( const SwPageFrame *pPage 
)
                 PaintContent( pContent, pPage, pContent->getFrameArea(), 
pContent->getFrameArea().Bottom());
             if ( IsIdle() )
             {
+                CheckIdleEnd();
                 // consider interrupt formatting.
                 if ( IsInterrupt() && !mbFormatContentOnInterrupt )
                     return false;
@@ -1866,6 +1874,7 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame 
*pFly )
         // If there's input, we interrupt processing.
         if ( !pFly->IsFlyInContentFrame() )
         {
+            CheckIdleEnd();
             // consider interrupt formatting.
             if ( IsInterrupt() && !mbFormatContentOnInterrupt )
                 return;
@@ -1875,11 +1884,6 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame 
*pFly )
     CheckWaitCursor();
 }
 
-bool SwLayIdle::IsInterrupt()
-{
-    return m_aWatch.exceededRuntime();
-}
-
 bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
 {
     OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
@@ -1964,7 +1968,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, 
IdleJobType eJob )
                 m_bPageValid = m_bPageValid && (SwTextNode::WrongState::TODO 
!= pTextNode->GetWrongDirty());
                 if ( aRepaint.HasArea() )
                     m_pImp->GetShell()->InvalidateWindows( aRepaint );
-                if (IsInterrupt())
+                if (Application::AnyInput(VCL_INPUT_ANY & 
VclInputFlags(~VclInputFlags::TIMER)))
                     return true;
                 break;
             }
@@ -1972,7 +1976,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, 
IdleJobType eJob )
                 
const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
                 // note: bPageValid remains true here even if the cursor
                 // position is skipped, so no PENDING state needed currently
-                if (IsInterrupt())
+                if (Application::AnyInput(VCL_INPUT_ANY & 
VclInputFlags(~VclInputFlags::TIMER)))
                     return true;
                 break;
             case WORD_COUNT :
@@ -1980,7 +1984,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, 
IdleJobType eJob )
                 const sal_Int32 nEnd = pTextNode->GetText().getLength();
                 SwDocStat aStat;
                 pTextNode->CountWords( aStat, 0, nEnd );
-                if (IsInterrupt())
+                if ( Application::AnyInput() )
                     return true;
                 break;
             }
@@ -1995,7 +1999,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, 
IdleJobType eJob )
                     // handle smarttag problems gracefully and provide 
diagnostics
                     TOOLS_WARN_EXCEPTION( "sw.core", "SMART_TAGS");
                 }
-                if (IsInterrupt())
+                if (Application::AnyInput(VCL_INPUT_ANY & 
VclInputFlags(~VclInputFlags::TIMER)))
                     return true;
                 break;
             }
@@ -2186,7 +2190,9 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp 
*pI ) :
 
         bool bInterrupt(false);
         {
-            SwLayAction aAction(m_pRoot, m_pImp, &m_aWatch);
+            SwLayAction aAction( m_pRoot, m_pImp );
+            aAction.SetInputType( VCL_INPUT_ANY & 
VclInputFlags(~VclInputFlags::TIMER) );
+            aAction.SetIdle( true );
             aAction.SetWaitAllowed( false );
             aAction.Action(m_pImp->GetShell()->GetOut());
             bInterrupt = aAction.IsInterrupt();
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index 4ec987fd777b..522813e4b912 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -284,6 +284,7 @@ void SwViewShell::ImplEndAction( const bool bIdleEnd )
         aAction.SetComplete( false );
         if ( mnLockPaint )
             aAction.SetPaint( false );
+        aAction.SetInputType( VclInputFlags::KEYBOARD );
         aAction.Action(GetWin());
     }
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to