sc/CppunitTest_sc_uicalc2.mk                 |    1 
 sc/qa/unit/uicalc/data/biff12.clipboard.xlsb |binary
 sc/qa/unit/uicalc/uicalc2.cxx                |   81 +++++++++++++++++++++++++++
 sc/source/core/data/SheetViewManager.cxx     |    5 +
 sc/source/filter/xml/xmlexprt.cxx            |    7 ++
 sc/source/ui/view/viewfun5.cxx               |    7 ++
 svx/qa/unit/classicshapes.cxx                |   28 +++++++++
 svx/qa/unit/data/tdf139968_shear45_rot30.odg |binary
 svx/source/svdraw/svdocirc.cxx               |   10 +--
 9 files changed, 132 insertions(+), 7 deletions(-)

New commits:
commit 54e4ab489340480ddf63452deb1d753642ac5026
Author:     Mike Kaganski <[email protected]>
AuthorDate: Tue Feb 3 18:53:38 2026 +0500
Commit:     Xisco Fauli <[email protected]>
CommitDate: Wed Feb 4 21:29:30 2026 +0100

    tdf#170567: Avoid resetting destination document's data
    
    When clipboard document is set up in Biff12 paste code, a call to
    ScDocument::ResetClip is required. In nearby code, the destination
    document is used for that, which was why I did the same.
    
    But it turned out, that following call to SfxObjectShell::DoLoad
    called ScDocShell::InitNew, and there some shared pooled items got
    reset, including an ScPatternAttr used for default attributes. It
    included clearing style pattern's, and that change affected target
    document. Then, in export, the document's formatting ranges were
    collected in ScXMLExport::AddStyleFromCells, which checked direct
    properties of each range. The document's default ScPatternAttr was
    missing style, and ScCellRangesBase::GetOnePropertyState returned
    PropertyState_AMBIGUOUS_VALUE, and ScXMLExport::AddStyleFromCells
    got empty aPropStates, without style name (which is documented to
    not have a default, so it must always be present). In the end, the
    default-formatted document ranges didn't create respective entries
    in ScRowFormatRanges::aRowFormatRanges.
    
    Then in ScXMLExport::ExportFormatRanges, trying to export formats
    for the first (default-formatted) rows, calls to GetFormatRanges
    left pRowFormatRanges empty, meaning that nMaxRows were 0, and no
    advance happened in the loop -> hang. (Maybe a similar situation
    caused commit b36a8a532b3ee6521d80277cb32a6936c0b09320 - busy loop
    seen on ods export attempt, 2023-12-07.)
    
    This change avoids unintended modification of the target document,
    by creating a fake "source" document to use in ResetClip.
    
    Also, this changes OSL_ENSURE to an assert, and fails export with
    XMLERROR_CANCEL | XMLERROR_FLAG_SEVERE error, when nMaxRows is 0
    in ScXMLExport::ExportFormatRanges - same as what the mentioned
    commit b36a8a532b3ee6521d80277cb32a6936c0b09320 did in an adjacent
    branch.
    
    Change-Id: I3839ef0d2cb42d33cfc0b36b329658e159022586
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198609
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>
    (cherry picked from commit 17fb6ff6d163c7037e1c66d28c229473ab77717e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198625
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/sc/CppunitTest_sc_uicalc2.mk b/sc/CppunitTest_sc_uicalc2.mk
index fbc467622f40..ec9ebbafb23a 100644
--- a/sc/CppunitTest_sc_uicalc2.mk
+++ b/sc/CppunitTest_sc_uicalc2.mk
@@ -29,6 +29,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_uicalc2, \
     sc \
     scqahelper \
     sfx \
+    sot \
     subsequenttest \
     svl \
     svl \
diff --git a/sc/qa/unit/uicalc/data/biff12.clipboard.xlsb 
b/sc/qa/unit/uicalc/data/biff12.clipboard.xlsb
new file mode 100644
index 000000000000..a013537d1cfc
Binary files /dev/null and b/sc/qa/unit/uicalc/data/biff12.clipboard.xlsb differ
diff --git a/sc/qa/unit/uicalc/uicalc2.cxx b/sc/qa/unit/uicalc/uicalc2.cxx
index 047abf75c1a0..7bc542920cbf 100644
--- a/sc/qa/unit/uicalc/uicalc2.cxx
+++ b/sc/qa/unit/uicalc/uicalc2.cxx
@@ -8,9 +8,13 @@
  */
 
 #include "../helper/qahelper.hxx"
+
+#include <comphelper/compbase.hxx>
 #include <editeng/brushitem.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sot/exchange.hxx>
 #include <svx/svdpage.hxx>
+#include <tools/stream.hxx>
 #include <vcl/keycodes.hxx>
 #include <vcl/scheduler.hxx>
 #include <stlsheet.hxx>
@@ -20,6 +24,9 @@
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/servicehelper.hxx>
 #include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
 #include <com/sun/star/sheet/GlobalSheetSettings.hpp>
 #include <com/sun/star/text/XTextRange.hpp>
 #include <dbdata.hxx>
@@ -1738,6 +1745,80 @@ CPPUNIT_TEST_FIXTURE(ScUiCalcTest2, 
testcommand_SetOptimalColumnWidth)
     CPPUNIT_ASSERT_EQUAL(nWidthB, pDoc->GetColWidth(1, 0));
 }
 
+CPPUNIT_TEST_FIXTURE(ScUiCalcTest2, testTdf170567_paste_Biff12_and_save_ODS)
+{
+    // A simple XTransferable implementation, that can provide a Biff12 
content from file
+    class Biff12Transferable : public 
comphelper::WeakImplHelper<datatransfer::XTransferable>
+    {
+    public:
+        Biff12Transferable(const OUString& url)
+            : m_aFileURL(url)
+        {
+        }
+
+        // XTransferable
+        uno::Any SAL_CALL getTransferData(const datatransfer::DataFlavor& 
aFlavor) override
+        {
+            if (!isDataFlavorSupported(aFlavor))
+                return {};
+            SvFileStream aStream(m_aFileURL, StreamMode::READ);
+            uno::Sequence<sal_Int8> bytes(aStream.remainingSize());
+            aStream.ReadBytes(bytes.getArray(), aStream.remainingSize());
+            return uno::Any(bytes);
+        }
+        uno::Sequence<datatransfer::DataFlavor> SAL_CALL 
getTransferDataFlavors() override
+        {
+            return { getBiff12Flavor() };
+        }
+        sal_Bool SAL_CALL isDataFlavorSupported(const 
datatransfer::DataFlavor& aFlavor) override
+        {
+            return 
aFlavor.MimeType.equalsIgnoreAsciiCase(getBiff12Flavor().MimeType);
+        }
+
+    private:
+        OUString m_aFileURL;
+
+        static datatransfer::DataFlavor getBiff12Flavor()
+        {
+            datatransfer::DataFlavor ret;
+            
CPPUNIT_ASSERT(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BIFF_12, 
ret));
+            return ret;
+        }
+    };
+
+    // Put a Biff12 format data into system clipboard:
+    auto xContext(comphelper::getProcessComponentContext());
+    auto xClipboard = xContext->getServiceManager()
+                          ->createInstanceWithContext(
+                              
u"com.sun.star.datatransfer.clipboard.SystemClipboard"_ustr, xContext)
+                          .queryThrow<datatransfer::clipboard::XClipboard>();
+    xClipboard->setContents(new 
Biff12Transferable(createFileURL(u"biff12.clipboard.xlsb")), {});
+
+    // Create document, and paste into C4 (important that first row is empty):
+    createScDoc();
+    goToCell(u"C4"_ustr);
+    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
+
+    ScDocument* pDoc = getScDoc();
+    CPPUNIT_ASSERT_EQUAL(u"1"_ustr, pDoc->GetString(ScAddress(2, 3, 0)));
+    CPPUNIT_ASSERT_EQUAL(u"2"_ustr, pDoc->GetString(ScAddress(2, 4, 0)));
+    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, pDoc->GetString(ScAddress(3, 3, 0)));
+    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pDoc->GetString(ScAddress(3, 4, 0)));
+
+    // Save to ODS and realod. Without the fix in place, this test used to 
hang (and now there is
+    // an assertion that would fail):
+    saveAndReload(TestFilter::ODS);
+
+    pDoc = getScDoc();
+    CPPUNIT_ASSERT_EQUAL(u"1"_ustr, pDoc->GetString(ScAddress(2, 3, 0)));
+    CPPUNIT_ASSERT_EQUAL(u"2"_ustr, pDoc->GetString(ScAddress(2, 4, 0)));
+    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, pDoc->GetString(ScAddress(3, 3, 0)));
+    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pDoc->GetString(ScAddress(3, 4, 0)));
+
+    // No need to keep clipboard content after the test
+    xClipboard->setContents({}, {});
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/xmlexprt.cxx 
b/sc/source/filter/xml/xmlexprt.cxx
index 6200754b01c9..be9c27da34e3 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -1589,7 +1589,12 @@ void ScXMLExport::ExportFormatRanges(ScDocument& rDoc, 
const sal_Int32 nStartCol
             {
                 pCellStyles->GetFormatRanges(0, 
pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, 
pRowFormatRanges.get());
                 sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows();
-                OSL_ENSURE(nMaxRows, "something went wrong");
+                assert(nMaxRows && "ScXMLExport::ExportFormatRanges cannot 
make progress with zero rows, something went wrong");
+                if (!nMaxRows)
+                {
+                    SetError(XMLERROR_CANCEL | XMLERROR_FLAG_SEVERE, {});
+                    break;
+                }
                 if (nMaxRows >= nTotalRows - nRows)
                 {
                     OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, 
aRowAttr);
diff --git a/sc/source/ui/view/viewfun5.cxx b/sc/source/ui/view/viewfun5.cxx
index d294979cb389..5a401d20e9ba 100644
--- a/sc/source/ui/view/viewfun5.cxx
+++ b/sc/source/ui/view/viewfun5.cxx
@@ -340,9 +340,13 @@ bool ScViewFunc::PasteDataFormat( SotClipboardFormatId 
nFormatId,
             SfxFilterMatcher 
aMatcher(ScDocShell::Factory().GetFilterContainer()->GetName());
             if (auto pFilter = 
aMatcher.GetFilter4ClipBoardId(SotClipboardFormatId::BIFF_12))
             {
+                // Do not use rDoc as "source" in the call to ResetClip: 
DoLoad would call InitNew,
+                // which resets many pooled items, shared between source and 
clipboard documents,
+                // which modifies the source. We don't want that, so use a 
temporary document.
+                ScDocument aTmpClipSrc(SCDOCMODE_DOCUMENT);
                 ScDocShellRef pClipShell(new ScDocShell(SfxModelFlags::NONE, 
SCDOCMODE_CLIP));
                 SCTAB nSrcTab = 0;
-                pClipShell->GetDocument().ResetClip(&rDoc, nSrcTab);
+                pClipShell->GetDocument().ResetClip(&aTmpClipSrc, nSrcTab);
                 auto pMed = std::make_unique<SfxMedium>();
                 pMed->GetItemSet().Put(SfxUnoAnyItem(SID_INPUTSTREAM, 
uno::Any(xStm)));
                 pMed->SetFilter(pFilter);
@@ -353,6 +357,7 @@ bool ScViewFunc::PasteDataFormat( SotClipboardFormatId 
nFormatId,
                                        bAllowDialogs);
                     bRet = true;
                 }
+                pClipShell->DoClose();
             }
         }
     }
commit ef92e8b8b41f5ff578bf814e821f1820609603cb
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Feb 3 14:54:55 2026 +0100
Commit:     Xisco Fauli <[email protected]>
CommitDate: Wed Feb 4 21:29:25 2026 +0100

    sc: fix crash in SheetViewManager::unsyncAllSheetViews()
    
    gdb on the crashreport's core file:
    
            #0  0x00007afad505b307 in sc::SheetView::unsync (this=0x0) at 
sc/inc/SheetView.hxx:44
            #1  sc::SheetViewManager::unsyncAllSheetViews (this=0x11fa76c0) at 
sc/source/core/data/SheetViewManager.cxx:120
            #2  0x00007afad552a415 in sc::SheetViewOperationsTester::check 
(this=this@entry=0x7ffcad3703c0, eOperation=<optimized out>, 
eOperation@entry=sc::Operation::DeleteRows)
                at sc/source/ui/docshell/SheetViewOperationsTester.cxx:157
            #3  0x00007afad54c2235 in ScDocFunc::CheckSheetViewProtection 
(eOperation=sc::Operation::DeleteRows)
                at sc/source/ui/docshell/docfunc.cxx:126
            #4  ScDocFunc::DeleteCells (this=0x124ca680, rRange=..., 
pTabMark=pTabMark@entry=0x164cec90, eCmd=<optimized out>, 
eCmd@entry=DelCellCmd::Rows, bApi=bApi@entry=false)
                at sc/source/ui/docshell/docfunc.cxx:2469
            #5  0x00007afad5971e06 in ScViewFunc::DeleteCells 
(this=this@entry=0x164cec60, eCmd=eCmd@entry=DelCellCmd::Rows) at 
/opt/rh/devtoolset-12/root/usr/include/c++/12/bits/unique_ptr.h:445
            #6  0x00007afad57f13c6 in ScCellShell::ExecuteEdit 
(this=0x183359d0, rReq=...)
                at sc/source/ui/view/cellsh1.cxx:348
    
    Seeing that SheetViewManager::getPreviousSheetView() checks if the
    pointers in the maViews container are nullptr, do the same here.
    
    Change-Id: I0e430edacccae83e2d2d5e7228c437dbd1de5d60
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198645
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <[email protected]>
    (cherry picked from commit 437d332908ac002075a2650fb91bf70460ef4049)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198676
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/sc/source/core/data/SheetViewManager.cxx 
b/sc/source/core/data/SheetViewManager.cxx
index 4cf291f8d8b5..c2b95bf44d10 100644
--- a/sc/source/core/data/SheetViewManager.cxx
+++ b/sc/source/core/data/SheetViewManager.cxx
@@ -117,6 +117,11 @@ void SheetViewManager::unsyncAllSheetViews()
 {
     for (auto const& pSheetView : maViews)
     {
+        if (!pSheetView)
+        {
+            continue;
+        }
+
         pSheetView->unsync();
     }
 }
commit 6e10c1d682c4fba2da642ce3a76fc98423cb159b
Author:     Regina Henschel <[email protected]>
AuthorDate: Wed Feb 4 00:36:04 2026 +0100
Commit:     Xisco Fauli <[email protected]>
CommitDate: Wed Feb 4 21:29:18 2026 +0100

    tdf#139968 first shear then rotate point of arc
    
    All internal calculation for transformation use the order resize, shear,
    rotate, translate. Thus the transformation of the points determining
    the angles of non-full SdrCircObj need to use that order too.
    
    Change-Id: If05310c64813bcffa410a328cf831b3f0b4c07e2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198630
    Reviewed-by: Regina Henschel <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit fe00ea424ebda161badc3d7ff57957077e7a457a)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198699
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/svx/qa/unit/classicshapes.cxx b/svx/qa/unit/classicshapes.cxx
index 07a4b9f916ab..ea536ff3ec91 100644
--- a/svx/qa/unit/classicshapes.cxx
+++ b/svx/qa/unit/classicshapes.cxx
@@ -10,6 +10,9 @@
 #include <test/unoapi_test.hxx>
 #include <rtl/ustring.hxx>
 #include <editeng/unoprnms.hxx>
+#include <svx/svdocirc.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svx/svdview.hxx>
 
 #include <cppunit/TestAssert.h>
 
@@ -187,5 +190,30 @@ CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf130076Flip)
                                      26000.0, nAngle2);
     }
 }
+
+CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf139968ShearRotateArcFlip)
+{
+    // The document contains an arc that is rotated and sheared. When 
horizonally flipped, start and
+    // end angles had got wrong values.
+    loadFromFile(u"tdf139968_shear45_rot30.odg");
+
+    // get shape and flip it
+    uno::Reference<drawing::XShape> xShape(getShape(0, 0));
+    SdrCircObj* 
pSdrCircObj(static_cast<SdrCircObj*>(SdrObject::getSdrObjectFromXShape(xShape)));
+    SfxViewShell* pViewShell = SfxViewShell::Current();
+    CPPUNIT_ASSERT(pViewShell);
+    SdrView* pSdrView = pViewShell->GetDrawView();
+    pSdrView->MarkObj(pSdrCircObj, pSdrView->GetSdrPageView());
+    dispatchCommand(mxComponent, u".uno:FlipHorizontal"_ustr, {});
+
+    // make sure start and end angle are correct.
+    double fAngleS(0.0), fAngleE(0.0);
+    uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xShapeProps->getPropertyValue(u"CircleStartAngle"_ustr) >>= 
fAngleS);
+    CPPUNIT_ASSERT(xShapeProps->getPropertyValue(u"CircleEndAngle"_ustr) >>= 
fAngleE);
+    // without fix, start angle was 19419, end angle was 18176. Tolerance for 
to ignore round errors.
+    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("StartAngle wrong", 22500.0, fAngleS, 
2.0);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("EndAngle wrong", 18000.0, fAngleE, 
2.0);
+}
 }
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/data/tdf139968_shear45_rot30.odg 
b/svx/qa/unit/data/tdf139968_shear45_rot30.odg
new file mode 100644
index 000000000000..7898593c5200
Binary files /dev/null and b/svx/qa/unit/data/tdf139968_shear45_rot30.odg differ
diff --git a/svx/source/svdraw/svdocirc.cxx b/svx/source/svdraw/svdocirc.cxx
index eed36dbc71c1..ef4e8b5f04dc 100644
--- a/svx/source/svdraw/svdocirc.cxx
+++ b/svx/source/svdraw/svdocirc.cxx
@@ -901,16 +901,16 @@ void SdrCircObj::NbcMirror(const Point& rRef1, const 
Point& rRef2)
         if (nWdt==0) aTmpPt2.setX(0 );
         if (nHgt==0) aTmpPt2.setY(0 );
         aTmpPt2+=aCenter;
-        if (maGeo.m_nRotationAngle)
-        {
-            RotatePoint(aTmpPt1, getRectangle().TopLeft(), 
maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
-            RotatePoint(aTmpPt2, getRectangle().TopLeft(), 
maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
-        }
         if (maGeo.m_nShearAngle)
         {
             ShearPoint(aTmpPt1, getRectangle().TopLeft(), 
maGeo.mfTanShearAngle);
             ShearPoint(aTmpPt2, getRectangle().TopLeft(), 
maGeo.mfTanShearAngle);
         }
+        if (maGeo.m_nRotationAngle)
+        {
+            RotatePoint(aTmpPt1, getRectangle().TopLeft(), 
maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+            RotatePoint(aTmpPt2, getRectangle().TopLeft(), 
maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+        }
     }
     SdrTextObj::NbcMirror(rRef1,rRef2);
     if (meCircleKind!=SdrCircKind::Full) { // adapt starting and finishing 
angle

Reply via email to