sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml | 2 - sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml | 2 - sw/qa/extras/htmlexport/htmlexport.cxx | 11 ++++---- sw/qa/extras/htmlimport/data/data.ole | 1 sw/qa/extras/htmlimport/data/ole-data.xhtml | 7 +++++ sw/qa/extras/htmlimport/htmlimport.cxx | 27 ++++++++++++++++++++++ sw/source/filter/html/htmlgrin.cxx | 8 ++++++ sw/source/filter/html/htmlplug.cxx | 13 +++++++--- sw/source/filter/html/swhtml.hxx | 3 ++ 9 files changed, 62 insertions(+), 12 deletions(-)
New commits: commit 56769d3982e6afb075cb6d833662f066437fab6a Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue May 24 14:58:47 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue May 24 17:08:24 2022 +0200 sw XHTML import: handle non-image, non-RTF objects as clickable images A pair of XHTML <object> elements is meant to be interpreted as "native data" (outer) and "fallback/preview image" (inner). In practice we map non-PNG + PNG pairs to images and OLE2 data + PNG pairs to OLE2 embedded objects. This setup works for OLE2 data and images, but XHTML producers can also put other raw data to the outer <object> like PDF, DOCX, XLSX, etc. These were mapped to ODummyEmbeddedObject, which preserves data, but you can't interact with the data. Fix the lack of interaction by changing how non-OLE2, non-image data is handled: map them to images where the image has a URL to the native data. This way the OS running Writer can decide how to handle that data. This required changing some existing tests where the intention was to have simple test data for OLE2 data, but that data was not OLE2, so the resulting doc model had images, but embedded objects were expected. Such tests now have OLE2 data instead. Change-Id: I0287ce2d9a02904e28cef619ff9f6e1f354d6147 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134874 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml index 9e0cfaa378b4..5f9c8940008e 100644 --- a/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml +++ b/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml @@ -1,3 +1,3 @@ <reqif-xhtml:div> - <reqif-xhtml:object data="reqif-ole-data.ole" type="text/rtf"/> + <reqif-xhtml:object data="ole2.ole" type="text/rtf"/> </reqif-xhtml:div> diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml index 6217412ae597..df3f4a048ec6 100644 --- a/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml +++ b/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml @@ -1,5 +1,5 @@ <reqif-xhtml:div><reqif-xhtml:br/> - <reqif-xhtml:object data="reqif-ole-data.ole" type="text/rtf"> + <reqif-xhtml:object data="ole2.ole" type="text/rtf"> <reqif-xhtml:object data="reqif-ole-img.png?test=true" type="image/png">OLE Object</reqif-xhtml:object> </reqif-xhtml:object> </reqif-xhtml:div> diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index a85715f6bebc..e823632f08ea 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -719,13 +719,12 @@ DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testReqIfOleImg, "reqif-ole-img.xhtml") // Check mime/media types. CPPUNIT_ASSERT_EQUAL(OUString("image/png"), getProperty<OUString>(xGraphic, "MimeType")); - uno::Reference<document::XStorageBasedDocument> xStorageProvider(mxComponent, uno::UNO_QUERY); - uno::Reference<embed::XStorage> xStorage = xStorageProvider->getDocumentStorage(); - auto aStreamName = getProperty<OUString>(xObject, "StreamName"); - uno::Reference<io::XStream> xStream - = xStorage->openStreamElement(aStreamName, embed::ElementModes::READ); + uno::Reference<beans::XPropertySet> xObjectProps(xObject, uno::UNO_QUERY); + uno::Reference<io::XActiveDataStreamer> xStreamProvider( + xObjectProps->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY); + uno::Reference<io::XSeekable> xStream(xStreamProvider->getStream(), uno::UNO_QUERY); // This was empty when either import or export handling was missing. - CPPUNIT_ASSERT_EQUAL(OUString("text/rtf"), getProperty<OUString>(xStream, "MediaType")); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(37888), xStream->getLength()); // Check alternate text (it was empty, for export the 'alt' attribute was used). CPPUNIT_ASSERT_EQUAL(OUString("OLE Object"), getProperty<OUString>(xObject, "Title").trim()); diff --git a/sw/qa/extras/htmlimport/data/data.ole b/sw/qa/extras/htmlimport/data/data.ole new file mode 100644 index 000000000000..d3dc23d793e2 --- /dev/null +++ b/sw/qa/extras/htmlimport/data/data.ole @@ -0,0 +1 @@ +{\pict} diff --git a/sw/qa/extras/htmlimport/data/ole-data.xhtml b/sw/qa/extras/htmlimport/data/ole-data.xhtml new file mode 100644 index 000000000000..e8f1910ad4c9 --- /dev/null +++ b/sw/qa/extras/htmlimport/data/ole-data.xhtml @@ -0,0 +1,7 @@ +<reqif-xhtml:div> +<reqif-xhtml:p> +<reqif-xhtml:object data="data.ole" type="application/octet-stream"> + <reqif-xhtml:object data="ole2.png" type="image/png"></reqif-xhtml:object> +</reqif-xhtml:object> +</reqif-xhtml:p> +</reqif-xhtml:div> diff --git a/sw/qa/extras/htmlimport/htmlimport.cxx b/sw/qa/extras/htmlimport/htmlimport.cxx index 00e2ec99191f..19c776fe687e 100644 --- a/sw/qa/extras/htmlimport/htmlimport.cxx +++ b/sw/qa/extras/htmlimport/htmlimport.cxx @@ -536,6 +536,33 @@ CPPUNIT_TEST_FIXTURE(HtmlImportTest, testUTF16_nonBMP) getParagraph(1)->getString()); } +CPPUNIT_TEST_FIXTURE(SwModelTestBase, testOleData) +{ + // Given an XHTML with an <object> (containing non-image, non-OLE2 data) and an inner <object> + // (containing PNG): + uno::Sequence<beans::PropertyValue> aLoadProperties = { + comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")), + comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), + }; + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "ole-data.xhtml"; + + // When loading the document: + mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", aLoadProperties); + + // Then make sure the result is a single clickable Writer image: + uno::Reference<text::XTextGraphicObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xObjects(xSupplier->getGraphicObjects(), + uno::UNO_QUERY); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 + // - Actual : 1 + // i.e. the image was not imported as a Writer image (but as an OLE object). + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xObjects->getCount()); + uno::Reference<css::drawing::XShape> xShape = getShape(1); + // And then the image was not clickable: this was empty. + CPPUNIT_ASSERT(getProperty<OUString>(xShape, "HyperLinkURL").endsWith("/data.ole")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlgrin.cxx b/sw/source/filter/html/htmlgrin.cxx index 5ed465811ed9..7d3c24d67021 100644 --- a/sw/source/filter/html/htmlgrin.cxx +++ b/sw/source/filter/html/htmlgrin.cxx @@ -871,6 +871,14 @@ IMAGE_SETEVENT: } } + else if (!m_aEmbedURL.isEmpty()) + { + // This is an inner <object> image and the outer <object> has a URL for us. Set that on the + // image. + SwFormatURL aURL(pFlyFormat->GetURL()); + aURL.SetURL(m_aEmbedURL, bIsMap); + pFlyFormat->SetFormatAttr(aURL); + } if( !aMacroItem.GetMacroTable().empty() ) { diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx index 710cd2f986c7..ace6570e332b 100644 --- a/sw/source/filter/html/htmlplug.cxx +++ b/sw/source/filter/html/htmlplug.cxx @@ -560,8 +560,8 @@ bool SwHTMLParser::InsertEmbed() aCnt.SwitchPersistence(xStorage); aObjName = aCnt.CreateUniqueObjectName(); { - SvFileStream aFileStream(aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE), - StreamMode::READ); + OUString aEmbedURL = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); + SvFileStream aFileStream(aEmbedURL, StreamMode::READ); uno::Reference<io::XInputStream> xInStream; SvMemoryStream aMemoryStream; @@ -599,8 +599,13 @@ bool SwHTMLParser::InsertEmbed() } if (!xInStream.is()) - // Non-RTF case. - xInStream.set(new utl::OStreamWrapper(aFileStream)); + { + // Object data is neither OLE2 in RTF, nor an image. Then map this to an URL that + // will be set on the inner image. + m_aEmbedURL = aEmbedURL; + // Signal success, so the outer object won't fall back to the image handler. + return true; + } if (!xObj.is()) { diff --git a/sw/source/filter/html/swhtml.hxx b/sw/source/filter/html/swhtml.hxx index e89cfb616712..aa5e98d911e6 100644 --- a/sw/source/filter/html/swhtml.hxx +++ b/sw/source/filter/html/swhtml.hxx @@ -492,6 +492,9 @@ class SwHTMLParser : public SfxHTMLParser, public SvtListener std::set<OUString> m_aAllowedRTFOLEMimeTypes; + /// This is the URL of the outer <object> data if it's not OLE2 or an image. + OUString m_aEmbedURL; + void DeleteFormImpl(); void DocumentDetected();