include/vcl/gdimtf.hxx                             |    1 
 sw/CppunitTest_sw_core_crsr.mk                     |   73 +++++++++++++++++++++
 sw/Module_sw.mk                                    |    1 
 sw/qa/core/crsr/crsr.cxx                           |   58 ++++++++++++++++
 sw/qa/core/crsr/data/sel-all-starts-with-table.odt |binary
 sw/qa/extras/uiwriter/uiwriter2.cxx                |    2 
 sw/source/core/crsr/callnk.cxx                     |   50 +++++++++++---
 sw/source/core/doc/docfmt.cxx                      |    1 
 sw/source/core/inc/UndoTable.hxx                   |    8 ++
 sw/source/core/undo/untbl.cxx                      |    2 
 sw/source/core/view/vprint.cxx                     |   65 +++++-------------
 vcl/source/gdi/gdimtf.cxx                          |    7 +-
 12 files changed, 209 insertions(+), 59 deletions(-)

New commits:
commit 1c988e09c84fc804271075b97b587c2d8974ca5a
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jun 30 14:44:21 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Jul 3 17:17:16 2023 +0200

    tdf#152231 vcl,sw: PDF/UA export: fix comments in the margin
    
    If enabled, the comments mess up the structure elements, because the
    PageSyncData::mActions stores indexes into the GDIMetaFile::m_aList
    vector, and in PageSyncData::PlaySyncPageAct() the indexes don't match.
    
    This is because SwViewShell::PrintOrPDFExport() replaces the GDIMetaFile
    with a temporary one, then records the page content, then applies
    scaling to the temporary one and replays it, recording with the original
    one; somehow replaying a temporary GDIMetaFile with 270 actions to one
    that already has 4 actions results in 392 actions.
    
    It's not obvious how this can work with the temporary GDIMetaFile, so
    try to get rid of it; not sure if there any drawbacks to this but the
    GDIMetaFile is freshly created by the caller in any case.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153808
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit a225b4dbd46897903b217969da5f97f2660022c9)
    
    Change-Id: Ic297367ea307aa8eee8d609751d06abf417e9629

diff --git a/include/vcl/gdimtf.hxx b/include/vcl/gdimtf.hxx
index 661caf863a22..a008613fce25 100644
--- a/include/vcl/gdimtf.hxx
+++ b/include/vcl/gdimtf.hxx
@@ -114,6 +114,7 @@ public:
     void            Move( long nX, long nY );
     // additional Move method getting specifics how to handle MapMode( 
MapUnit::MapPixel )
     void            Move( long nX, long nY, long nDPIX, long nDPIY );
+    void            ScaleActions(double fScaleX, double fScaleY);
     void            Scale( double fScaleX, double fScaleY );
     void            Scale( const Fraction& rScaleX, const Fraction& rScaleY );
     void            Rotate( long nAngle10 );
diff --git a/sw/source/core/view/vprint.cxx b/sw/source/core/view/vprint.cxx
index 8f0600d59a1d..4c89734e3ea2 100644
--- a/sw/source/core/view/vprint.cxx
+++ b/sw/source/core/view/vprint.cxx
@@ -33,6 +33,7 @@
 #include <unotools/syslocale.hxx>
 #include <vcl/oldprintadaptor.hxx>
 
+#include <optional>
 #include <unotxdoc.hxx>
 #include <docsh.hxx>
 #include <txtfld.hxx>
@@ -461,32 +462,13 @@ bool SwViewShell::PrintOrPDFExport(
     // output device is now provided by a call from outside the Writer)
     pOutDev->Push();
 
-    // fdo#36815 for comments in margins print to a metafile
-    // and then scale that metafile down so that the comments
-    // will fit on the real page, and replay that scaled
-    // output to the real outputdevice
-    GDIMetaFile *pOrigRecorder(nullptr);
-    std::unique_ptr<GDIMetaFile> pMetaFile;
     SwPostItMode nPostItMode = rPrintData.GetPrintPostIts();
 
     // tdf#91680 Reserve space in margin for comments only if there are 
comments
     const bool bHasPostItsToPrintInMargins = ( nPostItMode == 
SwPostItMode::InMargins ) &&
                                 sw_GetPostIts( 
&GetDoc()->getIDocumentFieldsAccess(), nullptr );
 
-    if ( bHasPostItsToPrintInMargins )
-    {
-        //get and disable the existing recorder
-        pOrigRecorder = pOutDev->GetConnectMetaFile();
-        pOutDev->SetConnectMetaFile(nullptr);
-        // turn off output to the device
-        pOutDev->EnableOutput(false);
-        // just record the rendering commands to the metafile
-        // instead
-        pMetaFile.reset(new GDIMetaFile);
-        pMetaFile->SetPrefSize(pOutDev->GetOutputSize());
-        pMetaFile->SetPrefMapMode(pOutDev->GetMapMode());
-        pMetaFile->Record(pOutDev);
-    }
+    ::std::optional<long> oOrigHeight;
 
     // Print/PDF export for (multi-)selection has already generated a
     // temporary document with the selected text.
@@ -550,32 +532,7 @@ bool SwViewShell::PrintOrPDFExport(
             pPostItManager->CalcRects();
             pPostItManager->LayoutPostIts();
             pPostItManager->DrawNotesForPage(pOutDev, nPage-1);
-
-            //Stop recording now
-            pMetaFile->Stop();
-            pMetaFile->WindStart();
-            //Enable output to the device again
-            pOutDev->EnableOutput();
-            //Restore the original recorder
-            pOutDev->SetConnectMetaFile(pOrigRecorder);
-
-            //Now scale the recorded page down so the notes
-            //will fit in the final page
-            double fScale = 0.75;
-            long nOrigHeight = pStPage->getFrameArea().Height();
-            long nNewHeight = nOrigHeight*fScale;
-            long nShiftY = (nOrigHeight-nNewHeight)/2;
-            pMetaFile->Scale( fScale, fScale );
-            pMetaFile->WindStart();
-            //Move the scaled page down to center it
-            //the other variant of Move does not map pixels
-            //back to the logical units correctly
-            pMetaFile->Move(0, convertTwipToMm100(nShiftY), 
pOutDev->GetDPIX(), pOutDev->GetDPIY());
-            pMetaFile->WindStart();
-
-            //play back the scaled page
-            pMetaFile->Play(pOutDev);
-            pMetaFile.reset();
+            oOrigHeight.emplace(pStPage->getFrameArea().Height());
         }
     }
 
@@ -585,6 +542,22 @@ bool SwViewShell::PrintOrPDFExport(
     // output device is now provided by a call from outside the Writer)
     pOutDev->Pop();
 
+    // avoid a warning about unbalanced Push/Pop by doing this last:
+    if (oOrigHeight)
+    {
+        // fdo#36815 Now scale the recorded page down so the comments in
+        // margins will fit in the final page
+        double fScale = 0.75;
+        long nNewHeight = *oOrigHeight*fScale;
+        long nShiftY = (*oOrigHeight-nNewHeight)/2;
+        GDIMetaFile *const pMetaFile = pOutDev->GetConnectMetaFile();
+        pMetaFile->ScaleActions(fScale, fScale);
+        //Move the scaled page down to center it
+        //the other variant of Move does not map pixels
+        //back to the logical units correctly
+        pMetaFile->Move(0, convertTwipToMm100(nShiftY), pOutDev->GetDPIX(), 
pOutDev->GetDPIY());
+    }
+
     return true;
 }
 
diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index eb730fe578a7..7e40830e7f7b 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -690,7 +690,7 @@ void GDIMetaFile::Move( long nX, long nY, long nDPIX, long 
nDPIY )
     }
 }
 
-void GDIMetaFile::Scale( double fScaleX, double fScaleY )
+void GDIMetaFile::ScaleActions(double const fScaleX, double const fScaleY)
 {
     for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
     {
@@ -706,6 +706,11 @@ void GDIMetaFile::Scale( double fScaleX, double fScaleY )
 
         pModAct->Scale( fScaleX, fScaleY );
     }
+}
+
+void GDIMetaFile::Scale( double fScaleX, double fScaleY )
+{
+    ScaleActions(fScaleX, fScaleY);
 
     m_aPrefSize.setWidth( FRound( m_aPrefSize.Width() * fScaleX ) );
     m_aPrefSize.setHeight( FRound( m_aPrefSize.Height() * fScaleY ) );
commit ae6e02f1b6e11698534d01e948a6b62cd1dc96ae
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Mon Jul 11 19:20:33 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Jul 3 14:46:43 2023 +0200

    sw: fix spurious layout invalidation from ~SwCallLink()
    
    This code was added in commit 56b2cf0c10d9caa01ebae1d80465e342d046a85c
    "sw-collapse-empty-table-par-like-html.diff" and leaves us to guess
    what it should do.
    
    Apparently it's trying to replicate a Word feature where an empty
    paragraph at the end of a table cell and preceded by a nested table is
    effectively hidden, *unless* the user moves the cursor into it, at which
    point it grows to its ordinary height.
    
    The problem is that this is implemented by invalidating the position of
    any table once the cursor is moved into it, causing it to be
    reformatted, at potentially great expense, regardless if the cursor is
    actually on a paragraph that may be hidden.
    
    Also limit invalidations to when the cursor has actually moved to a
    different node.
    
    To fix tdf#105330, un-collapse a paragraph after Undo, requires
    additionally doing the same notification from
    SwUndoInsTable::UndoImpl() because the SwCallLink won't see the removed
    table any more.
    
    Mysteriously this causes the test SwLayoutWriter2 testTdf124261 to fail
    in Jenkins, but only on MacOSX so impossible to debug; tb86 fails with:
    
    layout2.cxx:2227:testTdf124261::TestBody
    equality assertion failed
    - Expected: 1721
    - Actual  : 5437
    
    ... and tb84 with:
    
    layout2.cxx:2227:testTdf124261::TestBody
    equality assertion failed
    - Expected: 1721
    - Actual  : 3740
    
    Change-Id: Ifd55097735d3675e6b82264f455baa44e9c9e30a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136963
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit c605283ad6785dea762feab5fdffd9d27e75c292)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137034
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit dadaf930d14283f96cc06741d2eec6d846e59f7f)
    (cherry picked from commit 158012bcd3ed56cd1c9c5b3472d42d94d5a437da)

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index b359ef7df607..f7c0664d596d 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -1238,7 +1238,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, 
testMixedFormFieldInsertion)
 
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf124261)
 {
-#if !defined(WNT)
+#if !defined(WNT) && !defined(MACOSX)
     // Make sure that pressing a key in a btlr cell frame causes an immediate, 
correct repaint.
     SwDoc* pDoc = createDoc("tdf124261.docx");
     SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
diff --git a/sw/source/core/crsr/callnk.cxx b/sw/source/core/crsr/callnk.cxx
index 3c89a94474ca..51272444485e 100644
--- a/sw/source/core/crsr/callnk.cxx
+++ b/sw/source/core/crsr/callnk.cxx
@@ -35,6 +35,7 @@
 #include <ndtxt.hxx>
 #include <flyfrm.hxx>
 #include <breakit.hxx>
+#include <UndoTable.hxx>
 
 SwCallLink::SwCallLink( SwCursorShell & rSh )
     : rShell( rSh )
@@ -64,24 +65,36 @@ SwCallLink::SwCallLink( SwCursorShell & rSh )
     }
 }
 
-static void lcl_notifyRow(const SwContentNode* pNode, SwCursorShell & rShell)
+namespace sw {
+
+/**
+  An empty paragraph inside a table with a nested table preceding it
+  should be hidden, unless the cursor is positioned in the paragraph.
+
+  If the cursor is now (or was previously) inside such a paragraph,
+  send a size change notification on the row frame to force reformatting.
+ */
+void NotifyTableCollapsedParagraph(const SwContentNode *const pNode, 
SwCursorShell *const pShell)
 {
     if ( !pNode )
         return;
 
-    SwFrame *const pMyFrame = pNode->getLayoutFrame( rShell.GetLayout() );
+    SwFrame *const pMyFrame = pNode->getLayoutFrame(pShell ? 
pShell->GetLayout() : nullptr);
     if ( !pMyFrame )
         return;
 
-    // We need to emulated a change of the row height in order
-    // to have the complete row redrawn
+    // important: only invalidate layout if something is actually hidden or
+    // shown! Otherwise performance is going to suffer with "difficult" tables.
+    if (!pMyFrame->IsCollapse())
+        return;
+
     SwRowFrame *const pRow = pMyFrame->FindRowFrame();
     if ( !pRow )
         return;
 
     const SwTableLine* pLine = pRow->GetTabLine( );
 
-    if (rShell.IsTableMode() || (rShell.StartsWithTable() && 
rShell.ExtendedSelectedAll()))
+    if (pShell && (pShell->IsTableMode() || (pShell->StartsWithTable() && 
pShell->ExtendedSelectedAll())))
     {
         // If we have a table selection, then avoid the notification: it's not 
necessary (the text
         // cursor needs no updating) and the notification may kill the 
selection overlay, leading to
@@ -90,10 +103,13 @@ static void lcl_notifyRow(const SwContentNode* pNode, 
SwCursorShell & rShell)
         return;
     }
 
+    // notify a change in frame size to force reformatting of the row
     SwFormatFrameSize aSize = pLine->GetFrameFormat()->GetFrameSize();
     pRow->ModifyNotification(nullptr, &aSize);
 }
 
+} // namespace sw
+
 SwCallLink::~SwCallLink() COVERITY_NOEXCEPT_FALSE
 {
     if( nNdTyp == SwNodeType::NONE || !rShell.m_bCallChgLnk ) // see ctor
@@ -106,15 +122,17 @@ SwCallLink::~SwCallLink() COVERITY_NOEXCEPT_FALSE
     if( !pCNd )
         return;
 
-    lcl_notifyRow(pCNd, rShell);
-
-    const SwDoc *pDoc=rShell.GetDoc();
-    const SwContentNode *pNode = nullptr;
-    if ( pDoc && nNode < pDoc->GetNodes( ).Count( ) )
+    if (pCNd->GetIndex() != nNode) // only if moved to different node
     {
-        pNode = pDoc->GetNodes()[nNode]->GetContentNode();
+        ::sw::NotifyTableCollapsedParagraph(pCNd, &rShell);
+
+        const SwDoc *pDoc=rShell.GetDoc();
+        if (nNode < pDoc->GetNodes().Count())
+        {
+            const SwContentNode *const pNode = 
pDoc->GetNodes()[nNode]->GetContentNode();
+            ::sw::NotifyTableCollapsedParagraph(pNode, &rShell);
+        }
     }
-    lcl_notifyRow(pNode, rShell);
 
     sal_Int32 nCmp, nCurrentContent = 
pCurrentCursor->GetPoint()->nContent.GetIndex();
     SwNodeType nNdWhich = pCNd->GetNodeType();
diff --git a/sw/source/core/inc/UndoTable.hxx b/sw/source/core/inc/UndoTable.hxx
index 65a62d284682..224180f053b7 100644
--- a/sw/source/core/inc/UndoTable.hxx
+++ b/sw/source/core/inc/UndoTable.hxx
@@ -42,6 +42,14 @@ class SwStartNode;
 class SwTableNode;
 class SwTableAutoFormat;
 class SwTableSortBoxes;
+class SwContentNode;
+class SwCursorShell;
+
+namespace sw {
+
+void NotifyTableCollapsedParagraph(const SwContentNode* pNode, SwCursorShell 
*const pShell);
+
+}
 
 class SwUndoInsTable : public SwUndo
 {
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index a1c9fb40f338..4ebaea08d243 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -277,6 +277,8 @@ void SwUndoInsTable::UndoImpl(::sw::UndoRedoContext & 
rContext)
         if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK,
             false, &pItem ) )
             pNextNd->SetAttr( *pItem );
+
+        ::sw::NotifyTableCollapsedParagraph(pNextNd, nullptr);
     }
 
     sTableNm = pTableNd->GetTable().GetFrameFormat()->GetName();
commit 40fe84a005d0a6e4333030041d350bf18a826938
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Sep 14 21:02:31 2020 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Jul 3 14:46:43 2023 +0200

    tdf#135682 sw: fix lost selection-all when doc starts with table
    
    Regression from commit c56bf1479cc71d1a2b0639f6383e90c1f7e3655b
    (tdf#105330 sw: fix lost cursor on undoing nested table insert,
    2019-09-16), the problem was that the change reverted lcl_notifyRow()
    back to its original state, because it seemed the conditional
    notification is no longer needed. However, this broke the fix for
    tdf#37606 (ability to select-all when the doc starts with a table).
    
    Fix the problem by handling the starts-with-table case similar to a
    normal table selection, so there is still no need to restore the nested
    table visitor code but select-all works nicely with starts-with-table
    documents again.
    
    (cherry picked from commit 6f1e02c96b887750f974c187a82ecd6236e6a435)
    
     Conflicts:
            sw/qa/core/crsr/crsr.cxx
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102706
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit d3a874cedc6129bace47fbee4b781e7a5e30b65f)
    
    Change-Id: Icb823a39432d1774a63a0c633c172bba827ac76d

diff --git a/sw/CppunitTest_sw_core_crsr.mk b/sw/CppunitTest_sw_core_crsr.mk
new file mode 100644
index 000000000000..00c90bba69b4
--- /dev/null
+++ b/sw/CppunitTest_sw_core_crsr.mk
@@ -0,0 +1,73 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_core_crsr))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_crsr))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_core_crsr, \
+    sw/qa/core/crsr/crsr \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_core_crsr, \
+    comphelper \
+    cppu \
+    cppuhelper \
+    sal \
+    sfx \
+    svxcore \
+    sw \
+    test \
+    unotest \
+    utl \
+    vcl \
+    svt \
+    tl \
+    svl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_core_crsr,\
+    boost_headers \
+    libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_core_crsr,\
+    -I$(SRCDIR)/sw/inc \
+    -I$(SRCDIR)/sw/source/core/inc \
+    -I$(SRCDIR)/sw/source/uibase/inc \
+    -I$(SRCDIR)/sw/qa/extras/inc \
+    $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_core_crsr,\
+       udkapi \
+       offapi \
+       oovbaapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_core_crsr))
+$(eval $(call gb_CppunitTest_use_vcl,sw_core_crsr))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_core_crsr,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_core_crsr,\
+    officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_core_crsr))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_core_crsr, \
+    modules/swriter \
+))
+
+$(eval $(call gb_CppunitTest_use_more_fonts,sw_core_crsr))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index 9121847c6f01..ebf30e3e2ad7 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -102,6 +102,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
     CppunitTest_sw_accessible_relation_set \
     CppunitTest_sw_apitests \
     CppunitTest_sw_unowriter \
+    CppunitTest_sw_core_crsr \
 ))
 
 ifneq ($(DISABLE_GUI),TRUE)
diff --git a/sw/qa/core/crsr/crsr.cxx b/sw/qa/core/crsr/crsr.cxx
new file mode 100644
index 000000000000..c22e072091a5
--- /dev/null
+++ b/sw/qa/core/crsr/crsr.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/text/ControlCharacter.hpp>
+#include <com/sun/star/view/XLineCursor.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/text/XTextViewCursor.hpp>
+
+#include <comphelper/propertysequence.hxx>
+#include <svl/srchitem.hxx>
+#include <vcl/scheduler.hxx>
+
+#include <docsh.hxx>
+#include <unotxdoc.hxx>
+#include <wrtsh.hxx>
+
+char const DATA_DIRECTORY[] = "/sw/qa/core/crsr/data/";
+
+/// Covers sw/source/core/crsr/ fixes.
+class SwCoreCrsrTest : public SwModelTestBase
+{
+};
+
+CPPUNIT_TEST_FIXTURE(SwCoreCrsrTest, testSelAllStartsWithTable)
+{
+    load(DATA_DIRECTORY, "sel-all-starts-with-table.odt");
+    SwXTextDocument* pTextDoc = 
dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    SwDocShell* pDocShell = pTextDoc->GetDocShell();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), 
pDoc->GetTableFrameFormatCount(/*bUsed=*/true));
+
+    pWrtShell->SelAll();
+    pWrtShell->SelAll();
+    Scheduler::ProcessEventsToIdle();
+    pWrtShell->DelLeft();
+
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 0
+    // - Actual  : 1
+    // i.e. the table selection was lost and the table was not deleted.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), 
pDoc->GetTableFrameFormatCount(/*bUsed=*/true));
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/crsr/data/sel-all-starts-with-table.odt 
b/sw/qa/core/crsr/data/sel-all-starts-with-table.odt
new file mode 100644
index 000000000000..a368095a55cf
Binary files /dev/null and b/sw/qa/core/crsr/data/sel-all-starts-with-table.odt 
differ
diff --git a/sw/source/core/crsr/callnk.cxx b/sw/source/core/crsr/callnk.cxx
index 78ba53bf7dea..3c89a94474ca 100644
--- a/sw/source/core/crsr/callnk.cxx
+++ b/sw/source/core/crsr/callnk.cxx
@@ -64,7 +64,7 @@ SwCallLink::SwCallLink( SwCursorShell & rSh )
     }
 }
 
-static void lcl_notifyRow(const SwContentNode* pNode, SwCursorShell const & 
rShell)
+static void lcl_notifyRow(const SwContentNode* pNode, SwCursorShell & rShell)
 {
     if ( !pNode )
         return;
@@ -81,11 +81,12 @@ static void lcl_notifyRow(const SwContentNode* pNode, 
SwCursorShell const & rShe
 
     const SwTableLine* pLine = pRow->GetTabLine( );
 
-    if (rShell.IsTableMode())
+    if (rShell.IsTableMode() || (rShell.StartsWithTable() && 
rShell.ExtendedSelectedAll()))
     {
         // If we have a table selection, then avoid the notification: it's not 
necessary (the text
         // cursor needs no updating) and the notification may kill the 
selection overlay, leading to
         // flicker.
+        // Same for whole-document selection when it starts with a table.
         return;
     }
 
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 0c69d1d4a9a6..d91d83108cb9 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -1971,6 +1971,7 @@ void SwDoc::dumpAsXml(xmlTextWriterPtr pWriter) const
     mpFrameFormatTable->dumpAsXml(pWriter, "frmFormatTable");
     mpSpzFrameFormatTable->dumpAsXml(pWriter, "spzFrameFormatTable");
     mpSectionFormatTable->dumpAsXml(pWriter);
+    mpTableFrameFormatTable->dumpAsXml(pWriter, "tableFrameFormatTable");
     mpNumRuleTable->dumpAsXml(pWriter);
     getIDocumentRedlineAccess().GetRedlineTable().dumpAsXml(pWriter);
     getIDocumentRedlineAccess().GetExtraRedlineTable().dumpAsXml(pWriter);
commit 880fe95e2135691e25151ee12a6a14636d75e7c6
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Dec 16 21:01:13 2019 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Jul 3 14:46:42 2023 +0200

    tdf#128567 sw: fix flicker of table selection highlight
    
    Regression from commit c56bf1479cc71d1a2b0639f6383e90c1f7e3655b
    (tdf#105330 sw: fix lost cursor on undoing nested table insert,
    2019-09-16), the problem was that in case lcl_notifyRow() invokes
    SwRowFrame::ModifyNotification(), then the table selection is re-created
    all the time, while in case it does not, then it may result in a cursor
    loss.
    
    The reason for the flicker is that normally
    sw::DocumentTimerManager::m_aDocIdle is not invoked between the
    SwEditWin mouse button down/move/up events, but in case the notification
    is done, then the idle kicks in once the page frame of the row is
    invalidated.
    
    Fix the problem by avoiding the notification in the table selection
    case: this makes the flicker go away and the original cursor loss
    problem remains fixed, too.
    
    [ It is not clear to me woh can I test if the flicker happens, would
    need some mechanism to ensure that the mouse button down/up/move chain
    happens without the idle kicking in, perhaps. ]
    
    (cherry picked from commit d4ea54e18346a35590933dd1e8b83d1c12a741de)
    
    Change-Id: I91e0af0d3b1b9824754c0bf0be8535d294601787
    Reviewed-on: https://gerrit.libreoffice.org/85271
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit da2000648b852047ec9d865891539c28ada97730)

diff --git a/sw/source/core/crsr/callnk.cxx b/sw/source/core/crsr/callnk.cxx
index 0754ca48e48e..78ba53bf7dea 100644
--- a/sw/source/core/crsr/callnk.cxx
+++ b/sw/source/core/crsr/callnk.cxx
@@ -80,6 +80,15 @@ static void lcl_notifyRow(const SwContentNode* pNode, 
SwCursorShell const & rShe
         return;
 
     const SwTableLine* pLine = pRow->GetTabLine( );
+
+    if (rShell.IsTableMode())
+    {
+        // If we have a table selection, then avoid the notification: it's not 
necessary (the text
+        // cursor needs no updating) and the notification may kill the 
selection overlay, leading to
+        // flicker.
+        return;
+    }
+
     SwFormatFrameSize aSize = pLine->GetFrameFormat()->GetFrameSize();
     pRow->ModifyNotification(nullptr, &aSize);
 }

Reply via email to