[Libreoffice-commits] core.git: Branch 'distro/vector/vector-7.0-10.0' - 57 commits - configure.ac cui/source dictionaries dtrans/source embeddedobj/CppunitTest_embeddedobj_msole.mk embeddedobj/Module_embeddedobj.mk embeddedobj/qa embeddedobj/source emfio/inc emfio/source extensions/source filter/qa filter/source framework/CppunitTest_framework_services.mk framework/Module_framework.mk framework/qa framework/source .gitreview helpcontent2 include/svx include/systools include/test include/unotools include/vcl offapi/com offapi/UnoApi_offapi.mk officecfg/registry readlicense_oo/license sal/CppunitTest_sal_retry_if_failed.mk sal/Module_sal.mk sal/qa scp2/source sc/source sfx2/source solenv/flatpak-manifest.in svtools/source svx/qa svx/source sw/CppunitTest_sw_uibase_uiview.mk sw/CppunitTest_sw_uibase_uno.mk sw/inc sw/Module_sw.mk sw/qa sw/source sw/uiconfig test/source translations unotools/source vcl/qa vcl/source vcl/unx xmloff/CppunitTest_xmloff_draw.mk xmloff/CppunitTest_xmloff_style.mk xmloff/M odule_xmloff.mk xmloff/qa xmloff/source

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Tue Jun 15 08:55:37 UTC 2021


Rebased ref, commits from common ancestor:
commit 7a5717cb8ad4c6b30d46ad86326fa4274bd84f12
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri May 28 16:02:50 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Mon May 31 10:04:24 2021 +0200

    sw XHTML / reqif export, RTF markup of images: write OLE1 presentation data
    
    With this, images are exported as PBrush OLE objects, to please some
    consumers (e.g. IBM Doors).
    
    (cherry picked from commit 5fbd20682f34c817359156889ecbc3ad8290d72c)
    
    Conflicts:
            sw/source/filter/html/htmlreqifreader.cxx
    
    Change-Id: I89805cd66709d96cbe71853d65671f76a3fc871f

diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 5074c5e54e0d..50e001c72890 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -152,11 +152,6 @@ OLE1Reader::OLE1Reader(SvStream& rStream)
     rStream.ReadUInt32(m_nNativeDataSize);
     rStream.SeekRel(m_nNativeDataSize);
 
-    if (!rStream.remainingSize())
-    {
-        return;
-    }
-
     rStream.ReadUInt32(nData); // OLEVersion for presentation data
     CPPUNIT_ASSERT(rStream.good());
     rStream.ReadUInt32(nData); // FormatID
@@ -1492,6 +1487,11 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifImageToOle)
     // Without the accompanying fix in place, this test would have failed, as aOle1 was empty.
     OLE1Reader aOle1Reader(aOle1);
     CPPUNIT_ASSERT(aOle1Reader.m_nNativeDataSize);
+
+    // Make sure that the presentation data byte array is not empty.
+    // Without the accompanying fix in place, this test would have failed, as aOle1 only contained
+    // the native data.
+    CPPUNIT_ASSERT(aOle1Reader.m_nPresentationDataSize);
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 70b0d697ea4a..8a6101fa93ee 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -555,18 +555,7 @@ bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvS
     aNativeData.Seek(0);
     aOle1.WriteStream(aNativeData);
 
-    // TODO Write Presentation.
-
-    // End objdata.
-    msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOle1.GetData()), aOle1.GetSize(),
-                                &rRtf);
-    rRtf.WriteCharPtr("}");
-    rRtf.WriteOString(SAL_NEWLINE_STRING);
-
-    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_RESULT);
-    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT);
-
-    // Prepare presendation data.
+    // Prepare presentation data.
     const sal_uInt8* pPresentationData = nullptr;
     sal_uInt64 nPresentationData = 0;
     SvMemoryStream aGraphicStream;
@@ -580,6 +569,43 @@ bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvS
         msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
     }
 
+    // Write Presentation.
+    // OLEVersion.
+    aOle1.WriteUInt32(0x00000501);
+    // FormatID: constant means the ClassName field is present.
+    aOle1.WriteUInt32(0x00000005);
+    // ClassName: null terminated pascal string.
+    OString aPresentationClassName("METAFILEPICT");
+    aOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
+    aOle1.WriteOString(aPresentationClassName);
+    aOle1.WriteChar(0);
+    const sal_uInt8* pBytes = nullptr;
+    sal_uInt64 nBytes = 0;
+    // Take presentation data for OLE1 from RTF.
+    pBytes = pPresentationData;
+    nBytes = nPresentationData;
+    // Width.
+    aOle1.WriteUInt32(nWidth);
+    // Height.
+    aOle1.WriteUInt32(nHeight * -1);
+    // PresentationDataSize: size of (reserved fields + pBytes).
+    aOle1.WriteUInt32(8 + nBytes);
+    // Reserved1-4.
+    aOle1.WriteUInt16(0x0008);
+    aOle1.WriteUInt16(0x31b1);
+    aOle1.WriteUInt16(0x1dd9);
+    aOle1.WriteUInt16(0x0000);
+    aOle1.WriteBytes(pBytes, nBytes);
+
+    // End objdata.
+    msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOle1.GetData()), aOle1.GetSize(),
+                                &rRtf);
+    rRtf.WriteCharPtr("}");
+    rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_RESULT);
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT);
+
     Size aMapped(rGraphic.GetPrefSize());
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICW);
     rRtf.WriteOString(OString::number(aMapped.Width()));
commit ffbf6916e2bd7de4daa862e11e52c9ff24929260
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Thu May 27 16:54:59 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri May 28 16:20:07 2021 +0200

    sw XHTML / reqif export, RTF markup of images: write objdata
    
    The native data is BMP, presentation data is not yet done.
    
    (cherry picked from commit ff1f80e025a7c235e3960affe1b9db844c89c214)
    
    Change-Id: I30ef9f0c3b4dc7801e600ac751c32179372d5e4e

diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 105d90d39b18..5074c5e54e0d 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -138,6 +138,7 @@ OLE1Reader::OLE1Reader(SvStream& rStream)
 {
     // Skip ObjectHeader, see [MS-OLEDS] 2.2.4.
     rStream.Seek(0);
+    CPPUNIT_ASSERT(rStream.remainingSize());
     sal_uInt32 nData;
     rStream.ReadUInt32(nData); // OLEVersion
     rStream.ReadUInt32(nData); // FormatID
@@ -151,6 +152,11 @@ OLE1Reader::OLE1Reader(SvStream& rStream)
     rStream.ReadUInt32(m_nNativeDataSize);
     rStream.SeekRel(m_nNativeDataSize);
 
+    if (!rStream.remainingSize())
+    {
+        return;
+    }
+
     rStream.ReadUInt32(nData); // OLEVersion for presentation data
     CPPUNIT_ASSERT(rStream.good());
     rStream.ReadUInt32(nData); // FormatID
@@ -1479,6 +1485,13 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifImageToOle)
     // - Actual  : 0
     // i.e. the image was exported as PNG, not as WMF (with a version).
     CPPUNIT_ASSERT_EQUAL(8, xReader->getWmetafile());
+
+    // Make sure that the native data byte array is not empty.
+    SvMemoryStream aOle1;
+    CPPUNIT_ASSERT(xReader->WriteObjectData(aOle1));
+    // Without the accompanying fix in place, this test would have failed, as aOle1 was empty.
+    OLE1Reader aOle1Reader(aOle1);
+    CPPUNIT_ASSERT(aOle1Reader.m_nNativeDataSize);
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx
index 184c911956a9..e5a3b482bd61 100644
--- a/sw/source/filter/html/htmlflywriter.cxx
+++ b/sw/source/filter/html/htmlflywriter.cxx
@@ -1881,7 +1881,7 @@ static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rF
         aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
 
         SvFileStream aOutStream(aFileName, StreamMode::WRITE);
-        if (!SwReqIfReader::WrapGraphicInRtf(aGraphic, pGrfNd->GetTwipSize(), aOutStream))
+        if (!SwReqIfReader::WrapGraphicInRtf(aGraphic, rFrameFormat, aOutStream))
             SAL_WARN("sw.html", "SwReqIfReader::WrapGraphicInRtf() failed");
 
         // Refer to this data.
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 16be43358972..70b0d697ea4a 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -496,12 +496,73 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
     return true;
 }
 
-bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf)
+bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvStream& rRtf)
 {
     // Start object.
     rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJEMB);
 
+    // Object size: as used in the document model (not pixel size)
+    Size aSize = rFormat.GetFrameSize().GetSize();
+    sal_uInt32 nWidth = aSize.getWidth();
+    sal_uInt32 nHeight = aSize.getHeight();
+    rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJW);
+    rRtf.WriteOString(OString::number(nWidth));
+    rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJH);
+    rRtf.WriteOString(OString::number(nHeight));
+    rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+    // Start objclass.
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJCLASS " ");
+    OString aClassName("PBrush");
+    rRtf.WriteOString(aClassName);
+    // End objclass.
+    rRtf.WriteCharPtr("}");
+    rRtf.WriteOString(SAL_NEWLINE_STRING);
+
+    // Start objdata.
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA " ");
+
+    SvMemoryStream aOle1;
+    // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
+    // OLEVersion.
+    aOle1.WriteUInt32(0x00000501);
+
+    // FormatID is EmbeddedObject.
+    aOle1.WriteUInt32(0x00000002);
+
+    // ClassName
+    aOle1.WriteUInt32(aClassName.getLength() + 1);
+    aOle1.WriteOString(aClassName);
+    // Null terminated pascal string.
+    aOle1.WriteChar(0);
+
+    // TopicName.
+    aOle1.WriteUInt32(0);
+
+    // ItemName.
+    aOle1.WriteUInt32(0);
+
+    // NativeDataSize
+    SvMemoryStream aNativeData;
+    if (GraphicConverter::Export(aNativeData, rGraphic, ConvertDataFormat::BMP) != ERRCODE_NONE)
+    {
+        SAL_WARN("sw.html", "WrapGraphicInRtf: bmp conversion failed");
+    }
+    aOle1.WriteUInt32(aNativeData.TellEnd());
+
+    // Write the actual native data.
+    aNativeData.Seek(0);
+    aOle1.WriteStream(aNativeData);
+
+    // TODO Write Presentation.
+
+    // End objdata.
+    msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOle1.GetData()), aOle1.GetSize(),
+                                &rRtf);
+    rRtf.WriteCharPtr("}");
+    rRtf.WriteOString(SAL_NEWLINE_STRING);
+
     rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_RESULT);
     rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT);
 
@@ -526,9 +587,9 @@ bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream&
     rRtf.WriteOString(OString::number(aMapped.Height()));
 
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
-    rRtf.WriteOString(OString::number(rLogicSize.Width()));
+    rRtf.WriteOString(OString::number(nWidth));
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
-    rRtf.WriteOString(OString::number(rLogicSize.Height()));
+    rRtf.WriteOString(OString::number(nHeight));
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
     rRtf.WriteOString(SAL_NEWLINE_STRING);
 
diff --git a/sw/source/filter/html/htmlreqifreader.hxx b/sw/source/filter/html/htmlreqifreader.hxx
index 5f757d0fbf1d..84169bb7c087 100644
--- a/sw/source/filter/html/htmlreqifreader.hxx
+++ b/sw/source/filter/html/htmlreqifreader.hxx
@@ -30,10 +30,8 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
 
 /**
  * Wraps an image in an RTF fragment.
- *
- * @param rLogicSize the size used in the document model (not pixel size)
  */
-bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf);
+bool WrapGraphicInRtf(const Graphic& rGraphic, const SwFrameFormat& rFormat, SvStream& rRtf);
 }
 
 #endif // INCLUDED_SW_SOURCE_FILTER_HTML_HTMLREQIFREADER_HXX
commit 0b4b0fcd873d62bec9e826c174d8334a1d7d3228
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed May 26 17:46:53 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri May 28 16:12:38 2021 +0200

    sw XHTML / reqif export, RTF markup of images: write WMF in \pict
    
    Some consumers (e.g. IBM Doors) can only consume the RTF snippet if it's
    an OLE object and can't deal with plain images.
    
    Wrap \pict inside \object and unconditionally use WMF as the RTF-level
    preview format. The actual \objdata is not yet written.
    
    (cherry picked from commit 0e459bb3eb840ac1cab14c070973fb3b79bc13d8)
    
    Conflicts:
            sw/qa/extras/htmlexport/htmlexport.cxx
    
    Change-Id: I203fcd8709b25a4dd543047bd804af8181df9940

diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index ad64b6404007..105d90d39b18 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -50,12 +50,14 @@ public:
     bool WriteObjectData(SvStream& rOLE);
     long GetObjw() const { return m_nObjw; }
     long GetObjh() const { return m_nObjh; }
+    int getWmetafile() const { return m_nWmetafile; }
 
 private:
     bool m_bInObjData = false;
     OStringBuffer m_aHex;
     long m_nObjw = 0;
     long m_nObjh = 0;
+    int m_nWmetafile = 0;
 };
 
 TestReqIfRtfReader::TestReqIfRtfReader(SvStream& rStream)
@@ -83,6 +85,9 @@ void TestReqIfRtfReader::NextToken(int nToken)
         case RTF_OBJH:
             m_nObjh = nTokenValue;
             break;
+        case RTF_WMETAFILE:
+            m_nWmetafile = nTokenValue;
+            break;
     }
 }
 
@@ -1450,6 +1455,32 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testBlockQuoteNoMargin)
                        "string");
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifImageToOle)
+{
+    // Given a document with an image:
+    loadURL("private:factory/swriter", nullptr);
+    OUString aImageURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "ole2.png";
+    uno::Sequence<beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("FileName", aImageURL),
+    };
+    dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
+
+    // When exporting to XHTML:
+    ExportToReqif();
+
+    // Then make sure we export that PNG as WMF in ReqIF mode:
+    OUString aRtfUrl = GetOlePath();
+    SvMemoryStream aRtf;
+    HtmlExportTest::wrapRtfFragment(aRtfUrl, aRtf);
+    tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf));
+    CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+    // Without the accompanying fix in place, this test would have failed:
+    // - Expected: 8
+    // - Actual  : 0
+    // i.e. the image was exported as PNG, not as WMF (with a version).
+    CPPUNIT_ASSERT_EQUAL(8, xReader->getWmetafile());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 47cf2341e1e5..16be43358972 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -498,42 +498,27 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
 
 bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf)
 {
+    // Start object.
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_OBJECT);
+    rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_OBJEMB);
+
+    rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_RESULT);
     rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT);
 
-    GfxLink aLink = rGraphic.GetGfxLink();
-    const sal_uInt8* pGraphicAry = aLink.GetData();
-    sal_uInt64 nSize = aLink.GetDataSize();
-    OString aBlipType;
-    bool bIsWMF = false;
-    switch (aLink.GetType())
+    // Prepare presendation data.
+    const sal_uInt8* pPresentationData = nullptr;
+    sal_uInt64 nPresentationData = 0;
+    SvMemoryStream aGraphicStream;
+    uno::Sequence<beans::PropertyValue> aFilterData
+        = { comphelper::makePropertyValue("EmbedEMF", false) };
+    FilterConfigItem aConfigItem(&aFilterData);
+    if (ConvertGraphicToWMF(rGraphic, aGraphicStream, &aConfigItem))
     {
-        case GfxLinkType::NativeBmp:
-            aBlipType = OOO_STRING_SVTOOLS_RTF_WBITMAP;
-            break;
-        case GfxLinkType::NativeJpg:
-            aBlipType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP;
-            break;
-        case GfxLinkType::NativePng:
-            aBlipType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
-            break;
-        case GfxLinkType::NativeWmf:
-            if (aLink.IsEMF())
-                aBlipType = OOO_STRING_SVTOOLS_RTF_EMFBLIP;
-            else
-            {
-                aBlipType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
-                bIsWMF = true;
-            }
-            break;
-        default:
-            break;
+        pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
+        nPresentationData = aGraphicStream.TellEnd();
+        msfilter::rtfutil::StripMetafileHeader(pPresentationData, nPresentationData);
     }
 
-    if (aBlipType.isEmpty())
-        return false;
-
-    rRtf.WriteOString(aBlipType);
-
     Size aMapped(rGraphic.GetPrefSize());
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICW);
     rRtf.WriteOString(OString::number(aMapped.Width()));
@@ -544,19 +529,23 @@ bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream&
     rRtf.WriteOString(OString::number(rLogicSize.Width()));
     rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
     rRtf.WriteOString(OString::number(rLogicSize.Height()));
+    rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
+    rRtf.WriteOString(SAL_NEWLINE_STRING);
 
-    if (bIsWMF)
+    if (pPresentationData)
     {
-        rRtf.WriteOString(OString::number(8));
-        msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
+        msfilter::rtfutil::WriteHex(pPresentationData, nPresentationData, &rRtf);
+        rRtf.WriteOString(SAL_NEWLINE_STRING);
     }
-    rRtf.WriteOString(SAL_NEWLINE_STRING);
-
-    msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &rRtf);
-    rRtf.WriteOString(SAL_NEWLINE_STRING);
 
     // End pict.
     rRtf.WriteCharPtr("}");
+
+    // End result.
+    rRtf.WriteCharPtr("}");
+
+    // End object.
+    rRtf.WriteCharPtr("}");
     return true;
 }
 }
commit f6a92e61558ee9134d20da5dce96e5e3b11702a8
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri May 14 09:49:17 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri May 14 17:43:15 2021 +0200

    sw XHTML export: fix <blockquote> with no-margin to not have character children
    
    This is building on top of commit
    f2eae41e9a85cd1df4190160b7453d3e12b8ccbd (sw XHTML export: <blockquote>
    can't have character children, 2019-11-07), which handled this in
    general, but only worked in case the Quotation style had a non-zero
    bottom margin.
    
    (cherry picked from commit 9837d3b51557955b2a2b7e66c2bdcdc706474704)
    
    Change-Id: I4008ee964d9a87a6cf409a63affce8e44d63b602

diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index b19ab0d655f2..ad64b6404007 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -1420,6 +1420,36 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListHeading)
     assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p", "list header");
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testBlockQuoteNoMargin)
+{
+    // Given a document with some text, para style set to Quotations, no bottom margin:
+    loadURL("private:factory/swriter", nullptr);
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+    xText->insertString(xText->getEnd(), "string", /*bAbsorb=*/false);
+    uno::Reference<beans::XPropertySet> xQuotations(
+        getStyles("ParagraphStyles")->getByName("Quotations"), uno::UNO_QUERY);
+    xQuotations->setPropertyValue("ParaBottomMargin", uno::makeAny(static_cast<sal_Int32>(0)));
+    uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY);
+    xParagraph->setPropertyValue("ParaStyleName", uno::makeAny(OUString("Quotations")));
+
+    // When exporting to XHTML:
+    ExportToReqif();
+
+    // Then make sure the output is valid xhtml:
+    SvMemoryStream aStream;
+    HtmlExportTest::wrapFragment(maTempFile, aStream);
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
+    CPPUNIT_ASSERT(pXmlDoc);
+    // Without the accompanying fix in place, this test would have failed:
+    // - expected: <blockquote><p>...</p></blockquote>
+    // - actual  : <blockquote>...</blockquote>
+    // i.e. <blockquote> is can't have character children, but it had.
+    assertXPathContent(pXmlDoc,
+                       "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:blockquote/reqif-xhtml:p",
+                       "string");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx
index e7997b56f5e5..46abffd664a9 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -755,6 +755,8 @@ static void OutHTML_SwFormat( Writer& rWrt, const SwFormat& rFormat,
     rHWrt.ChangeParaToken( nToken );
 
     bool bHasParSpace = bUseParSpace && rULSpace.GetLower() > 0;
+    // XHTML doesn't allow character children for <blockquote>.
+    bool bXhtmlBlockQuote = rHWrt.mbXHTML && rInfo.aToken == OOO_STRING_SVTOOLS_HTML_blockquote;
 
     // if necessary, start a new list item
     if( rInfo.bInNumberBulletList && bNumbered )
@@ -801,7 +803,7 @@ static void OutHTML_SwFormat( Writer& rWrt, const SwFormat& rFormat,
     // Also, XHTML does not allow character children in this context.
     OString aToken = rInfo.aToken;
     if( (!rHWrt.m_bCfgOutStyles || rHWrt.mbXHTML) && rInfo.bParaPossible && !bPara &&
-        (bHasParSpace || pAdjItem) )
+        (bHasParSpace || bXhtmlBlockQuote || pAdjItem) )
     {
         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), rHWrt.GetNamespace() + rInfo.aToken );
         aToken = OOO_STRING_SVTOOLS_HTML_parabreak;
@@ -849,7 +851,7 @@ static void OutHTML_SwFormat( Writer& rWrt, const SwFormat& rFormat,
         (!rInfo.bInNumberBulletList && !rHWrt.m_nDefListLvl) ||
         (rInfo.bInNumberBulletList && !bNumbered) ||
         (!rHWrt.m_bCfgOutStyles &&
-         (bHasParSpace || pAdjItem ||
+         (bHasParSpace || bXhtmlBlockQuote || pAdjItem ||
           (eLang != LANGUAGE_DONTKNOW && eLang != rHWrt.m_eLang))) ||
         nDir != rHWrt.m_nDirection ||
         rHWrt.m_bCfgOutStyles )
commit 7896f845faeb561d79ee43c9b5190a08a1a1dccf
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Thu May 13 11:45:37 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri May 14 14:12:06 2021 +0200

    sw XHTML export: fix handling of list labels
    
    This is building on top of commit
    119b6876c92e4cdae44583c4b1b1419d3533e3ee (sw XHTML export: properly
    write <li>...</li> around multiple paragraphs, 2020-05-21), but the
    use-case here is a numbering with list labels only.
    
    The first problem was that the list label had its <li> suppressed, but
    not its </li>.
    
    The other problem is that <ul> can only have <li> child elements, so at
    least fix the case where the list only has list labels, in which case
    even <ul> and </ul> should be omitted.
    
    (cherry picked from commit 013a4f1f5c9ea5fb511568c53a7e76d1b365a65d)
    
    Change-Id: Id38978a40d8618f483e3e9d499f75838d5b2adb0

diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 3746c3e7e786..b19ab0d655f2 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -1389,6 +1389,37 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifObjdataPresentationDataSize)
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(565994), aOle1Reader.m_nPresentationDataSize);
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListHeading)
+{
+    // Given a document with a list heading:
+    loadURL("private:factory/swriter", nullptr);
+    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->Insert("list header");
+    SwDoc* pDoc = pWrtShell->GetDoc();
+    sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+    SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+    SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode();
+    SwTextNode& rTextNode = *rNode.GetTextNode();
+    rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+    rTextNode.SetCountedInList(false);
+
+    // When exporting to ReqIF:
+    ExportToReqif();
+
+    // Then make sure the output is valid xhtml:
+    SvMemoryStream aStream;
+    HtmlExportTest::wrapFragment(maTempFile, aStream);
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
+    CPPUNIT_ASSERT(pDoc);
+
+    // Without the accompanying fix in place, this test would have failed:
+    // - expected: <div><p>...</p></div>
+    // - actual  : <div><ol><p>...</p></li></ol></div>
+    // because a </li> but no <li> is not well-formed and <ol> with a non-li children is invalid.
+    assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p", "list header");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlnumwriter.cxx b/sw/source/filter/html/htmlnumwriter.cxx
index ea3c949c3801..84ed431699d8 100644
--- a/sw/source/filter/html/htmlnumwriter.cxx
+++ b/sw/source/filter/html/htmlnumwriter.cxx
@@ -94,6 +94,39 @@ Writer& OutHTML_NumberBulletListStart( SwHTMLWriter& rWrt,
         return rWrt;
     }
 
+    if (rWrt.mbXHTML && !rInfo.IsNumbered())
+    {
+        // If the list only consists of non-numbered text nodes, then don't start the list.
+        bool bAtLeastOneNumbered = false;
+        sal_uLong nPos = rWrt.m_pCurrentPam->GetPoint()->nNode.GetIndex() + 1;
+        while (true)
+        {
+            const SwNode* pNode = rWrt.m_pDoc->GetNodes()[nPos];
+            if (!pNode->IsTextNode())
+            {
+                break;
+            }
+
+            const SwTextNode* pTextNode = pNode->GetTextNode();
+            if (!pTextNode->GetNumRule())
+            {
+                break;
+            }
+
+            if (pTextNode->IsNumbered())
+            {
+                bAtLeastOneNumbered = true;
+                break;
+            }
+            ++nPos;
+        }
+
+        if (!bAtLeastOneNumbered)
+        {
+            return rWrt;
+        }
+    }
+
     bool bStartValue = false;
     if( !bSameRule && rInfo.GetDepth() )
     {
@@ -283,7 +316,7 @@ Writer& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt,
 
     if (rWrt.mbXHTML)
     {
-        if (bListEnd || (!bListEnd && rNextInfo.IsNumbered()))
+        if ((bListEnd && rInfo.IsNumbered()) || (!bListEnd && rNextInfo.IsNumbered()))
         {
             HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(),
                                        rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li, false);
@@ -295,6 +328,39 @@ Writer& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt,
         return rWrt;
     }
 
+    if (rWrt.mbXHTML && !rInfo.IsNumbered())
+    {
+        // If the list only consisted of non-numbered text nodes, then don't end the list.
+        bool bAtLeastOneNumbered = false;
+        sal_uLong nPos = rWrt.m_pCurrentPam->GetPoint()->nNode.GetIndex() - 1;
+        while (true)
+        {
+            const SwNode* pNode = rWrt.m_pDoc->GetNodes()[nPos];
+            if (!pNode->IsTextNode())
+            {
+                break;
+            }
+
+            const SwTextNode* pTextNode = pNode->GetTextNode();
+            if (!pTextNode->GetNumRule())
+            {
+                break;
+            }
+
+            if (pTextNode->IsNumbered())
+            {
+                bAtLeastOneNumbered = true;
+                break;
+            }
+            --nPos;
+        }
+
+        if (!bAtLeastOneNumbered)
+        {
+            return rWrt;
+        }
+    }
+
     OSL_ENSURE( rWrt.m_nLastParaToken == HtmlTokenId::NONE,
                 "<PRE> was not closed before </OL>." );
     sal_uInt16 nNextDepth =
commit 082bef47ce0be2e51fefb7cf71300c13b2a29eae
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri May 7 12:31:24 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Wed May 12 14:04:53 2021 +0200

    embeddedobj: handle getting the visible area on a thread
    
    The Windows OLE2 implementation of the embedded object interface assumes
    that the same thread is used for loading and saving the embedded
    objects.
    
    This means that in case the main thread is used for loading (e.g. from
    remote UNO, but with OnMainThead=true), but a
    thread is used for storing (without an explicit OnMainThead=true), then
    the underlying win32 API call failed and we returned a fixed size in
    EmbeddedObjectRef::GetSize().
    
    Fix the problem by explicitly checking for RPC_E_WRONG_THREAD and adding
    error handling for that case.
    
    (cherry picked from commit d5cd62164d32273a25913c93aa04be9f7f3a4073)
    
    Change-Id: Icf1e7722d33a809fa671d1505b2a0155af040c71

diff --git a/embeddedobj/CppunitTest_embeddedobj_msole.mk b/embeddedobj/CppunitTest_embeddedobj_msole.mk
new file mode 100644
index 000000000000..2ffb7f64d829
--- /dev/null
+++ b/embeddedobj/CppunitTest_embeddedobj_msole.mk
@@ -0,0 +1,48 @@
+# -*- 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,embeddedobj_msole))
+
+$(eval $(call gb_CppunitTest_use_externals,embeddedobj_msole,\
+	boost_headers \
+	libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,embeddedobj_msole, \
+    embeddedobj/qa/cppunit/msole \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,embeddedobj_msole, \
+    comphelper \
+    cppu \
+    embobj \
+    sal \
+    test \
+    unotest \
+    utl \
+    vcl \
+    tl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,embeddedobj_msole))
+
+$(eval $(call gb_CppunitTest_use_ure,embeddedobj_msole))
+$(eval $(call gb_CppunitTest_use_vcl,embeddedobj_msole))
+
+$(eval $(call gb_CppunitTest_use_rdb,embeddedobj_msole,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,embeddedobj_msole,\
+	officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,embeddedobj_msole))
+
+# vim: set noet sw=4 ts=4:
diff --git a/embeddedobj/Module_embeddedobj.mk b/embeddedobj/Module_embeddedobj.mk
index 394112a13b7d..659b406b9ea9 100644
--- a/embeddedobj/Module_embeddedobj.mk
+++ b/embeddedobj/Module_embeddedobj.mk
@@ -21,4 +21,10 @@ $(eval $(call gb_Module_add_slowcheck_targets,embeddedobj,\
 ))
 endif
 
+ifeq ($(OS),WNT)
+$(eval $(call gb_Module_add_slowcheck_targets,embeddedobj,\
+    CppunitTest_embeddedobj_msole \
+))
+endif
+
 # vim: set noet sw=4 ts=4:
diff --git a/embeddedobj/qa/cppunit/data/ole2.ole b/embeddedobj/qa/cppunit/data/ole2.ole
new file mode 100644
index 000000000000..c0013db40113
--- /dev/null
+++ b/embeddedobj/qa/cppunit/data/ole2.ole
@@ -0,0 +1,19 @@
+{\object\objemb\objw240\objh240{\*\objclass PBrush}{\*\objdata 01050000020000000700000050427275736800000000000000000040030000
+424d36030000000000003600000028000000100000001000000001001800000000000003000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000001050000050000000d0000004d45544146494c455049435400a701000059feffffe40000000800a701a7010000
+0100090000036e00000000004500000000000400000003010800050000000b0200000000050000000c0211001100030000001e000400000007010400040000000701040045000000410b2000cc00100010000000000010001000000000002800000010000000100000000100010000000000000000000000000000000000
+000000000000000000000000ffffff00ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101040000002701ffff030000000000}{\result {\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid793696 
+{\*\shppict{\pict{\*\picprop\shplid1027{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn fLockAspectRatio}{\sv 1}}{\sp{\sn pictureGray}{\sv 0}}
+{\sp{\sn pictureBiLevel}{\sv 0}}{\sp{\sn pictureActive}{\sv 0}}{\sp{\sn fRecolorFillAsPicture}{\sv 0}}{\sp{\sn fUseShapeAnchor}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fHitTestFill}{\sv 1}}
+{\sp{\sn fillShape}{\sv 1}}{\sp{\sn fillUseRect}{\sv 0}}{\sp{\sn fNoFillHitTest}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn fPreferRelativeResize}{\sv 1}}{\sp{\sn fReallyHidden}{\sv 0}}
+{\sp{\sn fScriptAnchor}{\sv 0}}{\sp{\sn fFakeMaster}{\sv 0}}{\sp{\sn fCameFromImgDummy}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}}\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0
+\picw423\pich423\picwgoal240\pichgoal240\pngblip\bliptag602933164{\*\blipuid 23f007ac3ac2aed53753eaea27c13e03}89504e470d0a1a0a0000000d494844520000001000000010080200000090916836000000017352474200aece1ce9000000097048597300000ec700000ec70138
+922f760000001f49444154384f63fcffff3f0329808914c520b5a31a8809b1d1501a1ca10400556d031d6ec895ac0000000049454e44ae426082}}{\nonshppict{\pict\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0
+\picw423\pich423\picwgoal240\pichgoal240\wmetafile8\bliptag602933164\blipupi96{\*\blipuid 23f007ac3ac2aed53753eaea27c13e03}0100090000036e00000000004500000000000400000003010800050000000b0200000000050000000c0211001100030000001e00040000000701040004000000
+0701040045000000410b2000cc001000100000000000100010000000000028000000100000001000000001000100000000000000000000000000000000000000
+00000000000000000000ffffff00ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101ffff0101040000002701ffff030000000000}}}}}
diff --git a/embeddedobj/qa/cppunit/data/ole2.png b/embeddedobj/qa/cppunit/data/ole2.png
new file mode 100644
index 000000000000..fdad35484e7c
Binary files /dev/null and b/embeddedobj/qa/cppunit/data/ole2.png differ
diff --git a/embeddedobj/qa/cppunit/data/reqif-ole2.xhtml b/embeddedobj/qa/cppunit/data/reqif-ole2.xhtml
new file mode 100644
index 000000000000..716ecd1bda63
--- /dev/null
+++ b/embeddedobj/qa/cppunit/data/reqif-ole2.xhtml
@@ -0,0 +1,5 @@
+<reqif-xhtml:div>
+	<reqif-xhtml:object data="ole2.ole" type="text/rtf">
+		<reqif-xhtml:object data="ole2.png" type="image/png">OLE Object</reqif-xhtml:object>
+	</reqif-xhtml:object>
+</reqif-xhtml:div>
diff --git a/embeddedobj/qa/cppunit/msole.cxx b/embeddedobj/qa/cppunit/msole.cxx
new file mode 100644
index 000000000000..6cd768ead146
--- /dev/null
+++ b/embeddedobj/qa/cppunit/msole.cxx
@@ -0,0 +1,142 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <test/xmltesttools.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
+
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <unotools/tempfile.hxx>
+#include <osl/thread.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <vcl/outdev.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Covers embeddedobj/source/msole/ fixes.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+private:
+    uno::Reference<lang::XComponent> mxComponent;
+
+public:
+    void setUp() override;
+    void tearDown() override;
+    uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+    void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
+};
+}
+
+void Test::setUp()
+{
+    test::BootstrapFixture::setUp();
+
+    mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+    if (mxComponent.is())
+        mxComponent->dispose();
+
+    test::BootstrapFixture::tearDown();
+}
+
+void Test::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
+{
+    XmlTestTools::registerODFNamespaces(pXmlXpathCtx);
+}
+
+class OdtExportThread : public osl::Thread
+{
+    uno::Reference<lang::XComponent> mxComponent;
+    OUString maURL;
+
+public:
+    OdtExportThread(const uno::Reference<lang::XComponent>& xComponent, const OUString& rURL);
+    virtual void SAL_CALL run() override;
+};
+
+OdtExportThread::OdtExportThread(const uno::Reference<lang::XComponent>& xComponent,
+                                 const OUString& rURL)
+    : mxComponent(xComponent)
+    , maURL(rURL)
+{
+}
+
+void OdtExportThread::run()
+{
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    uno::Sequence<beans::PropertyValue> aStoreProperties = {
+        comphelper::makePropertyValue("FilterName", OUString("writer8")),
+    };
+    xStorable->storeToURL(maURL, aStoreProperties);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSaveOnThread)
+{
+    // Given an embedded object which hosts mspaint data:
+    if (Application::GetDefaultDevice()->GetDPIX() != 96)
+    {
+        return;
+    }
+
+    DBG_TESTSOLARMUTEX();
+    OUString aURL = m_directories.getURLFromSrc(u"embeddedobj/qa/cppunit/data/reqif-ole2.xhtml");
+    uno::Sequence<beans::PropertyValue> aLoadProperties = {
+        comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+        comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+    };
+    getComponent().set(loadFromDesktop(aURL, "com.sun.star.text.TextDocument", aLoadProperties));
+
+    // When saving that document on a thread:
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    OdtExportThread aThread(getComponent(), aTempFile.GetURL());
+    aThread.create();
+    {
+        SolarMutexReleaser r;
+        while (aThread.isRunning())
+        {
+            SolarMutexGuard g;
+            Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
+        }
+    }
+
+    // Then make sure its visible area's width is correct.
+    uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+        = packages::zip::ZipFileAccess::createWithURL(mxComponentContext, aTempFile.GetURL());
+    uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("content.xml"),
+                                                  uno::UNO_QUERY);
+    std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // 16 pixels, assuming 96 DPI.
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 0.1665in
+    // - Actual  : 1.9685in
+    // i.e. we wrote a hardcoded 5cm width, not the real one.
+    assertXPath(pXmlDoc, "//style:graphic-properties", "visible-area-width", "0.1665in");
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olecomponent.cxx b/embeddedobj/source/msole/olecomponent.cxx
index 8fc8a3e0559f..514a24d86f06 100644
--- a/embeddedobj/source/msole/olecomponent.cxx
+++ b/embeddedobj/source/msole/olecomponent.cxx
@@ -38,6 +38,7 @@
 #include <osl/file.hxx>
 #include <rtl/ref.hxx>
 #include <o3tl/char16_t2wchar_t.hxx>
+#include <vcl/threadex.hxx>
 
 #include "graphconvert.hxx"
 #include "olecomponent.hxx"
@@ -1132,6 +1133,18 @@ awt::Size OleComponent::GetExtent( sal_Int64 nAspect )
             aFormat.dwAspect = nMSAspect;
 
             hr = pDataObject->GetData( &aFormat, &aMedium );
+
+            if (hr == RPC_E_WRONG_THREAD)
+            {
+                // Assume that the OLE object was loaded on the main thread.
+                vcl::solarthread::syncExecute([this, &hr, &pDataObject, &aFormat, &aMedium]() {
+                    // Make sure that the current state is embed::EmbedStates::RUNNING.
+                    RunObject();
+                    // Now try again on the correct thread.
+                    hr = pDataObject->GetData(&aFormat, &aMedium);
+                });
+            }
+
             if ( SUCCEEDED( hr ) && aMedium.tymed == TYMED_MFPICT ) // Win Metafile
             {
                 METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( aMedium.hMetaFilePict ));
@@ -1180,6 +1193,10 @@ awt::Size OleComponent::GetExtent( sal_Int64 nAspect )
                         OSL_FAIL( "Unexpected size is provided!" );
                 }
             }
+            else if (!SUCCEEDED(hr))
+            {
+                SAL_WARN("embeddedobj.ole", " OleComponent::GetExtent: GetData() failed");
+            }
             // i113605, to release storage medium
             if ( SUCCEEDED( hr ) )
                 ::ReleaseStgMedium(&aMedium);
@@ -1212,6 +1229,7 @@ awt::Size OleComponent::GetCachedExtent( sal_Int64 nAspect )
         //else
         //  throw io::IOException(); // TODO
 
+        SAL_WARN("embeddedobj.ole", " OleComponent::GetCachedExtent: GetExtent() failed");
         throw lang::IllegalArgumentException();
     }
 
@@ -1228,7 +1246,10 @@ awt::Size OleComponent::GetRecommendedExtent( sal_Int64 nAspect )
     SIZEL aSize;
     HRESULT hr = m_pNativeImpl->m_pOleObject->GetExtent( nMSAspect, &aSize );
     if ( FAILED( hr ) )
+    {
+        SAL_WARN("embeddedobj.ole", " OleComponent::GetRecommendedExtent: GetExtent() failed");
         throw lang::IllegalArgumentException();
+    }
 
     return awt::Size( aSize.cx, aSize.cy );
 }
diff --git a/embeddedobj/source/msole/olevisual.cxx b/embeddedobj/source/msole/olevisual.cxx
index 21a53e2a5306..55efee353bfa 100644
--- a/embeddedobj/source/msole/olevisual.cxx
+++ b/embeddedobj/source/msole/olevisual.cxx
@@ -225,8 +225,9 @@ awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect )
                     aSize = m_pOleComponent->GetExtent( nAspect ); // will throw an exception in case of failure
                     bSuccess = true;
                 }
-                catch( const uno::Exception& )
+                catch( const uno::Exception& rException )
                 {
+                    SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetExtent() failed: " << rException);
                 }
 
                 if (bBackToLoaded)
@@ -249,8 +250,9 @@ awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect )
                         aSize = m_pOleComponent->GetCachedExtent( nAspect ); // will throw an exception in case of failure
                         bSuccess = true;
                     }
-                    catch( const uno::Exception& )
+                    catch( const uno::Exception& rException )
                     {
+                        SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetCachedExtent() failed: " << rException);
                     }
                 }
 
@@ -262,8 +264,9 @@ awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect )
                         aSize = m_pOleComponent->GetRecommendedExtent( nAspect ); // will throw an exception in case of failure
                         bSuccess = true;
                     }
-                    catch( const uno::Exception& )
+                    catch( const uno::Exception& rException )
                     {
+                        SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetRecommendedExtent() failed: " << rException);
                     }
                 }
 
diff --git a/include/test/xmltesttools.hxx b/include/test/xmltesttools.hxx
index a2c08d7dc0e8..c2ba98885868 100644
--- a/include/test/xmltesttools.hxx
+++ b/include/test/xmltesttools.hxx
@@ -96,6 +96,7 @@ protected:
      */
     void          assertXPathNoAttribute(const xmlDocUniquePtr& pXmlDoc, const OString& rXPath, const OString& rAttribute);
 
+    static void registerODFNamespaces(xmlXPathContextPtr& pXmlXpathCtx);
 };
 
 #endif
diff --git a/svtools/source/misc/embedhlp.cxx b/svtools/source/misc/embedhlp.cxx
index 2319485a65bd..f8dcf1356621 100644
--- a/svtools/source/misc/embedhlp.cxx
+++ b/svtools/source/misc/embedhlp.cxx
@@ -486,6 +486,7 @@ Size EmbeddedObjectRef::GetSize( MapMode const * pTargetMapMode ) const
             }
             catch(const embed::NoVisualAreaSizeException&)
             {
+                SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: no visual area size");
             }
             catch (const uno::Exception&)
             {
@@ -504,6 +505,7 @@ Size EmbeddedObjectRef::GetSize( MapMode const * pTargetMapMode ) const
 
         if ( !aSize.Height && !aSize.Width )
         {
+            SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: empty size, defaulting to 5x5cm");
             aSize.Width = 5000;
             aSize.Height = 5000;
         }
diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx
index 27833af1e90d..13fd45203d0e 100644
--- a/test/source/xmltesttools.cxx
+++ b/test/source/xmltesttools.cxx
@@ -278,4 +278,78 @@ int XmlTestTools::getXPathPosition(const xmlDocUniquePtr& pXmlDoc, const OString
     return nRet;
 }
 
+void XmlTestTools::registerODFNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
+{
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("office"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("style"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:style:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("text"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:text:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("table"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:table:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("draw"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("fo"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("config"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:config:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xlink"), BAD_CAST("http://www.w3.org/1999/xlink"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dc"), BAD_CAST("http://purl.org/dc/elements/1.1/"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("meta"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:meta:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("number"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("svg"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("chart"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:chart:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dr3d"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("math"),
+                       BAD_CAST("http://www.w3.org/1998/Math/MathML"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("form"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:form:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("script"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:script:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ooo"),
+                       BAD_CAST("http://openoffice.org/2004/office"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ooow"),
+                       BAD_CAST("http://openoffice.org/2004/writer"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("oooc"), BAD_CAST("http://openoffice.org/2004/calc"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dom"),
+                       BAD_CAST("http://www.w3.org/2001/xml-events"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xforms"), BAD_CAST("http://www.w3.org/2002/xforms"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xsd"), BAD_CAST("http://www.w3.org/2001/XMLSchema"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xsi"),
+                       BAD_CAST("http://www.w3.org/2001/XMLSchema-instance"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("rpt"),
+                       BAD_CAST("http://openoffice.org/2005/report"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("of"),
+                       BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:of:1.2"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xhtml"), BAD_CAST("http://www.w3.org/1999/xhtml"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("grddl"),
+                       BAD_CAST("http://www.w3.org/2003/g/data-view#"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("officeooo"),
+                       BAD_CAST("http://openoffice.org/2009/office"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("tableooo"),
+                       BAD_CAST("http://openoffice.org/2009/table"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("drawooo"),
+                       BAD_CAST("http://openoffice.org/2010/draw"));
+    xmlXPathRegisterNs(
+        pXmlXpathCtx, BAD_CAST("calcext"),
+        BAD_CAST("urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"));
+    xmlXPathRegisterNs(
+        pXmlXpathCtx, BAD_CAST("loext"),
+        BAD_CAST("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"));
+    xmlXPathRegisterNs(
+        pXmlXpathCtx, BAD_CAST("field"),
+        BAD_CAST("urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"));
+    xmlXPathRegisterNs(
+        pXmlXpathCtx, BAD_CAST("formx"),
+        BAD_CAST("urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("css3t"),
+                       BAD_CAST("http://www.w3.org/TR/css3-text/"));
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit d3ab4fc0ba8e62d4f25caf5d759eb54d3f7ecd94
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Thu Apr 29 17:21:54 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Apr 30 17:37:22 2021 +0200

    sw html/reqif export: fix size of presentation data for "real" OLE2 embedding
    
    InsertOLE1Header() can either take its OLE1 presentation data (preview)
    from OLE2 or from RTF (SwOLENode). The presentation data size we wrote
    was incorrect in the OLE2 case case: nPresentationData is the RTF size,
    nBytes is the actual buffer size.
    
    In practice this made the embedded object non-editable in Word (when
    trying to edit the RTF fragment).
    
    This went wrong in commit 0d027abbc5609b096d2a954e77aa7354a55928ab (sw
    reqif-xhtml export, embedded objects: take OLE1 pres data from rtf if
    needed, 2020-09-02).
    
    (cherry picked from commit 58607e1c410ee89ddfd47dcd128abfa00e0ac839)
    
    Change-Id: I89019202c9a8b40c1b9a21f611f1190fd50073a5

diff --git a/sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odt b/sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odt
new file mode 100644
index 000000000000..231a7c572a3a
Binary files /dev/null and b/sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odt differ
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 08a21b6b7dd3..3746c3e7e786 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -255,6 +255,8 @@ public:
     OUString GetOlePath();
     /// Parse the ole1 data out of an RTF fragment URL.
     void ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1);
+    /// Export using the C++ HTML export filter, with xhtmlns=reqif-xhtml.
+    void ExportToReqif();
 };
 
 OUString SwHtmlDomExportTest::GetOlePath()
@@ -283,6 +285,16 @@ void SwHtmlDomExportTest::ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryS
     CPPUNIT_ASSERT(rOle1.Tell());
 }
 
+void SwHtmlDomExportTest::ExportToReqif()
+{
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    uno::Sequence<beans::PropertyValue> aStoreProperties = {
+        comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+        comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+    };
+    xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+}
+
 char const DATA_DIRECTORY[] = "/sw/qa/extras/htmlexport/data/";
 
 DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo81276, "fdo81276.html")
@@ -1354,6 +1366,29 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifAscharObjsize)
     CPPUNIT_ASSERT_EQUAL(static_cast<long>(4116), xReader->GetObjh());
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifObjdataPresentationDataSize)
+{
+    // Given a document with an OLE2 embedded object, containing a preview:
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reqif-objdata-presentationdatasize.odt";
+    mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", {});
+
+    // When exporting to ReqIF:
+    ExportToReqif();
+
+    // Then make sure that the PresentationDataSize in the RTF's objdata blob is correct:
+    OUString aRtfUrl = GetOlePath();
+    SvMemoryStream aOle1;
+    ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+    OLE1Reader aOle1Reader(aOle1);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 565994
+    // - Actual  : 330240 (Linux)
+    // - Actual  : 566034 (Windows, when Word is installed)
+    // because PresentationData was taken from the OLE2 stream but its size was taken from RTF.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(565994), aOle1Reader.m_nPresentationDataSize);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index a59f56ee40ee..47cf2341e1e5 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -341,8 +341,8 @@ OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, s
     rOle1.WriteUInt32(nWidth);
     // Height.
     rOle1.WriteUInt32(nHeight * -1);
-    // PresentationDataSize
-    rOle1.WriteUInt32(8 + nPresentationData);
+    // PresentationDataSize: size of (reserved fields + pBytes).
+    rOle1.WriteUInt32(8 + nBytes);
     // Reserved1-4.
     rOle1.WriteUInt16(0x0008);
     rOle1.WriteUInt16(0x31b1);
commit 6544a10541fce546034a5411cd6333c2d94fe965
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Apr 28 14:43:09 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Apr 29 09:37:39 2021 +0200

    framework: allow loading a component on the main thread, using XDesktop
    
    This is similar to commit 2dc3a6c273cb82506842864481d78df7294debbf
    (framework: allow loading a component on the main thread, 2018-12-19),
    but that focused on the special case when loading happens via XFrame.
    
    The more frequently used XDesktop way now supports the same flag,
    allowing correctly loading "real" OLE objects on Windows.
    
    (cherry picked from commit 6002014ce0a5c9cea22c14b2437b7a508b2c72cb)
    
    Change-Id: I059ea143c91894508d8264084094eefc2bff24e8

diff --git a/framework/source/services/desktop.cxx b/framework/source/services/desktop.cxx
index 998f0af29a62..91611d4eaa45 100644
--- a/framework/source/services/desktop.cxx
+++ b/framework/source/services/desktop.cxx
@@ -57,6 +57,7 @@
 #include <vcl/scheduler.hxx>
 #include <sal/log.hxx>
 #include <vcl/errcode.hxx>
+#include <vcl/threadex.hxx>
 #include <unotools/configmgr.hxx>
 
 namespace framework{
@@ -623,7 +624,25 @@ css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::loadComponentFrom
 
     css::uno::Reference< css::frame::XComponentLoader > xThis(static_cast< css::frame::XComponentLoader* >(this), css::uno::UNO_QUERY);
 
-    return LoadEnv::loadComponentFromURL(xThis, m_xContext, sURL, sTargetFrameName, nSearchFlags, lArguments);
+    utl::MediaDescriptor aDescriptor(lArguments);
+    bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault("OnMainThread", false);
+
+    if (bOnMainThread)
+    {
+        // Make sure that we own the solar mutex, otherwise later
+        // vcl::SolarThreadExecutor::execute() will release the solar mutex, even if it's owned by
+        // another thread, leading to an std::abort() at the end.
+        SolarMutexGuard g;
+
+        return vcl::solarthread::syncExecute(std::bind(&LoadEnv::loadComponentFromURL, xThis,
+                                                       m_xContext, sURL, sTargetFrameName,
+                                                       nSearchFlags, lArguments));
+    }
+    else
+    {
+        return LoadEnv::loadComponentFromURL(xThis, m_xContext, sURL, sTargetFrameName,
+                                             nSearchFlags, lArguments);
+    }
 }
 
 /*-************************************************************************************************************
commit d377f4d9c0449a4acece1bddedb3c081f5e1d0ed
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri Apr 23 12:19:49 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Apr 23 17:57:40 2021 +0200

    embeddedobj: fix lost native data when updating it via OLE fails, take 2
    
    How to reproduce the problem:
    
    1) Create an ODT file which has an OLE object, where the native data is
    an OLE2 container, containing a Package stream, containing a DOCX file
    
    2) Install some external application on Windows which registers itself
    as a handler for the DOCX CSLID [ this is where writing a testcase for
    this bug is challenging ].
    
    3) Open this document via Java, using URP. Load the document with
    Hidden=true and OnMainThread=true.
    
    4) Save the document using XStorable.store().
    
    Expected result: the native data is there.
    
    Actual result: the native data is sometimes missing (0 bytes).
    
    The root cause is that GetUserClassID() Win32 API call in
    OleComponent::StoreOwnTmpIfNecessary() fails in some cases, and
    re-trying a few times after a small sleep doesn't help.
    
    Handle this error better by doing what
    OleEmbeddedObject::SwitchOwnPersistence(XStorage, OUString) already
    does: discard the old native data only if we have non-empty new native
    data.
    
    A result of the above was that an export to reqif-xhtml (sw HTML export
    with FilterOptions set to xhtmlns=reqif-xhtml) wrote empty \objdata.
    
    (cherry picked from commit 02298dbdfde3432ef757fdc1a28f7e6341254179)
    
    Change-Id: I59611601cf09597e9f7727db5bd6d7426fe17b75

diff --git a/embeddedobj/source/msole/olepersist.cxx b/embeddedobj/source/msole/olepersist.cxx
index 57699246a723..6dc751e5c44c 100644
--- a/embeddedobj/source/msole/olepersist.cxx
+++ b/embeddedobj/source/msole/olepersist.cxx
@@ -742,6 +742,22 @@ void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStor
         return;
     }
 
+    uno::Reference<io::XSeekable> xNewSeekable(xNewObjectStream, uno::UNO_QUERY);
+    if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
+    {
+        uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
+        if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
+        {
+            SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence(stream version): "
+                                        "empty new stream, reusing old one");
+            uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
+            uno::Reference<io::XOutputStream> xOutput = xNewObjectStream->getOutputStream();
+            xOldSeekable->seek(0);
+            comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
+            xNewSeekable->seek(0);
+        }
+    }
+
     try {
         uno::Reference< lang::XComponent > xComponent( m_xObjectStream, uno::UNO_QUERY );
         OSL_ENSURE( !m_xObjectStream.is() || xComponent.is(), "Wrong stream implementation!" );
commit e564e66553d2d6304f5e0a5c8510070ac6262ec1
Author:     Julien Nabet <serval2412 at yahoo.fr>
AuthorDate: Wed Aug 26 11:00:16 2020 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Apr 22 17:34:34 2021 +0200

    tdf#136133: AppendInfoBar can return null
    
    2 cases:
    1) When set Donate property to false value in /org.openoffice.Office.UI.Infobar/Enabled
     and LastTimeDonateShow with 1 in /org.openoffice.Setup/Product (Expert Configuration)
    See https://bugs.documentfoundation.org/attachment.cgi?id=164702
    
    2) GetInvolved = false and LastTimeGetInvolved = 1
    See https://bugs.documentfoundation.org/attachment.cgi?id=164703
    
    (cherry picked from commit be4fcac736fccce8ee7d4550a860b0127e7601bb)
    
    Change-Id: I2da22616fb6f3fb4e42bf6b5e5c29cc094dc2fd6

diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index 3a0572058932..39b1c911778d 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -1331,11 +1331,14 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
 
                     VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("getinvolved", "", SfxResId(STR_GET_INVOLVED_TEXT), InfobarType::INFO);
 
-                    VclPtrInstance<PushButton> xGetInvolvedButton(&GetWindow());
-                    xGetInvolvedButton->SetText(SfxResId(STR_GET_INVOLVED_BUTTON));
-                    xGetInvolvedButton->SetSizePixel(xGetInvolvedButton->GetOptimalSize());
-                    xGetInvolvedButton->SetClickHdl(LINK(this, SfxViewFrame, GetInvolvedHandler));
-                    pInfoBar->addButton(xGetInvolvedButton);
+                    if (pInfoBar)
+                    {
+                        VclPtrInstance<PushButton> xGetInvolvedButton(&GetWindow());
+                        xGetInvolvedButton->SetText(SfxResId(STR_GET_INVOLVED_BUTTON));
+                        xGetInvolvedButton->SetSizePixel(xGetInvolvedButton->GetOptimalSize());
+                        xGetInvolvedButton->SetClickHdl(LINK(this, SfxViewFrame, GetInvolvedHandler));
+                        pInfoBar->addButton(xGetInvolvedButton);
+                    }
                 }
 
                 if (bUpdateLastTimeGetInvolvedShown
@@ -1357,12 +1360,14 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
                     bUpdateLastTimeDonateShown = true;
 
                     VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("donate", "", SfxResId(STR_DONATE_TEXT), InfobarType::INFO);
-
-                    VclPtrInstance<PushButton> xDonateButton(&GetWindow());
-                    xDonateButton->SetText(SfxResId(STR_DONATE_BUTTON));
-                    xDonateButton->SetSizePixel(xDonateButton->GetOptimalSize());
-                    xDonateButton->SetClickHdl(LINK(this, SfxViewFrame, DonationHandler));
-                    pInfoBar->addButton(xDonateButton);
+                    if (pInfoBar)
+                    {
+                        VclPtrInstance<PushButton> xDonateButton(&GetWindow());
+                        xDonateButton->SetText(SfxResId(STR_DONATE_BUTTON));
+                        xDonateButton->SetSizePixel(xDonateButton->GetOptimalSize());
+                        xDonateButton->SetClickHdl(LINK(this, SfxViewFrame, DonationHandler));
+                        pInfoBar->addButton(xDonateButton);
+                    }
                 }
 
                 if (bUpdateLastTimeDonateShown
commit a4b426d4cd246fc9a5faf2a89cad0ebdc0a18847
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri Apr 16 10:14:05 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Apr 16 17:16:08 2021 +0200

    sw html/reqif export: fix size of embedded object
    
    We used to write the size of the underlying OLE object, which may or may
    not match the user-configured size. The PNG preview was correct, which
    works with the size from the SwFormatFlyCnt ("as-char formatting"). Do
    the same when writing the "object size" (i.e. \objw and \objh in the RTF
    snippet).
    
    (cherry picked from commit 21cd910d144b14ead358bccd1146650806346eb5)
    
    Change-Id: I7e240c1e115846c17b0945376b0de02d19769100

diff --git a/sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odt b/sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odt
new file mode 100644
index 000000000000..6028b54a4190
Binary files /dev/null and b/sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odt differ
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 5e1264fcadb4..08a21b6b7dd3 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -48,10 +48,14 @@ public:
     TestReqIfRtfReader(SvStream& rStream);
     void NextToken(int nToken) override;
     bool WriteObjectData(SvStream& rOLE);
+    long GetObjw() const { return m_nObjw; }
+    long GetObjh() const { return m_nObjh; }
 
 private:
     bool m_bInObjData = false;
     OStringBuffer m_aHex;
+    long m_nObjw = 0;
+    long m_nObjh = 0;
 };
 
 TestReqIfRtfReader::TestReqIfRtfReader(SvStream& rStream)
@@ -73,6 +77,12 @@ void TestReqIfRtfReader::NextToken(int nToken)
         case RTF_OBJDATA:
             m_bInObjData = true;
             break;
+        case RTF_OBJW:
+            m_nObjw = nTokenValue;
+            break;
+        case RTF_OBJH:
+            m_nObjh = nTokenValue;
+            break;
     }
 }
 
@@ -1316,6 +1326,34 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PresDataWmfOnly)
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(135660), aOle1Reader.m_nPresentationDataSize);
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifAscharObjsize)
+{
+    // Given a document with an as-char anchored embedded object:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reqif-aschar-objsize.odt";
+    mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", {});
+
+    // When exporting to reqif-xhtml:
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    uno::Sequence<beans::PropertyValue> aStoreProperties = {
+        comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+        comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+    };
+    xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+    // Then make sure that the RTF snippet has the correct aspect ratio:
+    OUString aRtfUrl = GetOlePath();
+    SvMemoryStream aRtf;
+    HtmlExportTest::wrapRtfFragment(aRtfUrl, aRtf);
+    tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf));
+    CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 7344
+    // - Actual  : 2836
+    // i.e. the aspect ratio was 1:1, while the PNG aspect ratio was correctly not 1:1.
+    CPPUNIT_ASSERT_EQUAL(static_cast<long>(7344), xReader->GetObjw());
+    CPPUNIT_ASSERT_EQUAL(static_cast<long>(4116), xReader->GetObjh());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx
index 525b3b0ea175..5fd6b3e54d7b 100644
--- a/sw/source/filter/html/htmlplug.cxx
+++ b/sw/source/filter/html/htmlplug.cxx
@@ -1549,7 +1549,7 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame
             if (xStream.is())
             {
                 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xStream));
-                if (SwReqIfReader::WrapOleInRtf(*pStream, aOutStream, *pOLENd))
+                if (SwReqIfReader::WrapOleInRtf(*pStream, aOutStream, *pOLENd, rFrameFormat))
                 {
                     // Data always wrapped in RTF.
                     aFileType = aRTFType;
@@ -1568,7 +1568,7 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame
             aOLEExp.ExportOLEObject(rOLEObj.GetObject(), *pStorage);
             pStorage->Commit();
             aMemory.Seek(0);
-            if (SwReqIfReader::WrapOleInRtf(aMemory, aOutStream, *pOLENd))
+            if (SwReqIfReader::WrapOleInRtf(aMemory, aOutStream, *pOLENd, rFrameFormat))
             {
                 // Data always wrapped in RTF.
                 aFileType = aRTFType;
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 3aa3de435b11..a59f56ee40ee 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -24,6 +24,8 @@
 #include <vcl/FilterConfigItem.hxx>
 #include <vcl/wmf.hxx>
 #include <comphelper/propertyvalue.hxx>
+#include <fmtfsize.hxx>
+#include <frmfmt.hxx>
 
 using namespace com::sun::star;
 
@@ -427,7 +429,8 @@ bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
     return true;
 }
 
-bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode)
+bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
+                  const SwFrameFormat& rFormat)
 {
     sal_uInt64 nPos = rOle2.Tell();
     comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
@@ -436,7 +439,7 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode)
     SvMemoryStream aOLE1;
 
     // Prepare presentation data early, so it's available to both OLE1 and RTF.
-    Size aSize(rOLENode.GetTwipSize());
+    Size aSize = rFormat.GetFrameSize().GetSize();
     sal_uInt32 nWidth = aSize.getWidth();
     sal_uInt32 nHeight = aSize.getHeight();
     const Graphic* pGraphic = rOLENode.GetGraphic();
diff --git a/sw/source/filter/html/htmlreqifreader.hxx b/sw/source/filter/html/htmlreqifreader.hxx
index 3d0816739d6a..5f757d0fbf1d 100644
--- a/sw/source/filter/html/htmlreqifreader.hxx
+++ b/sw/source/filter/html/htmlreqifreader.hxx
@@ -13,6 +13,7 @@ class Graphic;
 class Size;
 class SvStream;
 class SwOLENode;
+class SwFrameFormat;
 
 namespace SwReqIfReader
 {
@@ -24,7 +25,8 @@ namespace SwReqIfReader
 bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat);
 
 /// Wraps an OLE2 container binary in an RTF fragment.
-bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode);
+bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode,
+                  const SwFrameFormat& rFormat);
 
 /**
  * Wraps an image in an RTF fragment.
commit 295626a0bd39540544b774094a63df23e5376839
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Dec 9 09:38:48 2020 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Apr 15 17:57:47 2021 +0200

    vcl: improve EMF+ -> WMF conversion
    
    We throw away EMF fallback info when parsing EMF+ data. This means that
    the resulting GDIMetaFile (containing EMF+ data but no EMF fallback) is
    tricky to export to WMF, where EMF+ comments are not allowed.
    
    Improve the conversion result by re-parsing such EMF+ data with EMF+
    disabled, and then converting the GDIMetaFile (containing EMF fallback
    data) to WMF.
    
    (cherry picked from commit ca67839234e78fe6bea21ec39906d1bd71d34d47)
    
    Conflicts:
            emfio/inc/emfreader.hxx
            emfio/source/emfuno/xemfparser.cxx
            include/vcl/vectorgraphicdata.hxx
            vcl/source/gdi/vectorgraphicdata.cxx
    
    Change-Id: Ib2c0388f1344aef7f601ce9be59e4a8924e8085b

diff --git a/emfio/inc/emfreader.hxx b/emfio/inc/emfreader.hxx
index 90d8969ae70c..6dc9487330cb 100644
--- a/emfio/inc/emfreader.hxx
+++ b/emfio/inc/emfreader.hxx
@@ -32,6 +32,7 @@ namespace emfio
         bool        mbRecordPath : 1;
         bool        mbEMFPlus : 1;
         bool        mbEMFPlusDualMode : 1;
+        bool mbEnableEMFPlus = true;
 
         bool        ReadHeader();
         // reads and converts the rectangle
@@ -43,6 +44,7 @@ namespace emfio
 
         bool ReadEnhWMF();
         void ReadGDIComment(sal_uInt32 nCommentId);
+        void SetEnableEMFPlus(bool bEnableEMFPlus) { mbEnableEMFPlus = bEnableEMFPlus; }
 
     private:
         template <class T> void ReadAndDrawPolyPolygon(sal_uInt32 nNextPos);
diff --git a/emfio/source/emfuno/xemfparser.cxx b/emfio/source/emfuno/xemfparser.cxx
index 3297dea8f30a..0fd49da1c097 100644
--- a/emfio/source/emfuno/xemfparser.cxx
+++ b/emfio/source/emfuno/xemfparser.cxx
@@ -32,6 +32,7 @@
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
 #include <unotools/ucbstreamhelper.hxx>
 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <comphelper/sequenceashashmap.hxx>
 
 #include <wmfreader.hxx>
 #include <emfreader.hxx>
@@ -109,6 +110,17 @@ namespace emfio::emfreader
             {
                 WmfExternal aExternalHeader;
                 const bool bExternalHeaderUsed(aExternalHeader.setSequence(rProperties));
+                bool bEnableEMFPlus = true;
+                comphelper::SequenceAsHashMap aMap(rProperties);
+                auto it = aMap.find("EMFPlusEnable");
+                if (it != aMap.end())
+                {
+                    bool bValue;
+                    if (it->second >>= bValue)
+                    {
+                        bEnableEMFPlus = bValue;
+                    }
+                }
 
                 // rough check - import and conv to primitive
                 GDIMetaFile aMtf;
@@ -130,7 +142,12 @@ namespace emfio::emfreader
                     if (nMetaType == 0x464d4520)
                     {
                         // read and get possible failure/error, ReadEnhWMF returns success
-                        bReadError = !emfio::EmfReader(*pStream, aMtf).ReadEnhWMF();
+                        emfio::EmfReader aReader(*pStream, aMtf);
+                        if (!bEnableEMFPlus)
+                        {
+                            aReader.SetEnableEMFPlus(bEnableEMFPlus);
+                        }
+                        bReadError = !aReader.ReadEnhWMF();
                     }
                     else
                     {
diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx
index c9dd15bc1879..56349bf0774c 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -728,6 +728,12 @@ namespace emfio
         OUString aEMFPlusDisable;
         rtl::Bootstrap::get("EMF_PLUS_DISABLE", aEMFPlusDisable);
         bool bEnableEMFPlus = aEMFPlusDisable.isEmpty();
+        if (!mbEnableEMFPlus)
+        {
+            // EMF+ is enabled if neither the bootstrap variable, not the member variable disables
+            // it.
+            bEnableEMFPlus = mbEnableEMFPlus;
+        }
 
         SAL_INFO("emfio", "EMF_PLUS_DISABLE is " << (bEnableEMFPlus ? "enabled" : "disabled"));
 
diff --git a/include/vcl/vectorgraphicdata.hxx b/include/vcl/vectorgraphicdata.hxx
index 8fce6666e6e8..9151a3425197 100644
--- a/include/vcl/vectorgraphicdata.hxx
+++ b/include/vcl/vectorgraphicdata.hxx
@@ -74,6 +74,8 @@ private:
     // If the vector format has more pages this denotes which page to render
     sal_Int32 mnPageIndex;
 
+    bool mbEnableEMFPlus = true;
+
     // on demand creators
     void ensurePdfReplacement();
     void ensureReplacement();
@@ -113,6 +115,8 @@ public:
 
     sal_Int32 getPageIndex() const { return std::max(sal_Int32(0), mnPageIndex); }
 
+    void setEnableEMFPlus(bool bEnableEMFPlus) { mbEnableEMFPlus = bEnableEMFPlus; }
+
     bool isPrimitiveSequenceCreated() const { return mbSequenceCreated; }
 };
 
diff --git a/include/vcl/wmf.hxx b/include/vcl/wmf.hxx
index 26a1c734425d..4acc21465723 100644
--- a/include/vcl/wmf.hxx
+++ b/include/vcl/wmf.hxx
@@ -25,10 +25,12 @@
 class FilterConfigItem;
 class GDIMetaFile;
 class SvStream;
+class Graphic;
 
 VCL_DLLPUBLIC bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF );
 
 VCL_DLLPUBLIC bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem const * pConfigItem, bool bPlaceable = true );
+VCL_DLLPUBLIC bool ConvertGraphicToWMF( const Graphic & rGraphic, SvStream & rTargetStream, FilterConfigItem const * pConfigItem, bool bPlaceable = true );
 
 bool ConvertGDIMetaFileToEMF(const GDIMetaFile & rMTF, SvStream & rTargetStream);
 
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 6488f32ad578..3aa3de435b11 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -448,7 +448,7 @@ bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode)
         uno::Sequence<beans::PropertyValue> aFilterData
             = { comphelper::makePropertyValue("EmbedEMF", false) };
         FilterConfigItem aConfigItem(&aFilterData);
-        if (ConvertGDIMetaFileToWMF(pGraphic->GetGDIMetaFile(), aGraphicStream, &aConfigItem))
+        if (ConvertGraphicToWMF(*pGraphic, aGraphicStream, &aConfigItem))
         {
             pPresentationData = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
             nPresentationData = aGraphicStream.TellEnd();
diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx
index 4c082a10d21c..acabc316bc4b 100644
--- a/vcl/qa/cppunit/GraphicTest.cxx
+++ b/vcl/qa/cppunit/GraphicTest.cxx
@@ -26,6 +26,7 @@
 #include <unotools/ucbstreamhelper.hxx>
 #include <unotools/tempfile.hxx>
 #include <vcl/cvtgrf.hxx>
+#include <vcl/metaact.hxx>
 
 #include <impgraph.hxx>
 #include <graphic/GraphicFormatDetector.hxx>
@@ -332,6 +333,31 @@ void GraphicTest::testEmfToWmfConversion()
     // - Actual  : EMF
     // i.e. EMF data was requested to be converted to WMF, but the output was still EMF.
     CPPUNIT_ASSERT_EQUAL(OUString("WMF"), aDetector.msDetectedFormat);
+
+    // Import the WMF result and check for traces of EMF+ in it.
+    Graphic aWmfGraphic;
+    aGraphicStream.Seek(0);
+    CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aGraphicFilter.ImportGraphic(aWmfGraphic, OUString(),
+                                                                    aGraphicStream, nFormat));
+    int nCommentCount = 0;
+    for (size_t i = 0; i < aWmfGraphic.GetGDIMetaFile().GetActionSize(); ++i)
+    {
+        MetaAction* pAction = aWmfGraphic.GetGDIMetaFile().GetAction(i);
+        if (pAction->GetType() == MetaActionType::COMMENT)
+        {
+            auto pComment = static_cast<MetaCommentAction*>(pAction);
+            if (pComment->GetComment().startsWith("EMF_PLUS"))
+            {
+                ++nCommentCount;
+            }
+        }
+    }
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected less or equal than: 4
+    // - Actual  : 8
+    // i.e. even more EMF+ comments were left in the WMF output. The ideal would be to get this down
+    // to 0, though.
+    CPPUNIT_ASSERT_LESSEQUAL(4, nCommentCount);
 }
 
 void GraphicTest::testSwapping()
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index b4763831105b..a95bfff363c3 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -1951,7 +1951,7 @@ ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& r
                 if (!bDone)
                 {
                     // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
-                    if (!ConvertGDIMetaFileToWMF(aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem))
+                    if (!ConvertGraphicToWMF(aGraphic, rOStm, &aConfigItem))
                         nStatus = ERRCODE_GRFILTER_FORMATERROR;
 
                     if (rOStm.GetError())
diff --git a/vcl/source/filter/wmf/wmf.cxx b/vcl/source/filter/wmf/wmf.cxx
index 7818309ed6d1..8a04bc1d3025 100644
--- a/vcl/source/filter/wmf/wmf.cxx
+++ b/vcl/source/filter/wmf/wmf.cxx
@@ -23,6 +23,8 @@
 #include <vcl/gdimetafiletools.hxx>
 #include <vcl/graph.hxx>
 
+using namespace com::sun::star;
+
 bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF )
 {
     // tdf#111484 Use new method to import Metafile. Take current StreamPos
@@ -80,7 +82,32 @@ bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream
         clipMetafileContentAgainstOwnRegions(aGdiMetaFile);
     }
 
-    return aWMFWriter.WriteWMF( aGdiMetaFile, rTargetStream, pConfigItem, bPlaceable );
+    bool bRet = aWMFWriter.WriteWMF(aGdiMetaFile, rTargetStream, pConfigItem, bPlaceable);
+    return bRet;
+}
+
+bool ConvertGraphicToWMF(const Graphic& rGraphic, SvStream& rTargetStream,
+                         FilterConfigItem const* pConfigItem, bool bPlaceable)
+{
+    GfxLink aLink = rGraphic.GetGfxLink();
+    if (aLink.IsEMF() && aLink.GetData() && aLink.GetDataSize())
+    {
+        // This may be an EMF+ file, converting that to WMF is better done by re-parsing EMF+ as EMF
+        // and converting that to WMF.
+        uno::Sequence<sal_Int8> aData(reinterpret_cast<const sal_Int8*>(aLink.GetData()),
+                                      aLink.GetDataSize());
+        auto aVectorGraphicData
+            = std::make_shared<VectorGraphicData>(aData, OUString(), VectorGraphicDataType::Emf);
+        aVectorGraphicData->setEnableEMFPlus(false);
+        Graphic aGraphic(aVectorGraphicData);
+        bool bRet = ConvertGDIMetaFileToWMF(aGraphic.GetGDIMetaFile(), rTargetStream, pConfigItem,
+                                            bPlaceable);
+        return bRet;
+    }
+
+    bool bRet = ConvertGDIMetaFileToWMF(rGraphic.GetGDIMetaFile(), rTargetStream, pConfigItem,
+                                        bPlaceable);
+    return bRet;
 }
 
 bool ConvertGDIMetaFileToEMF(const GDIMetaFile & rMTF, SvStream & rTargetStream)
diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx
index 99e51f65cc71..fe9ca5535e6e 100644
--- a/vcl/source/gdi/vectorgraphicdata.cxx
+++ b/vcl/source/gdi/vectorgraphicdata.cxx
@@ -34,6 +34,7 @@
 #include <comphelper/seqstream.hxx>
 #include <comphelper/sequence.hxx>
 #include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/outdev.hxx>
 #include <vcl/wmfexternal.hxx>
@@ -209,6 +210,16 @@ void VectorGraphicData::ensureSequenceAndRange()
                     aSequence = mpExternalHeader->getSequence();
                 }
 
+                if (!mbEnableEMFPlus)
+                {
+                    auto aVector
+                        = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(
+                            aSequence);
+                    aVector.push_back(
+                        comphelper::makePropertyValue("EMFPlusEnable", uno::makeAny(false)));
+                    aSequence = comphelper::containerToSequence(aVector);
+                }
+
                 if (myInputStream.is())
                     maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(myInputStream, maPath, aSequence));
 
commit d8a2a453866e035d77654caef115463cfdbe7c07
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Thu Apr 8 17:03:21 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Apr 9 10:01:19 2021 +0200

    embeddedobj: fix lost native data when updating it via OLE fails
    
    How to reproduce the problem:
    
    1) Create an ODT file which has an OLE object, where the native data is
    an OLE2 container, containing a Package stream, containing a DOCX file.
    
    2) Install some external application on Windows which registers itself
    as a handler for the DOCX CSLID [ this is where writing a testcase for
    this bug is challenging ].
    
    3) Open this document via Java, using URP. Load the document with
    Hidden=true and OnMainThread=true.
    
    4) Dispatch .uno:UpdateAll
    
    5) Save the document using XStorable.store()
    
    Expected result: the native data is there.
    
    Actual result: the native data is sometimes missing (0 bytes). Typically
    happens at least once if you perform the steps 4 times in a row.
    
    The root cause is that GetUserClassID() Win32 API fails in some cases,
    and re-trying a few times after a small sleep doesn't help.
    
    Handle this error better by detecting this situation in
    OleEmbeddedObject::SwitchOwnPersistence() and reusing the old native
    data, similar to how svt::EmbeddedObjectRef::GetReplacement() updates
    the preview image in a transactional way (only delete the old one when
    we have a one one).
    
    Finally, detect a broken OLE2 preview during reqif export, this way the
    reqif export result's embedded object is editable in Word, while
    \objdata was simply empty previously.
    
    (cherry picked from commit fb4dc0f1786e0a036fc224393e91a3f1fdbff1b3)
    
    Change-Id: I4dd34ebe6ad892a14cdcfb82acc82d9edf790fb3

diff --git a/embeddedobj/source/msole/olecomponent.cxx b/embeddedobj/source/msole/olecomponent.cxx
index 7e8cfdb1809e..8fc8a3e0559f 100644
--- a/embeddedobj/source/msole/olecomponent.cxx
+++ b/embeddedobj/source/msole/olecomponent.cxx
@@ -1300,7 +1300,10 @@ void OleComponent::StoreOwnTmpIfNecessary()
             GUID aCLSID;
             hr = m_pNativeImpl->m_pOleObject->GetUserClassID( &aCLSID );
             if ( FAILED( hr ) )
+            {
+                SAL_WARN("embeddedobj.ole", "OleComponent::StoreOwnTmpIfNecessary: GetUserClassID() failed");
                 throw io::IOException(); // TODO
+            }
 
             hr = WriteClassStg( m_pNativeImpl->m_pIStorage, aCLSID );
             if ( FAILED( hr ) )
diff --git a/embeddedobj/source/msole/olepersist.cxx b/embeddedobj/source/msole/olepersist.cxx
index c4c8760b549b..57699246a723 100644
--- a/embeddedobj/source/msole/olepersist.cxx
+++ b/embeddedobj/source/msole/olepersist.cxx
@@ -767,6 +767,21 @@ void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStor
     sal_Int32 nStreamMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
 
     uno::Reference< io::XStream > xNewOwnStream = xNewParentStorage->openStreamElement( aNewName, nStreamMode );
+
+    uno::Reference<io::XSeekable> xNewSeekable (xNewOwnStream, uno::UNO_QUERY);
+    if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
+    {
+        uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
+        if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
+        {
+            SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence: empty new stream, reusing old one");
+            uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
+            uno::Reference<io::XOutputStream> xOutput = xNewOwnStream->getOutputStream();
+            comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
+            xNewSeekable->seek(0);
+        }
+    }
+
     SAL_WARN_IF( !xNewOwnStream.is(), "embeddedobj.ole", "The method can not return empty reference!" );
 
     SwitchOwnPersistence( xNewParentStorage, xNewOwnStream, aNewName );
diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx
index 005dd2788640..6488f32ad578 100644
--- a/sw/source/filter/html/htmlreqifreader.cxx
+++ b/sw/source/filter/html/htmlreqifreader.cxx
@@ -142,6 +142,15 @@ bool ParseOLE2Presentation(SvStream& rOle2, sal_uInt32& nWidth, sal_uInt32& nHei
     // Read Data.
     if (nSize > xOle2Presentation->remainingSize())
         return false;
+
+    if (nSize <= 64)
+    {
+        SAL_WARN("sw.html",
+                 "ParseOLE2Presentation: ignoring potentially broken small preview: size is "
+                     << nSize);
+        return false;
+    }
+
     std::vector<char> aBuffer(nSize);
     xOle2Presentation->ReadBytes(aBuffer.data(), aBuffer.size());
     rPresentationData.WriteBytes(aBuffer.data(), aBuffer.size());
commit 7be1c307653cbff8470d3a01c50f93034d1eba3f
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Apr 7 14:25:02 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Wed Apr 7 14:25:06 2021 +0200

    CppunitTest_sw_uibase_uno: remove not needed reference to swqahelper
    
    Forgot to squash this into the previous commit. swqahelper is needed on
    master but not on this branch.
    
    Change-Id: Ica348d70425c199b7c858d3b488bb3027ae2e014

diff --git a/sw/CppunitTest_sw_uibase_uno.mk b/sw/CppunitTest_sw_uibase_uno.mk
index 36c54d04db33..5f6e3cc2c07d 100644
--- a/sw/CppunitTest_sw_uibase_uno.mk
+++ b/sw/CppunitTest_sw_uibase_uno.mk
@@ -28,7 +28,6 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_uibase_uno, \
     svx \
     svxcore \
     sw \
-	swqahelper \
     test \
     unotest \
     utl \
commit b7812468120c8618c62ef8cfbf061528f55e4da3
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Sep 30 16:48:27 2020 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Wed Mar 31 08:35:48 2021 +0200

    sw: fix heap-use-after-free in the UnoActionContext dtor
    
    When lockControllers() is followed by close() + dispose(), but no match
    unlock first:
    
    ==8514==ERROR: AddressSanitizer: heap-use-after-free on address 0x6190002d1b58 at pc 0x7f48b13f5b85 bp 0x7fff557d98c0 sp 0x7fff557d98b8
    ...
        #3 0x7f48b138beca in SwDoc::getIDocumentLayoutAccess() /sw/source/core/doc/doc.cxx:412:12
        #4 0x7f48b58db224 in UnoActionContext::~UnoActionContext() /sw/source/core/unocore/unoobj2.cxx:200:49
    ...
        #15 0x7f48b841c484 in SwXTextDocument::~SwXTextDocument() /sw/source/uibase/uno/unotxdoc.cxx:439:1
    
    freed by thread T0 here:
        #1 0x7f48b1388a26 in SwDoc::release() /sw/source/core/doc/doc.cxx:118:9
    ...
        #17 0x7f48d15a40e5 in SfxBaseModel::dispose() /sfx2/source/doc/sfxbasemodel.cxx:755:13
        #18 0x7f48b8429a48 in SwXTextDocument::dispose() /sw/source/uibase/uno/unotxdoc.cxx:586:19
    
    (cherry picked from commit e08afec61aef62dd4f949ca7e1ffcc70d437e525)
    
    Change-Id: I39bf65e43c12ce5ee49bdedeb1673b934ca21106

diff --git a/sw/CppunitTest_sw_uibase_uno.mk b/sw/CppunitTest_sw_uibase_uno.mk
new file mode 100644
index 000000000000..36c54d04db33
--- /dev/null
+++ b/sw/CppunitTest_sw_uibase_uno.mk
@@ -0,0 +1,74 @@
+# -*- 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_uibase_uno))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_uibase_uno))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_uibase_uno, \
+    sw/qa/uibase/uno/uno \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_uibase_uno, \
+    comphelper \
+    cppu \
+    cppuhelper \
+    editeng \
+    sal \
+    sfx \
+    svl \
+    svx \
+    svxcore \
+    sw \
+	swqahelper \
+    test \
+    unotest \
+    utl \
+    vcl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_uibase_uno,\
+    boost_headers \
+    libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_uibase_uno,\
+    -I$(SRCDIR)/sw/inc \
+    -I$(SRCDIR)/sw/source/core/inc \
+    -I$(SRCDIR)/sw/source/uibase/inc \
+    -I$(SRCDIR)/sw/qa/inc \
+    $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_uibase_uno,\
+	udkapi \
+	offapi \
+	oovbaapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_uibase_uno))
+$(eval $(call gb_CppunitTest_use_vcl,sw_uibase_uno))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_uibase_uno,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_uibase_uno,\
+    officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_uibase_uno))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_uibase_uno, \
+    modules/swriter \
+))
+
+$(eval $(call gb_CppunitTest_use_more_fonts,sw_uibase_uno))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index 653f97335f92..723c26f53e40 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -111,6 +111,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
     CppunitTest_sw_uibase_shells \
     CppunitTest_sw_uibase_dochdl \
     CppunitTest_sw_uibase_frmdlg \
+    CppunitTest_sw_uibase_uno \
     CppunitTest_sw_core_accessibilitycheck \
     CppunitTest_sw_core_layout \
     CppunitTest_sw_core_frmedt \
diff --git a/sw/qa/uibase/uno/uno.cxx b/sw/qa/uibase/uno/uno.cxx
new file mode 100644
index 000000000000..23c1829ab7de
--- /dev/null
+++ b/sw/qa/uibase/uno/uno.cxx
@@ -0,0 +1,36 @@
+/* -*- 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/util/XCloseable.hpp>
+
+/// Covers sw/source/uibase/uno/ fixes.
+class SwUibaseUnoTest : public SwModelTestBase
+{
+};
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testLockControllers)
+{
+    mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+    {
+        uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY_THROW);
+        xModel->lockControllers();
+    }
+    {
+        uno::Reference<util::XCloseable> xCloseable(mxComponent, uno::UNO_QUERY_THROW);
+        xCloseable->close(false);
+    }
+    // Without the accompanying fix in place, this test would have crashed.
+    mxComponent.clear();
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index b65386a7c392..63a5a86941e7 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -583,6 +583,10 @@ void SwXTextDocument::disconnectController(const Reference< frame::XController >
 
 void SwXTextDocument::dispose()
 {
+    // Delete UnoActionContexts before deleting the SwDoc, as the first has unowned pointers to the
+    // second.
+    maActionArr.clear();
+
     SfxBaseModel::dispose();
 }
 
commit 833de9c3dbf52adaa2e62d0e5f624dce9ec0113d
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Mar 24 16:38:18 2021 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Mar 25 13:49:49 2021 +0100

    sw reqif-xhtml export: fix unexpected height for <td>
    
    The ReqIF validator complains about this, similar to the already
    disabled width.
    
    (cherry picked from commit ab6a7a9addfc059d8f1fbeaa6c6012666629d420)
    
    Change-Id: I05137a9dcc7e94bffe92269e98d310724a144b24

diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 6fdf15730dde..5e1264fcadb4 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -684,6 +684,39 @@ DECLARE_HTMLEXPORT_TEST(testReqIfTable2, "reqif-table2.odt")
     CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:td>") != -1);
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIfTableHeight)
+{
+    // Given a document with a table in it, with an explicit row height:
+    loadURL("private:factory/swriter", nullptr);
+    uno::Sequence<beans::PropertyValue> aTableProperties = {
+        comphelper::makePropertyValue("Rows", static_cast<sal_Int32>(1)),
+        comphelper::makePropertyValue("Columns", static_cast<sal_Int32>(1)),
+    };
+    dispatchCommand(mxComponent, ".uno:InsertTable", aTableProperties);
+    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
+                                                    uno::UNO_QUERY);
+    uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xRow(xTable->getRows()->getByIndex(0), uno::UNO_QUERY);
+    xRow->setPropertyValue("Height", uno::makeAny(static_cast<sal_Int32>(1000)));
+
+    // When exporting to reqif-xhtml:
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    uno::Sequence<beans::PropertyValue> aStoreProperties = {
+        comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+        comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+    };
+    xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+    // Then make sure that the explicit cell height is omitted from the output:
+    SvMemoryStream aStream;
+    HtmlExportTest::wrapFragment(maTempFile, aStream);
+    xmlDocUniquePtr pDoc = parseXmlStream(&aStream);
+    // Without the accompanying fix in place, this test would have failed, explicit height was
+    // written, which is not valid reqif-xhtml.
+    assertXPathNoAttribute(pDoc, "//reqif-xhtml:td", "height");
+}

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list