sc/inc/hints.hxx                                      |    4 
 sc/qa/unit/tiledrendering/data/cell-invalidations.ods |binary
 sc/qa/unit/tiledrendering/tiledrendering.cxx          |  128 ++++++++++++++++--
 sc/source/core/tool/hints.cxx                         |    5 
 sc/source/ui/docshell/docfunc.cxx                     |   27 +++
 sc/source/ui/docshell/docsh3.cxx                      |   41 ++++-
 sc/source/ui/inc/docsh.hxx                            |   11 -
 sc/source/ui/inc/tabview.hxx                          |    3 
 sc/source/ui/view/tabview3.cxx                        |   34 +++-
 sc/source/ui/view/tabvwsh5.cxx                        |    7 
 sc/source/ui/view/viewfun3.cxx                        |   18 ++
 11 files changed, 233 insertions(+), 45 deletions(-)

New commits:
commit 37e6aef98f311962f77caabddddf6cb1e72807b8
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Mon Jan 15 10:46:42 2024 +0000
Commit:     Michael Meeks <michael.me...@collabora.com>
CommitDate: Mon Jan 22 18:34:36 2024 +0100

    don't always invalidate the entire width of the calc window
    
    If know the max width affected we can avoid redrawing much of
    the row
    
    LTR cell edits, deletes, single line paste
    
    Change-Id: Ib7e3d8bfa3a5ce7df97f28bcf7858b3abcb752a4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162114
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Marco Cecchetti <marco.cecche...@collabora.com>
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>

diff --git a/sc/inc/hints.hxx b/sc/inc/hints.hxx
index d890072c1f81..00d6d80e0fa3 100644
--- a/sc/inc/hints.hxx
+++ b/sc/inc/hints.hxx
@@ -28,10 +28,11 @@ class SC_DLLPUBLIC ScPaintHint final : public SfxHint
 {
     ScRange         aRange;
     PaintPartFlags  nParts;
+    tools::Long nWidthAffectedHint;
 
 public:
                     ScPaintHint() = delete;
-                    ScPaintHint( const ScRange& rRng, PaintPartFlags nPaint );
+                    ScPaintHint( const ScRange& rRng, PaintPartFlags nPaint, 
tools::Long nMaxWidthAffectedHint = -1);
                     virtual ~ScPaintHint() override;
 
     SCCOL           GetStartCol() const     { return aRange.aStart.Col(); }
@@ -41,6 +42,7 @@ public:
     SCROW           GetEndRow() const       { return aRange.aEnd.Row(); }
     SCTAB           GetEndTab() const       { return aRange.aEnd.Tab(); }
     PaintPartFlags  GetParts() const        { return nParts; }
+    tools::Long     GetMaxWidthAffectedHint() const { return 
nWidthAffectedHint; }
 };
 
 class ScUpdateRefHint final : public SfxHint
diff --git a/sc/qa/unit/tiledrendering/data/cell-invalidations.ods 
b/sc/qa/unit/tiledrendering/data/cell-invalidations.ods
new file mode 100644
index 000000000000..0f117775a467
Binary files /dev/null and 
b/sc/qa/unit/tiledrendering/data/cell-invalidations.ods differ
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx 
b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 55e72325f772..250caa5d5392 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -93,6 +93,8 @@ CPPUNIT_NS_END
 namespace
 {
 
+class ViewCallback;
+
 class ScTiledRenderingTest : public UnoApiXmlTest
 {
 public:
@@ -100,6 +102,11 @@ public:
     virtual void setUp() override;
     virtual void tearDown() override;
 
+    void checkSampleInvalidation(const ViewCallback& rView, bool bFullRow);
+    void cellInvalidationHelper(ScModelObj* pModelObj, ScTabViewShell* pView,
+                                const ScAddress& rAdr, bool bAddText,
+                                bool bFullRow);
+
     void testRowColumnHeaders();
     void testRowColumnSelections();
     void testPartHash();
@@ -166,6 +173,7 @@ public:
     void testLongFirstColumnMouseClick();
     void testSidebarLocale();
     void testNoInvalidateOnSave();
+    void testCellMinimalInvalidations();
     void testCellInvalidationDocWithExistingZoom();
 
     CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
@@ -242,6 +250,7 @@ public:
     CPPUNIT_TEST(testLongFirstColumnMouseClick);
     CPPUNIT_TEST(testSidebarLocale);
     CPPUNIT_TEST(testNoInvalidateOnSave);
+    CPPUNIT_TEST(testCellMinimalInvalidations);
     CPPUNIT_TEST(testCellInvalidationDocWithExistingZoom);
     CPPUNIT_TEST_SUITE_END();
 
@@ -3691,6 +3700,111 @@ void ScTiledRenderingTest::testNoInvalidateOnSave()
     CPPUNIT_ASSERT(!aView.m_bInvalidateTiles);
 }
 
+void ScTiledRenderingTest::checkSampleInvalidation(const ViewCallback& rView, 
bool bFullRow)
+{
+    // we expect invalidations, but that isn't really important
+    CPPUNIT_ASSERT(rView.m_bInvalidateTiles);
+    tools::Rectangle aInvalidation;
+    for (const auto& rRect : rView.m_aInvalidations)
+        aInvalidation.Union(rRect);
+    if (!bFullRow)
+    {
+        // What matters is that we expect that the invalidation does not 
extend all the
+        // way to the max right of the sheet.
+        // Here we originally got 32212306 and now ~5056 for a single cell case
+        CPPUNIT_ASSERT_LESSEQUAL(tools::Long(8000), aInvalidation.GetWidth());
+    }
+    else
+    {
+        // We expect RTL to continue to invalidate the entire row
+        // from 0 to end of sheet (see ScDocShell::PostPaint, 'Extend to whole 
rows'),
+        // which is different to the adjusted LTR case which
+        // invalidated the row from left of edited cell to right of end
+        // of sheet.
+        CPPUNIT_ASSERT_LESSEQUAL(tools::Long(0), aInvalidation.Left());
+        CPPUNIT_ASSERT_EQUAL(tools::Long(32212230), aInvalidation.Right());
+    }
+}
+
+void ScTiledRenderingTest::cellInvalidationHelper(ScModelObj* pModelObj, 
ScTabViewShell* pView, const ScAddress& rAdr,
+                                                  bool bAddText, bool bFullRow)
+{
+    // view
+    ViewCallback aView;
+
+    if (bAddText)
+    {
+        // Type "Hello World" in D8, process events to idle and don't commit 
yet
+        lcl_typeCharsInCell("Hello World", rAdr.Col(), rAdr.Row(), pView, 
pModelObj, false, false);
+
+        aView.m_bInvalidateTiles = false;
+        aView.m_aInvalidations.clear();
+
+        // commit text and process events to idle
+        lcl_typeCharsInCell("", rAdr.Col(), rAdr.Row(), pView, pModelObj, 
true, true);
+    }
+    else // DeleteText
+    {
+        pView->SetCursor(rAdr.Col(), rAdr.Row());
+        pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::DELETE);
+        pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::DELETE);
+        Scheduler::ProcessEventsToIdle();
+    }
+
+    checkSampleInvalidation(aView, bFullRow);
+}
+
+void ScTiledRenderingTest::testCellMinimalInvalidations()
+{
+    ScAddress aA8(0, 7, 0);
+    ScAddress aD4(3, 7, 0);
+    ScAddress aD13(3, 12, 0);
+    ScAddress aD17(3, 16, 0);
+
+    ScModelObj* pModelObj = createDoc("cell-invalidations.ods");
+    ScTabViewShell* pView = 
dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+    CPPUNIT_ASSERT(pModelObj && pView);
+
+    // Changed: Minimized invalidations (bFullRow: false)
+
+    // Common case, LTR, default cell formatting
+    cellInvalidationHelper(pModelObj, pView, aA8, true, false);
+    cellInvalidationHelper(pModelObj, pView, aD4, true, false);
+    // Left-aligned merged cells
+    cellInvalidationHelper(pModelObj, pView, aD17, true, false);
+    // Delete single cell text case
+    cellInvalidationHelper(pModelObj, pView, aA8, false, false);
+    // Paste into a single cell
+    {
+        pView->SetCursor(aD4.Col(), aD4.Row());
+        uno::Sequence<beans::PropertyValue> aArgs;
+        dispatchCommand(mxComponent, ".uno:Copy", aArgs);
+        pView->SetCursor(aA8.Col(), aA8.Row());
+        Scheduler::ProcessEventsToIdle();
+
+        ViewCallback aView;
+        dispatchCommand(mxComponent, ".uno:Paste", aArgs);
+        Scheduler::ProcessEventsToIdle();
+
+        checkSampleInvalidation(aView, false);
+    }
+
+    // Unchanged: Non-minimized invalidations (bFullRow: true)
+
+    // Centered merged cells;
+    cellInvalidationHelper(pModelObj, pView, aD13, true, true);
+
+    // switch to RTL sheet
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::PAGEDOWN | 
KEY_MOD1);
+    pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::PAGEDOWN | 
KEY_MOD1);
+    Scheduler::ProcessEventsToIdle();
+
+    cellInvalidationHelper(pModelObj, pView, aA8, true, true);
+    cellInvalidationHelper(pModelObj, pView, aD4, true, true);
+    // Delete Text
+    cellInvalidationHelper(pModelObj, pView, aA8, false, true);
+}
+
 void ScTiledRenderingTest::testCellInvalidationDocWithExistingZoom()
 {
     ScAddress aB7(1, 6, 0);
@@ -3765,15 +3879,11 @@ void 
ScTiledRenderingTest::testCellInvalidationDocWithExistingZoom()
     // That they don't exactly match doesn't matter, we're not checking 
rounding issues,
     // what matters is that they are not utterly different rectangles
     // Without fix result is originally:
-    // Comparing invalidation rects Left expected 278 actual 1213 Tolerance 50
-    CppUnit::AssertPointEqualWithTolerance("Comparing invalidations topleft",
-                                          aView1.m_aInvalidations[0].TopLeft(),
-                                          aView2.m_aInvalidations[0].TopLeft(),
-                                          100);
-    CppUnit::AssertPointEqualWithTolerance("Comparing invalidations 
bottomleft",
-                                          
aView1.m_aInvalidations[0].BottomLeft(),
-                                          
aView2.m_aInvalidations[0].BottomLeft(),
-                                          100);
+    // Comparing invalidation rectangles Width expected 6214742 actual 
26716502 Tolerance 50
+    CppUnit::AssertRectEqualWithTolerance("Comparing invalidation rectangles",
+                                          aView2.m_aInvalidations[0],
+                                          aView1.m_aInvalidations[0],
+                                          50);
 }
 
 }
diff --git a/sc/source/core/tool/hints.cxx b/sc/source/core/tool/hints.cxx
index 06ac946d9b6e..a3be243750a4 100644
--- a/sc/source/core/tool/hints.cxx
+++ b/sc/source/core/tool/hints.cxx
@@ -22,9 +22,10 @@
 
 // ScPaintHint - info what has to be repainted
 
-ScPaintHint::ScPaintHint( const ScRange& rRng, PaintPartFlags nPaint ) :
+ScPaintHint::ScPaintHint( const ScRange& rRng, PaintPartFlags nPaint, 
tools::Long nMaxWidthAffectedHint ) :
     aRange( rRng ),
-    nParts( nPaint )
+    nParts( nPaint ),
+    nWidthAffectedHint(nMaxWidthAffectedHint)
 {
 }
 
diff --git a/sc/source/ui/docshell/docfunc.cxx 
b/sc/source/ui/docshell/docfunc.cxx
index 12ff9a0f9908..750fa3e01b18 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -671,6 +671,26 @@ bool ScDocFunc::DeleteContents(
     return true;
 }
 
+tools::Long ScDocShell::GetPixelWidthHint(const ScAddress& rPos)
+{
+    ScViewData* pViewData = GetViewData();
+    if (!pViewData)
+        return -1;
+
+    ScSizeDeviceProvider aProv(this);
+    OutputDevice* pDev = aProv.GetDevice();         // has pixel MapMode
+    double nPPTX = aProv.GetPPTX();
+    double nPPTY = aProv.GetPPTY();
+
+    ScDocument& rDoc = GetDocument();
+    Fraction aInvX(pViewData->GetZoomX().GetDenominator(),
+                   pViewData->GetZoomX().GetNumerator());
+    Fraction aInvY(pViewData->GetZoomY().GetDenominator(),
+                   pViewData->GetZoomY().GetNumerator());
+    return rDoc.GetNeededSize(rPos.Col(), rPos.Row(), rPos.Tab(), pDev,
+                              nPPTX, nPPTY, aInvX, aInvY, true /*bWidth*/);
+}
+
 bool ScDocFunc::DeleteCell(
     const ScAddress& rPos, const ScMarkData& rMark, InsertDeleteFlags nFlags, 
bool bRecord, bool bApi )
 {
@@ -719,6 +739,7 @@ bool ScDocFunc::DeleteCell(
         pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, rMark, rPos);
     }
 
+    tools::Long nBefore(rDocShell.GetPixelWidthHint(rPos));
     rDoc.DeleteArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark, 
nFlags);
 
     if (bRecord)
@@ -731,7 +752,7 @@ bool ScDocFunc::DeleteCell(
     if (!AdjustRowHeight(rPos, true, bApi))
         rDocShell.PostPaint(
             rPos.Col(), rPos.Row(), rPos.Tab(), rPos.Col(), rPos.Row(), 
rPos.Tab(),
-            PaintPartFlags::Grid, nExtFlags);
+            PaintPartFlags::Grid, nExtFlags, nBefore);
 
     aModificator.SetDocumentModified();
 
@@ -833,7 +854,9 @@ bool ScDocFunc::SetNormalString( bool& o_rbNumFmtSet, const 
ScAddress& rPos, con
         aOldValues.push_back(aOldValue);
     }
 
+    tools::Long nBefore(rDocShell.GetPixelWidthHint(rPos));
     o_rbNumFmtSet = rDoc.SetString( rPos.Col(), rPos.Row(), rPos.Tab(), rText 
);
+    tools::Long nAfter(rDocShell.GetPixelWidthHint(rPos));
 
     if (bUndo)
     {
@@ -845,7 +868,7 @@ bool ScDocFunc::SetNormalString( bool& o_rbNumFmtSet, const 
ScAddress& rPos, con
     if ( bEditDeleted || rDoc.HasAttrib( ScRange(rPos), 
HasAttrFlags::NeedHeight ) )
         AdjustRowHeight( ScRange(rPos), true, bApi );
 
-    rDocShell.PostPaintCell( rPos );
+    rDocShell.PostPaintCell( rPos, std::max(nBefore, nAfter) );
     aModificator.SetDocumentModified();
 
     // notify input handler here the same way as in PutCell
diff --git a/sc/source/ui/docshell/docsh3.cxx b/sc/source/ui/docshell/docsh3.cxx
index 0e2efa7f09fc..388a51758295 100644
--- a/sc/source/ui/docshell/docsh3.cxx
+++ b/sc/source/ui/docshell/docsh3.cxx
@@ -100,13 +100,13 @@ void ScDocShell::PostDataChanged()
 
 void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
                             SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, 
PaintPartFlags nPart,
-                            sal_uInt16 nExtFlags )
+                            sal_uInt16 nExtFlags, tools::Long 
nMaxWidthAffectedHint )
 {
     ScRange aRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
-    PostPaint(aRange, nPart, nExtFlags);
+    PostPaint(aRange, nPart, nExtFlags, nMaxWidthAffectedHint);
 }
 
-void ScDocShell::PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, 
sal_uInt16 nExtFlags )
+void ScDocShell::PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, 
sal_uInt16 nExtFlags, tools::Long nMaxWidthAffectedHint )
 {
     ScRangeList aPaintRanges;
     std::set<SCTAB> aTabsInvalidated;
@@ -118,9 +118,17 @@ void ScDocShell::PostPaint( const ScRangeList& rRanges, 
PaintPartFlags nPart, sa
         SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
         SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = std::min<SCTAB>(nMaxTab, 
rRange.aEnd.Tab());
 
-        if (!m_pDocument->ValidCol(nCol1)) nCol1 = m_pDocument->MaxCol();
+        if (!m_pDocument->ValidCol(nCol1))
+        {
+            nMaxWidthAffectedHint = -1; // Hint no longer valid
+            nCol1 = m_pDocument->MaxCol();
+        }
         if (!m_pDocument->ValidRow(nRow1)) nRow1 = m_pDocument->MaxRow();
-        if (!m_pDocument->ValidCol(nCol2)) nCol2 = m_pDocument->MaxCol();
+        if (!m_pDocument->ValidCol(nCol2))
+        {
+            nMaxWidthAffectedHint = -1; // Hint no longer valid
+            nCol2 = m_pDocument->MaxCol();
+        }
         if (!m_pDocument->ValidRow(nRow2)) nRow2 = m_pDocument->MaxRow();
 
         if ( m_pPaintLockData )
@@ -143,8 +151,16 @@ void ScDocShell::PostPaint( const ScRangeList& rRanges, 
PaintPartFlags nPart, sa
         if (nExtFlags & SC_PF_LINES)            // respect space for lines
         {
                                                 //! check for hidden 
columns/rows!
-            if (nCol1>0) --nCol1;
-            if (nCol2<m_pDocument->MaxCol()) ++nCol2;
+            if (nCol1 > 0)
+            {
+                nMaxWidthAffectedHint = -1; // Hint no longer valid
+                --nCol1;
+            }
+            if (nCol2 < m_pDocument->MaxCol())
+            {
+                nMaxWidthAffectedHint = -1; // Hint no longer valid
+                ++nCol2;
+            }
             if (nRow1>0) --nRow1;
             if (nRow2<m_pDocument->MaxRow()) ++nRow2;
         }
@@ -166,6 +182,7 @@ void ScDocShell::PostPaint( const ScRangeList& rRanges, 
PaintPartFlags nPart, sa
             {
                 nCol1 = 0;
                 nCol2 = m_pDocument->MaxCol();
+                nMaxWidthAffectedHint = -1; // Hint no longer valid
             }
         }
         aPaintRanges.push_back(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, 
nTab2));
@@ -173,7 +190,7 @@ void ScDocShell::PostPaint( const ScRangeList& rRanges, 
PaintPartFlags nPart, sa
             aTabsInvalidated.insert(nTabNum);
     }
 
-    Broadcast(ScPaintHint(aPaintRanges.Combine(), nPart));
+    Broadcast(ScPaintHint(aPaintRanges.Combine(), nPart, 
nMaxWidthAffectedHint));
 
     // LOK: we are supposed to update the row / columns headers (and actually
     // the document size too - cell size affects that, obviously)
@@ -190,14 +207,14 @@ void ScDocShell::PostPaintGridAll()
     PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, 
PaintPartFlags::Grid );
 }
 
-void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
+void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab, 
tools::Long nMaxWidthAffectedHint )
 {
-    PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, 
SC_PF_TESTMERGE );
+    PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, 
SC_PF_TESTMERGE, nMaxWidthAffectedHint );
 }
 
-void ScDocShell::PostPaintCell( const ScAddress& rPos )
+void ScDocShell::PostPaintCell( const ScAddress& rPos, tools::Long 
nMaxWidthAffectedHint )
 {
-    PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() );
+    PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab(), nMaxWidthAffectedHint );
 }
 
 void ScDocShell::PostPaintExtras()
diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx
index cb54b932991a..2d13df4848b3 100644
--- a/sc/source/ui/inc/docsh.hxx
+++ b/sc/source/ui/inc/docsh.hxx
@@ -314,13 +314,16 @@ public:
 
     void            PostEditView( ScEditEngineDefaulter* pEditEngine, const 
ScAddress& rCursorPos );
 
+    tools::Long     GetPixelWidthHint(const ScAddress& rPos);
+
     void            PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB 
nStartTab,
                             SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, 
PaintPartFlags nPart,
-                            sal_uInt16 nExtFlags = 0 );
-    void            PostPaint( const ScRangeList& rRanges, PaintPartFlags 
nPart, sal_uInt16 nExtFlags = 0 );
+                            sal_uInt16 nExtFlags = 0, tools::Long 
nMaxWidthAffectedHint = -1 );
+    void            PostPaint( const ScRangeList& rRanges, PaintPartFlags 
nPart, sal_uInt16 nExtFlags = 0,
+                               tools::Long nMaxWidthAffectedHint = -1 );
 
-    void            PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab );
-    void            PostPaintCell( const ScAddress& rPos );
+    void            PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab, 
tools::Long nMaxWidthAffectedHint = -1);
+    void            PostPaintCell( const ScAddress& rPos, tools::Long 
nMaxWidthAffectedHint = -1);
     void            PostPaintGridAll();
     void            PostPaintExtras();
 
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 648c9189a3a0..e6c68651804a 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -478,7 +478,8 @@ public:
                                     // Drawing
 
     void            PaintArea( SCCOL nStartCol, SCROW nStartRow, SCCOL 
nEndCol, SCROW nEndRow,
-                                        ScUpdateMode eMode = ScUpdateMode::All 
);
+                               ScUpdateMode eMode = ScUpdateMode::All,
+                               tools::Long nMaxWidthAffectedHint = -1 );
 
     void            PaintGrid();
 
diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
index 8fdd5f5a3a33..db171a96e3b1 100644
--- a/sc/source/ui/view/tabview3.cxx
+++ b/sc/source/ui/view/tabview3.cxx
@@ -2326,7 +2326,7 @@ void ScTabView::UpdateFormulas(SCCOL nStartCol, SCROW 
nStartRow, SCCOL nEndCol,
 //  PaintArea - repaint block
 
 void ScTabView::PaintArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, 
SCROW nEndRow,
-                            ScUpdateMode eMode )
+                            ScUpdateMode eMode, tools::Long 
nMaxWidthAffectedHint )
 {
     SCCOL nCol1;
     SCROW nRow1;
@@ -2404,20 +2404,32 @@ void ScTabView::PaintArea( SCCOL nStartCol, SCROW 
nStartRow, SCCOL nEndCol, SCRO
 
         if ( eMode == ScUpdateMode::All )
         {
-            if (bIsTiledRendering)
+            if (nMaxWidthAffectedHint != -1)
             {
-                // When a cell content is deleted we have no clue about
-                // the width of the embedded text.
-                // Anyway, clients will ask only for tiles that overlaps
-                // the visible area.
-                // Remember that wsd expects int and that aEnd.X() is
-                // in pixels and will be converted in twips, before performing
-                // the lok callback, so we need to avoid that an overflow 
occurs.
-                aEnd.setX( std::numeric_limits<int>::max() / 1000 );
+                // If we know the max text width affected then just invalidate
+                // the max of the cell width and hint of affected cell width
+                // (where affected with is in terms of max width of optimal 
cell
+                // width for before/after change)
+                tools::Long nCellWidth = std::abs(aEnd.X() - aStart.X());
+                aEnd.setX(aStart.getX() + std::max(nCellWidth, 
nMaxWidthAffectedHint) * nLayoutSign);
             }
             else
             {
-                aEnd.setX( bLayoutRTL ? 0 : 
pGridWin[i]->GetOutputSizePixel().Width() );
+                if (bIsTiledRendering)
+                {
+                    // When a cell content is deleted we have no clue about
+                    // the width of the embedded text.
+                    // Anyway, clients will ask only for tiles that overlaps
+                    // the visible area.
+                    // Remember that wsd expects int and that aEnd.X() is
+                    // in pixels and will be converted in twips, before 
performing
+                    // the lok callback, so we need to avoid that an overflow 
occurs.
+                    aEnd.setX( std::numeric_limits<int>::max() / 1000 );
+                }
+                else
+                {
+                    aEnd.setX( bLayoutRTL ? 0 : 
pGridWin[i]->GetOutputSizePixel().Width() );
+                }
             }
         }
         aEnd.AdjustX( -nLayoutSign );
diff --git a/sc/source/ui/view/tabvwsh5.cxx b/sc/source/ui/view/tabvwsh5.cxx
index b701cc327e5e..711344d50f08 100644
--- a/sc/source/ui/view/tabvwsh5.cxx
+++ b/sc/source/ui/view/tabvwsh5.cxx
@@ -57,12 +57,15 @@ void ScTabViewShell::Notify( SfxBroadcaster& rBC, const 
SfxHint& rHint )
 
             if (nParts & PaintPartFlags::Size)
                 RepeatResize();                     //! InvalidateBorder ???
+            const tools::Long nWidthAffectedHint = 
pPaintHint->GetMaxWidthAffectedHint();
             if (nParts & PaintPartFlags::Grid)
                 PaintArea( pPaintHint->GetStartCol(), 
pPaintHint->GetStartRow(),
-                           pPaintHint->GetEndCol(), pPaintHint->GetEndRow() );
+                           pPaintHint->GetEndCol(), pPaintHint->GetEndRow(),
+                           ScUpdateMode::All, nWidthAffectedHint );
             if (nParts & PaintPartFlags::Marks)
                 PaintArea( pPaintHint->GetStartCol(), 
pPaintHint->GetStartRow(),
-                           pPaintHint->GetEndCol(), pPaintHint->GetEndRow(), 
ScUpdateMode::Marks );
+                           pPaintHint->GetEndCol(), pPaintHint->GetEndRow(),
+                           ScUpdateMode::Marks, nWidthAffectedHint );
             if (nParts & PaintPartFlags::Left)
                 PaintLeftArea( pPaintHint->GetStartRow(), 
pPaintHint->GetEndRow() );
             if (nParts & PaintPartFlags::Top)
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
index 567447149937..11c4096c1445 100644
--- a/sc/source/ui/view/viewfun3.cxx
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -1266,6 +1266,11 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags 
nFlags, ScDocument* pClipDoc,
         }
     }
 
+    const bool bSingleCellBefore = nStartCol == nEndCol &&
+                                   nStartRow == nEndRow &&
+                                   nStartTab == nEndTab;
+    tools::Long nBeforeHint(bSingleCellBefore ? 
pDocSh->GetPixelWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)) : -1);
+
     sal_uInt16 nExtFlags = 0;
     pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
                                        nEndCol,   nEndRow,   nEndTab );     // 
content before the change
@@ -1441,9 +1446,20 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags 
nFlags, ScDocument* pClipDoc,
         nPaint |= PaintPartFlags::Left;
         nUndoEndRow = rDoc.MaxRow();               // just for drawing !
     }
+
+    tools::Long nMaxWidthAffectedHint = -1;
+    const bool bSingleCellAfter = nStartCol == nUndoEndCol &&
+                                  nStartRow == nUndoEndRow &&
+                                  nStartTab == nEndTab;
+    if (bSingleCellBefore && bSingleCellAfter)
+    {
+        tools::Long nAfterHint(pDocSh->GetPixelWidthHint(ScAddress(nStartCol, 
nStartRow, nStartTab)));
+        nMaxWidthAffectedHint = std::max(nBeforeHint, nAfterHint);
+    }
+
     pDocSh->PostPaint(
         ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, 
nEndTab),
-        nPaint, nExtFlags);
+        nPaint, nExtFlags, nMaxWidthAffectedHint);
     // AdjustBlockHeight has already been called above
 
     aModificator.SetDocumentModified();

Reply via email to