[Libreoffice-commits] core.git: sw/inc sw/source

Balazs Santha (via logerrit) logerrit at kemper.freedesktop.org
Wed Mar 24 14:08:58 UTC 2021


 sw/inc/ndtxt.hxx                                        |    2 
 sw/source/core/doc/DocumentContentOperationsManager.cxx |   55 ++++++++++++++--
 sw/source/core/txtnode/txtedt.cxx                       |    6 -
 3 files changed, 54 insertions(+), 9 deletions(-)

New commits:
commit e463d239555d3a4dc61797eeb8c638b6442112a3
Author:     Balazs Santha <santha.balazs at simonyi.bme.hu>
AuthorDate: Fri Feb 26 08:06:03 2021 -0500
Commit:     László Németh <nemeth at numbertext.org>
CommitDate: Wed Mar 24 15:08:18 2021 +0100

    tdf#140731: sw transliteration: avoid too many redlines
    
    As a workaround for the performance regression
    from commit 2d3c77e9b10f20091ef338e262ba7756eb280ce9
    (tdf#109266 sw change tracking: track transliteration),
    switch off redlining to avoid ~freezing, if a single
    transliteration could result too many (>~500) redlines.
    
    A single transliteration creates n redlines
    for n paragraphs of the selected text, except in
    the case of transliterating to title case, where it
    creates n redlines for n words. It's very easy
    to freeze Writer, because Writer's slowing down with
    n redlines is described by an O(n²) (quadratic) time
    complexity. Eg. in an experiment, title casing
    ~660 words was 6 sec, but ~3000 words was 85 sec,
    regarding to creating 660 vs 3000 redlines.
    
    Note: this is a partial revert of commit
    2d3c77e9b10f20091ef338e262ba7756eb280ce9, if the
    selection contains more than 500 paragraphs (or in the
    case transliterating to title case, ~500 words).
    
    Change-Id: Iad98943cc9e1ed64aa9779e49ee3e941abad02ac
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111637
    Tested-by: Jenkins
    Tested-by: László Németh <nemeth at numbertext.org>
    Reviewed-by: László Németh <nemeth at numbertext.org>

diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 5dbbbc721f37..50986f3daca7 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -746,7 +746,7 @@ public:
     /// change text to Upper/Lower/Hiragana/Katakana/...
     void TransliterateText( utl::TransliterationWrapper& rTrans,
                             sal_Int32 nStart, sal_Int32 nEnd,
-                            SwUndoTransliterate* pUndo );
+                            SwUndoTransliterate* pUndo, bool bUseRedlining = false );
 
     /// count words in given range - returns true if we refreshed out count
     bool CountWords( SwDocStat& rStat, sal_Int32 nStart, sal_Int32 nEnd ) const;
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index b9846d852a2a..e66ed8e4a673 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -74,6 +74,8 @@
 #include <sal/log.hxx>
 #include <unotools/charclass.hxx>
 #include <unotools/configmgr.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <i18nutil/transliteration.hxx>
 #include <sfx2/Metadatable.hxx>
 #include <sot/exchange.hxx>
 #include <svl/stritem.hxx>
@@ -2821,6 +2823,44 @@ void DocumentContentOperationsManager::TransliterateText(
         }
     }
 
+    bool bUseRedlining = m_rDoc.getIDocumentRedlineAccess().IsRedlineOn();
+    // as a workaround for a known performance problem, switch off redlining
+    // to avoid freezing, if transliteration could result too many redlines
+    if ( bUseRedlining )
+    {
+        const sal_uLong nMaxRedlines = 500;
+        const bool bIsTitleCase = rTrans.getType() == TransliterationFlags::TITLE_CASE;
+        sal_uLong nAffectedNodes = 0;
+        sal_uLong nAffectedChars = nEndCnt;
+        SwNodeIndex aIdx( pStt->nNode );
+        for( ; aIdx.GetIndex() <= nEndNd; ++aIdx )
+        {
+            SwTextNode* pAffectedNode = aIdx.GetNode().GetTextNode();
+
+            // don't count not text nodes or empty text nodes
+            if( !pAffectedNode || pAffectedNode->GetText().isEmpty() )
+                continue;
+
+            nAffectedNodes++;
+
+            // count characters of the node (the last - maybe partially
+            // selected - node was counted at initialization of nAffectedChars)
+            if( aIdx.GetIndex() < nEndNd )
+                nAffectedChars += pAffectedNode->GetText().getLength();
+
+            // transliteration creates n redlines for n nodes, except in the
+            // case of title case, where it creates n redlines for n words
+            if( nAffectedNodes > nMaxRedlines ||
+                    // estimate word count based on the character count, where
+                    // 6 = average English word length is ~5 letters + space
+                    ( bIsTitleCase && (nAffectedChars - nSttCnt)/6 > nMaxRedlines ) )
+            {
+                bUseRedlining = false;
+                break;
+            }
+        }
+    }
+
     if( nSttNd != nEndNd )  // is more than one text node involved?
     {
         // iterate over all effected text nodes, the first and the last one
@@ -2831,8 +2871,10 @@ void DocumentContentOperationsManager::TransliterateText(
         {
             ++aIdx;
             if( pTNd )
+            {
                 pTNd->TransliterateText(
-                        rTrans, nSttCnt, pTNd->GetText().getLength(), pUndo.get());
+                        rTrans, nSttCnt, pTNd->GetText().getLength(), pUndo.get(), bUseRedlining);
+            }
         }
 
         for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
@@ -2841,16 +2883,19 @@ void DocumentContentOperationsManager::TransliterateText(
             if (pTNd)
             {
                 pTNd->TransliterateText(
-                        rTrans, 0, pTNd->GetText().getLength(), pUndo.get());
+                        rTrans, 0, pTNd->GetText().getLength(), pUndo.get(), bUseRedlining);
             }
         }
 
         if( nEndCnt && nullptr != ( pTNd = pEnd->nNode.GetNode().GetTextNode() ))
-            pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo.get() );
+        {
+            pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo.get(), bUseRedlining );
+        }
     }
     else if( pTNd && nSttCnt < nEndCnt )
-        pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo.get() );
-
+    {
+        pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo.get(), bUseRedlining );
+    }
     if( pUndo && pUndo->HasData() )
     {
         m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index ba25c5fccba1..e734e471060b 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1684,7 +1684,7 @@ namespace
 void SwTextNode::TransliterateText(
     utl::TransliterationWrapper& rTrans,
     sal_Int32 nStt, sal_Int32 nEnd,
-    SwUndoTransliterate* pUndo )
+    SwUndoTransliterate* pUndo, bool bUseRedlining )
 {
     if (nStt >= nEnd)
         return;
@@ -1908,7 +1908,7 @@ void SwTextNode::TransliterateText(
     // now apply the changes from end to start to leave the offsets of the
     // yet unchanged text parts remain the same.
     size_t nSum(0);
-    bool bIsRedlineOn(GetDoc().getIDocumentRedlineAccess().IsRedlineOn());
+
     for (size_t i = 0; i < aChanges.size(); ++i)
     {   // check this here since AddChanges cannot be moved below
         // call to ReplaceTextOnly
@@ -1922,7 +1922,7 @@ void SwTextNode::TransliterateText(
             return;
         }
 
-        if ( bIsRedlineOn )
+        if ( bUseRedlining )
         {
             // create SwPaM with mark & point spanning the attributed text
             //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different


More information about the Libreoffice-commits mailing list