tdf#144642 XLSX import: round down row height to 0.75 pt

like table layout of MSO does, e.g. 20 pt to 19.5 pt.

Changing table row height is only for interoperability.
To avoid of regressions, apply this workaround only for
documents created in MSO.

Note: likely this is an old adjustment for low-resolution
monitors, where 0.75 is the factor between 96 ppi of Windows
resolution and (originally) 72 ppi of monitor resolutions.

Co-authored-by: Tibor Nagy (NISZ)

Change-Id: Ie1e2c781d21174a877b18cd3250eb445222bd1c4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122428
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/include/oox/core/xmlfilterbase.hxx b/include/oox/core/xmlfilterbase.hxx
index 7c1cada..15de6ce 100644
--- a/include/oox/core/xmlfilterbase.hxx
+++ b/include/oox/core/xmlfilterbase.hxx
@@ -246,6 +246,7 @@ public:
    static FastParser* createParser();

    bool isMSO2007Document() const;
    bool isMSODocument() const;

    /// Signal that an MSO 2007-created SmartArt was found, need to warn the
    /// user about it.
@@ -281,6 +282,7 @@ private:
    sal_Int32 mnRelId;
    sal_Int32 mnMaxDocId;
    bool mbMSO2007;
    bool mbMSO;
protected:
    bool mbMissingExtDrawing;
};
diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx
index 371439b..7f4ff6b 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -200,6 +200,7 @@ XmlFilterBase::XmlFilterBase( const Reference< XComponentContext >& rxContext ) 
    mnRelId( 1 ),
    mnMaxDocId( 0 ),
    mbMSO2007(false),
    mbMSO(false),
    mbMissingExtDrawing(false)
{
}
@@ -218,9 +219,10 @@ XmlFilterBase::~XmlFilterBase()

void XmlFilterBase::checkDocumentProperties(const Reference<XDocumentProperties>& xDocProps)
{
    mbMSO2007 = false;
    mbMSO2007 = mbMSO = false;
    if (!xDocProps->getGenerator().startsWithIgnoreAsciiCase("Microsoft"))
        return;
    mbMSO = true;

    uno::Reference<beans::XPropertyAccess> xUserDefProps(xDocProps->getUserDefinedProperties(), uno::UNO_QUERY);
    if (!xUserDefProps.is())
@@ -1020,6 +1022,11 @@ bool XmlFilterBase::isMSO2007Document() const
    return mbMSO2007;
}

bool XmlFilterBase::isMSODocument() const
{
    return mbMSO;
}

void XmlFilterBase::setMissingExtDrawing()
{
    mbMissingExtDrawing = true;
diff --git a/sc/qa/unit/data/xlsx/tdf144642_RowHeight_10mm_SavedByCalc.xlsx b/sc/qa/unit/data/xlsx/tdf144642_RowHeight_10mm_SavedByCalc.xlsx
new file mode 100644
index 0000000..d85d94c
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/tdf144642_RowHeight_10mm_SavedByCalc.xlsx
Binary files differ
diff --git a/sc/qa/unit/data/xlsx/tdf144642_RowHeight_28.35pt_SavedByExcel.xlsx b/sc/qa/unit/data/xlsx/tdf144642_RowHeight_28.35pt_SavedByExcel.xlsx
new file mode 100644
index 0000000..367922d
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/tdf144642_RowHeight_28.35pt_SavedByExcel.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_export_test.cxx b/sc/qa/unit/subsequent_export_test.cxx
index aa2a12f..ad27741 100644
--- a/sc/qa/unit/subsequent_export_test.cxx
+++ b/sc/qa/unit/subsequent_export_test.cxx
@@ -1564,7 +1564,7 @@ void ScExportTest::testMiscRowHeightExport()
    static const TestParam::RowData DfltRowData[] = {
        { 0, 4, 0, 529, 0, false },
        { 5, 10, 0, 1058, 0, false },
        { 17, 20, 0, 1767, 0, false },
        { 17, 20, 0, 1746, 0, false },
        // check last couple of row in document to ensure
        // they are 5.29mm ( effective default row xlsx height )
        { 1048573, 1048575, 0, 529, 0, false },
diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx
index cea7c5e..2be6a07 100644
--- a/sc/qa/unit/subsequent_export_test2.cxx
+++ b/sc/qa/unit/subsequent_export_test2.cxx
@@ -199,6 +199,7 @@ public:
    void testTdf136721_paper_size();
    void testTdf139258_rotated_image();
    void testTdf142854_GridVisibilityImportXlsxInHeadlessMode();
    void testTdf144642_RowHeightRounding();
    void testTdf140431();
    void testCheckboxFormControlXlsxExport();
    void testButtonFormControlXlsxExport();
@@ -309,6 +310,7 @@ public:
    CPPUNIT_TEST(testTdf136721_paper_size);
    CPPUNIT_TEST(testTdf139258_rotated_image);
    CPPUNIT_TEST(testTdf142854_GridVisibilityImportXlsxInHeadlessMode);
    CPPUNIT_TEST(testTdf144642_RowHeightRounding);
    CPPUNIT_TEST(testTdf140431);
    CPPUNIT_TEST(testCheckboxFormControlXlsxExport);
    CPPUNIT_TEST(testButtonFormControlXlsxExport);
@@ -2547,6 +2549,29 @@ void ScExportTest2::testTdf142854_GridVisibilityImportXlsxInHeadlessMode()
    CPPUNIT_ASSERT(!xShell->GetDocument().GetViewOptions().GetOption(VOPT_GRID));
}

void ScExportTest2::testTdf144642_RowHeightRounding()
{
    // MS Excel round down row heights to 0.75pt
    // MS Excel can save a row height of 28.35pt, but will display it as a row height of 27.75pt.
    // Calc simulates this roundings but only if the xlsx file was saved in MS Excel.

    ScDocShellRef xShell = loadDoc(u"tdf144642_RowHeight_10mm_SavedByCalc.", FORMAT_XLSX);
    CPPUNIT_ASSERT(xShell.is());
    ScDocument& rDoc = xShell->GetDocument();
    // 10mm == 567 twips == 28.35pt
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(567), rDoc.GetRowHeight(0, 0));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(567 * 26), rDoc.GetRowHeight(0, 25, 0, true));
    xShell->DoClose();

    xShell = loadDoc(u"tdf144642_RowHeight_28.35pt_SavedByExcel.", FORMAT_XLSX);
    CPPUNIT_ASSERT(xShell.is());
    ScDocument& rDoc2 = xShell->GetDocument();
    // 555twips == 27.75pt == 9.79mm
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(555), rDoc2.GetRowHeight(0, 0));
    CPPUNIT_ASSERT_EQUAL(sal_uLong(555 * 26), rDoc2.GetRowHeight(0, 25, 0, true));
    xShell->DoClose();
}

void ScExportTest2::testTdf140431()
{
    ScDocShellRef xShell = loadDoc(u"129969-min.", FORMAT_XLSX);
diff --git a/sc/source/filter/oox/sheetdatacontext.cxx b/sc/source/filter/oox/sheetdatacontext.cxx
index c2b47a1..ddc3c9f 100644
--- a/sc/source/filter/oox/sheetdatacontext.cxx
+++ b/sc/source/filter/oox/sheetdatacontext.cxx
@@ -19,6 +19,7 @@

#include <sheetdatacontext.hxx>

#include <oox/core/xmlfilterbase.hxx>
#include <oox/helper/attributelist.hxx>
#include <oox/helper/binaryinputstream.hxx>
#include <oox/token/namespaces.hxx>
@@ -278,6 +279,11 @@ void SheetDataContext::importRow( const AttributeList& rAttribs )
    aModel.mbThickTop     = rAttribs.getBool( XML_thickTop, false );
    aModel.mbThickBottom  = rAttribs.getBool( XML_thickBot, false );

    if (aModel.mfHeight > 0 && getFilter().isMSODocument())
    {
        aModel.mfHeight -= fmod(aModel.mfHeight, 0.75);  //round down to 0.75pt
    }

    // decode the column spans (space-separated list of colon-separated integer pairs)
    OUString aColSpansText = rAttribs.getString( XML_spans, OUString() );
    sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Col();