editeng/qa/unit/core-test.cxx | 61 ++++ editeng/source/editeng/editeng.cxx | 7 editeng/source/editeng/impedit2.cxx | 33 ++ sc/CppunitTest_sc_tiledrendering2.mk | 75 +++++ sc/Module_sc.mk | 1 sc/qa/unit/tiledrendering/tiledrendering.cxx | 26 - sc/qa/unit/tiledrendering2/tiledrendering2.cxx | 166 ++++++++++++ sw/qa/core/layout/data/floattable-not-wrapped-by-table.docx |binary sw/qa/core/layout/tabfrm.cxx | 22 + sw/source/core/layout/tabfrm.cxx | 15 - 10 files changed, 375 insertions(+), 31 deletions(-)
New commits: commit 26a45d7809ca5a90e36a90ee14bf56d555adf278 Author: Miklos Vajna <[email protected]> AuthorDate: Tue Jan 23 15:34:07 2024 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Jan 25 08:34:21 2024 +0100 tdf#159017 sw floattable: only shift to the right when needed Regression from commit 868140fcc1311259b9d5f666637b33d226511a53 (tdf#60558 sw floattable: allow wrap of table on the right of a floattable, 2023-12-05), the document had an inline table, followed by a floating table, and we moved the inline table to the right even if the left hand side of the floating table already had enough space. What happens here is that nominally the inline table's original position overlaps, but because the table width is small enough, such an overlap doesn't actually happen. In this case, it's not needed to shift the inline table to the right. Fix the problem by making the check that decides whether it's necessary to increment the left margin of the table more strict: it's not enough to have enough space on the right of the fly, it's also needed to *not* have enough space on the left side. This keeps the original "floating table wrapped by inline table on the right" use-case working, but restores the ~no left margin for the inline table for the new bugdoc. (cherry picked from commit 5df7c66193d55af944b3269f11374e60da437c0b) Change-Id: Ifb30d90ca6dba7cc4a402d8a4445251120b575ae Tested-by: Jenkins Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162464 Reviewed-by: Xisco Fauli <[email protected]> diff --git a/sw/qa/core/layout/data/floattable-not-wrapped-by-table.docx b/sw/qa/core/layout/data/floattable-not-wrapped-by-table.docx new file mode 100644 index 000000000000..2c255148d351 Binary files /dev/null and b/sw/qa/core/layout/data/floattable-not-wrapped-by-table.docx differ diff --git a/sw/qa/core/layout/tabfrm.cxx b/sw/qa/core/layout/tabfrm.cxx index 9357fc2df133..61b1a25109f5 100644 --- a/sw/qa/core/layout/tabfrm.cxx +++ b/sw/qa/core/layout/tabfrm.cxx @@ -199,6 +199,28 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWrappedByTable) // i.e. the inline table was under the floating one, not on the right of it. CPPUNIT_ASSERT_LESS(nFloatingBottom, nInlineTop); } + +CPPUNIT_TEST_FIXTURE(Test, testInlineTableThenSplitFly) +{ + // Given a document with a floating table ("right") and an inline table ("left"): + // When laying out the document: + createSwDoc("floattable-not-wrapped-by-table.docx"); + + // Then make sure the inline table is on the left (small negative offset): + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage = pLayout->Lower()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage); + SwFrame* pBody = pPage->FindBodyCont(); + auto pTab = pBody->GetLower()->GetNext()->DynCastTabFrame(); + SwTwips nInlineLeft = pTab->getFramePrintArea().Left(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected less than: 0 + // - Actual : 6958 + // i.e. "left" was on the right, its horizontal margin was not a small negative value but a + // large positive one. + CPPUNIT_ASSERT_LESS(static_cast<SwTwips>(0), nInlineLeft); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 033f692f47cc..f75782456181 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -3296,6 +3296,7 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, bool bShiftDown = css::text::WrapTextMode_NONE == nSurround; bool bSplitFly = pFly->IsFlySplitAllowed(); + const SwRect aFlyRectWithoutSpaces = pFly->GetObjRect(); if (!bShiftDown && bAddVerticalFlyOffsets) { if (nSurround == text::WrapTextMode_PARALLEL && isHoriOrientShiftDown) @@ -3310,7 +3311,6 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, // Ignore spacing when determining the left/right edge of the fly, like // Word does. - const SwRect aFlyRectWithoutSpaces = pFly->GetObjRect(); basegfx::B1DRange aFlyRange(aRectFnSet.GetLeft(aFlyRectWithoutSpaces), aRectFnSet.GetRight(aFlyRectWithoutSpaces)); @@ -3373,9 +3373,16 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, bool bFlyHoriOrientLeft = text::HoriOrientation::LEFT == rHori.GetHoriOrient(); if (bSplitFly && !bFlyHoriOrientLeft) { - // If a split fly is oriented "from left", we already checked if it has enough space on - // the right, so from-left and left means the same here. - bFlyHoriOrientLeft = rHori.GetHoriOrient() == text::HoriOrientation::NONE; + // Only shift to the right if we don't have enough space on the left. + SwTwips nTabWidth = getFramePrintArea().Width(); + SwTwips nWidthDeadline = aFlyRectWithoutSpaces.Left() + - pFly->GetAnchorFrame()->GetUpper()->getFrameArea().Left(); + if (nTabWidth > nWidthDeadline) + { + // If a split fly is oriented "from left", we already checked if it has enough space on + // the right, so from-left and left means the same here. + bFlyHoriOrientLeft = rHori.GetHoriOrient() == text::HoriOrientation::NONE; + } } if ((css::text::WrapTextMode_RIGHT == nSurround || css::text::WrapTextMode_PARALLEL == nSurround) commit 1991b50908c5a53642e7ad086fd1319ec7710dd5 Author: Miklos Vajna <[email protected]> AuthorDate: Tue Jan 23 17:08:44 2024 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Jan 25 08:31:43 2024 +0100 CppunitTest_sc_tiledrendering2: extract one test from the old, large suite Not a split, to avoid too many conflicts while cherry-picking, but at least create a new suite where next tests can be added without too much build time after source code edits. (cherry picked from commit a2763fe7b6f22e3e65d7e0db62b6ada967ccdd61) Change-Id: I494df6e23941845a433aab6ec5ecef040feab30e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162473 Tested-by: Jenkins diff --git a/sc/CppunitTest_sc_tiledrendering2.mk b/sc/CppunitTest_sc_tiledrendering2.mk new file mode 100644 index 000000000000..d360780428a6 --- /dev/null +++ b/sc/CppunitTest_sc_tiledrendering2.mk @@ -0,0 +1,75 @@ +# -*- 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,sc_tiledrendering2)) + +$(eval $(call gb_CppunitTest_use_common_precompiled_header,sc_tiledrendering2)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sc_tiledrendering2, \ + sc/qa/unit/tiledrendering2/tiledrendering2 \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sc_tiledrendering2, \ + comphelper \ + cppu \ + cppuhelper \ + editeng \ + sal \ + sfx \ + sot \ + svl \ + svt \ + svxcore \ + sc \ + scfilt \ + scui \ + subsequenttest \ + test \ + unotest \ + $(call gb_Helper_optional,SCRIPTING, \ + vbahelper) \ + vcl \ + tl \ + utl \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sc_tiledrendering2,\ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_CppunitTest_set_include,sc_tiledrendering2,\ + -I$(SRCDIR)/sc/source/ui/inc \ + -I$(SRCDIR)/sc/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,sc_tiledrendering2)) +$(eval $(call gb_CppunitTest_use_api,sc_tiledrendering2,oovbaapi)) + +$(eval $(call gb_CppunitTest_use_ure,sc_tiledrendering2)) +$(eval $(call gb_CppunitTest_use_vcl,sc_tiledrendering2)) + +$(eval $(call gb_CppunitTest_use_rdb,sc_tiledrendering2,services)) + +$(eval $(call gb_CppunitTest_use_configuration,sc_tiledrendering2)) + +$(eval $(call gb_CppunitTest_add_arguments,sc_tiledrendering2, \ + -env:arg-env=$(gb_Helper_LIBRARY_PATH_VAR)"$$$${$(gb_Helper_LIBRARY_PATH_VAR)+=$$$$$(gb_Helper_LIBRARY_PATH_VAR)}" \ +)) + +$(eval $(call gb_CppunitTest_use_uiconfigs,sc_tiledrendering2, \ + modules/scalc \ + sfx \ + svt \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index 0c2178b7fea1..74abee25c4b6 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -70,6 +70,7 @@ ifneq ($(DISABLE_GUI),TRUE) ifeq ($(OS),LINUX) $(eval $(call gb_Module_add_check_targets,sc,\ CppunitTest_sc_tiledrendering \ + CppunitTest_sc_tiledrendering2 \ )) endif endif diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx index e70cbfb93f1b..b7676f70761e 100644 --- a/sc/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx @@ -3594,32 +3594,6 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testStatusBarLocale) CPPUNIT_ASSERT_EQUAL(std::string("de-DE"), aLocale); } -CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testSidebarLocale) -{ - ScModelObj* pModelObj = createDoc("chart.ods"); - int nView1 = SfxLokHelper::getView(); - ViewCallback aView1; - SfxViewShell* pView1 = SfxViewShell::Current(); - pView1->SetLOKLocale("en-US"); - SfxLokHelper::createView(); - ViewCallback aView2; - SfxViewShell* pView2 = SfxViewShell::Current(); - pView2->SetLOKLocale("de-DE"); - TestLokCallbackWrapper::InitializeSidebar(); - Scheduler::ProcessEventsToIdle(); - aView2.m_aStateChanges.clear(); - - pModelObj->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, /*x=*/1,/*y=*/1,/*count=*/2, /*buttons=*/1, /*modifier=*/0); - pModelObj->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, /*x=*/1, /*y=*/1, /*count=*/2, /*buttons=*/1, /*modifier=*/0); - SfxLokHelper::setView(nView1); - Scheduler::ProcessEventsToIdle(); - - auto it = aView2.m_aStateChanges.find(".uno:Sidebar"); - CPPUNIT_ASSERT(it != aView2.m_aStateChanges.end()); - std::string aLocale = it->second.get<std::string>("locale"); - CPPUNIT_ASSERT_EQUAL(std::string("de-DE"), aLocale); -} - CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testLongFirstColumnMouseClick) { // Document has a long first column. We want to mouse-click on the column and diff --git a/sc/qa/unit/tiledrendering/data/chart.ods b/sc/qa/unit/tiledrendering2/data/chart.ods similarity index 100% rename from sc/qa/unit/tiledrendering/data/chart.ods rename to sc/qa/unit/tiledrendering2/data/chart.ods diff --git a/sc/qa/unit/tiledrendering2/tiledrendering2.cxx b/sc/qa/unit/tiledrendering2/tiledrendering2.cxx new file mode 100644 index 000000000000..058e7deb0883 --- /dev/null +++ b/sc/qa/unit/tiledrendering2/tiledrendering2.cxx @@ -0,0 +1,166 @@ +/* -*- 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/unoapixml_test.hxx> + +#include <boost/property_tree/json_parser.hpp> + +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <comphelper/lok.hxx> +#include <comphelper/servicehelper.hxx> +#include <sfx2/lokhelper.hxx> +#include <test/lokcallback.hxx> +#include <vcl/scheduler.hxx> + +#include <docuno.hxx> + +using namespace com::sun::star; + +namespace +{ +class Test : public UnoApiXmlTest +{ +public: + Test(); + void setUp() override; + void tearDown() override; + + ScModelObj* createDoc(const char* pName); +}; + +Test::Test() + : UnoApiXmlTest("/sc/qa/unit/tiledrendering2/data/") +{ +} + +void Test::setUp() +{ + UnoApiXmlTest::setUp(); + + comphelper::LibreOfficeKit::setActive(true); +} + +void Test::tearDown() +{ + if (mxComponent.is()) + { + mxComponent->dispose(); + mxComponent.clear(); + } + + comphelper::LibreOfficeKit::resetCompatFlag(); + + comphelper::LibreOfficeKit::setActive(false); + + UnoApiXmlTest::tearDown(); +} + +ScModelObj* Test::createDoc(const char* pName) +{ + loadFromFile(OUString::createFromAscii(pName)); + + ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(mxComponent); + CPPUNIT_ASSERT(pModelObj); + pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + return pModelObj; +} + +/// A view callback tracks callbacks invoked on one specific view. +class ViewCallback final +{ + SfxViewShell* mpViewShell; + int mnView; + +public: + std::map<std::string, boost::property_tree::ptree> m_aStateChanges; + TestLokCallbackWrapper m_callbackWrapper; + + ViewCallback() + : m_callbackWrapper(&callback, this) + { + mpViewShell = SfxViewShell::Current(); + mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper); + mnView = SfxLokHelper::getView(); + m_callbackWrapper.setLOKViewId(mnView); + } + + ~ViewCallback() + { + if (mpViewShell) + { + SfxLokHelper::setView(mnView); + mpViewShell->setLibreOfficeKitViewCallback(nullptr); + } + } + + static void callback(int nType, const char* pPayload, void* pData) + { + static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload); + } + + void callbackImpl(int nType, const char* pPayload) + { + switch (nType) + { + case LOK_CALLBACK_STATE_CHANGED: + { + std::stringstream aStream(pPayload); + if (!aStream.str().starts_with("{")) + { + break; + } + + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + auto it = aTree.find("commandName"); + if (it == aTree.not_found()) + { + break; + } + + std::string aCommandName = it->second.get_value<std::string>(); + m_aStateChanges[aCommandName] = aTree; + } + break; + } + } +}; + +CPPUNIT_TEST_FIXTURE(Test, testSidebarLocale) +{ + ScModelObj* pModelObj = createDoc("chart.ods"); + int nView1 = SfxLokHelper::getView(); + ViewCallback aView1; + SfxViewShell* pView1 = SfxViewShell::Current(); + pView1->SetLOKLocale("en-US"); + SfxLokHelper::createView(); + ViewCallback aView2; + SfxViewShell* pView2 = SfxViewShell::Current(); + pView2->SetLOKLocale("de-DE"); + TestLokCallbackWrapper::InitializeSidebar(); + Scheduler::ProcessEventsToIdle(); + aView2.m_aStateChanges.clear(); + + pModelObj->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, /*x=*/1, /*y=*/1, /*count=*/2, + /*buttons=*/1, /*modifier=*/0); + pModelObj->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, /*x=*/1, /*y=*/1, /*count=*/2, + /*buttons=*/1, /*modifier=*/0); + SfxLokHelper::setView(nView1); + Scheduler::ProcessEventsToIdle(); + + auto it = aView2.m_aStateChanges.find(".uno:Sidebar"); + CPPUNIT_ASSERT(it != aView2.m_aStateChanges.end()); + std::string aLocale = it->second.get<std::string>("locale"); + CPPUNIT_ASSERT_EQUAL(std::string("de-DE"), aLocale); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 57d7e73789dcc20a67da19766a27e71fddbdb991 Author: Miklos Vajna <[email protected]> AuthorDate: Wed Jan 24 12:17:41 2024 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Jan 25 08:31:09 2024 +0100 cool#8023 editeng: support HTML paste editeng text (e.g. Writer shape text or Calc cell text edit) had working plain text and RTF paste, but HTML paste was not working. This is typically not noticed because desktop paste usually goes via RTF, but it can be visible when a LOK client just puts the best format on the clipboard, i.e. HTML is provided, but RTF is unavailable in the browser and plain text is also not written to the LOK clipboard. Fix the problem by connecting the existing ImpEditEngine::ReadHTML() to the generic ImpEditEngine::PasteText(): this already worked for plain text and RTF, but not for HTML. Note that "SIMPLE_HTML" was already supported, but that's not really HTML but some custom format that contains HTML, and it's claimed that MS IE 4.0 produced this. (cherry picked from commit ce53519f025158f8f64a4e8603c8c6e0dc35473a) Change-Id: Ib41529c66d9bda30cc4ed5faca4a99274ae594d7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162449 Tested-by: Jenkins diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx index b5320f90e448..348bb031d13c 100644 --- a/editeng/qa/unit/core-test.cxx +++ b/editeng/qa/unit/core-test.cxx @@ -34,6 +34,7 @@ #include <editeng/fhgtitem.hxx> #include <com/sun/star/text/textfield/Type.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> #include <memory> #include <editeng/outliner.hxx> @@ -79,6 +80,9 @@ public: /// Test Copy/Paste using Legacy Format void testCopyPaste(); + /// Test Paste using HTML + void testHTMLPaste(); + /// Test Copy/Paste with selective selection over multiple paragraphs void testMultiParaSelCopyPaste(); @@ -125,6 +129,7 @@ public: CPPUNIT_TEST(testAutocorrect); CPPUNIT_TEST(testHyperlinkCopyPaste); CPPUNIT_TEST(testCopyPaste); + CPPUNIT_TEST(testHTMLPaste); CPPUNIT_TEST(testMultiParaSelCopyPaste); CPPUNIT_TEST(testTabsCopyPaste); CPPUNIT_TEST(testHyperlinkSearch); @@ -708,6 +713,62 @@ void Test::testCopyPaste() CPPUNIT_ASSERT_EQUAL( OUString(aText + aText), rDoc.GetParaAsString(sal_Int32(0)) ); } +/// XTransferable implementation that provides simple HTML content. +class TestHTMLTransferable : public cppu::WeakImplHelper<datatransfer::XTransferable> +{ +public: + uno::Any SAL_CALL getTransferData(const datatransfer::DataFlavor& rFlavor) override; + uno::Sequence<datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override; + sal_Bool SAL_CALL isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor) override; +}; + +uno::Any TestHTMLTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor) +{ + if (rFlavor.MimeType != "text/html") + { + return {}; + } + + uno::Any aRet; + SvMemoryStream aStream; + aStream.WriteOString("<!DOCTYPE html> <html><body>test</body></html>"); + aRet <<= uno::Sequence<sal_Int8>(static_cast<const sal_Int8*>(aStream.GetData()), aStream.GetSize()); + return aRet; +} + +uno::Sequence<datatransfer::DataFlavor> TestHTMLTransferable::getTransferDataFlavors() +{ + datatransfer::DataFlavor aFlavor; + aFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get(); + aFlavor.MimeType = "text/html"; + aFlavor.HumanPresentableName = aFlavor.MimeType; + return { aFlavor }; +} + +sal_Bool TestHTMLTransferable::isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor) +{ + return rFlavor.MimeType == "text/html" + && rFlavor.DataType == cppu::UnoType<uno::Sequence<sal_Int8>>::get(); +} + +void Test::testHTMLPaste() +{ + // Given an empty editeng document: + EditEngine aEditEngine(mpItemPool.get()); + EditDoc &rDoc = aEditEngine.GetEditDoc(); + uno::Reference< datatransfer::XTransferable > xData(new TestHTMLTransferable); + + // When trying to paste HTML: + aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true); + + // Then make sure the text gets pasted: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: test + // - Actual : + // i.e. RTF and plain text paste worked, but not HTML. + CPPUNIT_ASSERT_EQUAL(OUString("test"), rDoc.GetParaAsString(static_cast<sal_Int32>(0))); +} + void Test::testMultiParaSelCopyPaste() { // Create EditEngine's instance diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx index 4dbb93ce2c94..260e8dfb5038 100644 --- a/editeng/source/editeng/editeng.cxx +++ b/editeng/source/editeng/editeng.cxx @@ -2795,6 +2795,13 @@ bool EditEngine::HasValidData( const css::uno::Reference< css::datatransfer::XTr datatransfer::DataFlavor aFlavor; SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor ); bValidData = rTransferable->isDataFlavorSupported( aFlavor ); + + if (!bValidData) + { + // Allow HTML-only clipboard, i.e. without plain text. + SotExchange::GetFormatDataFlavor(SotClipboardFormatId::HTML, aFlavor); + bValidData = rTransferable->isDataFlavorSupported(aFlavor); + } } return bValidData; diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx index 4b8f0a63799a..7a5897196715 100644 --- a/editeng/source/editeng/impedit2.cxx +++ b/editeng/source/editeng/impedit2.cxx @@ -3939,7 +3939,7 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransfera } } if (!bDone) { - // HTML + // HTML_SIMPLE SotExchange::GetFormatDataFlavor(SotClipboardFormatId::HTML_SIMPLE, aFlavor); bool bHtmlSupported = rxDataObj->isDataFlavorSupported(aFlavor); if (bHtmlSupported && (SotClipboardFormatId::NONE == format || SotClipboardFormatId::HTML_SIMPLE == format)) { @@ -3963,6 +3963,37 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransfera } } } + + if (!bDone) + { + // HTML + SotExchange::GetFormatDataFlavor(SotClipboardFormatId::HTML, aFlavor); + bool bHtmlSupported = rxDataObj->isDataFlavorSupported(aFlavor); + if (bHtmlSupported + && (format == SotClipboardFormatId::NONE || format == SotClipboardFormatId::HTML)) + { + try + { + uno::Any aData = rxDataObj->getTransferData(aFlavor); + uno::Sequence<sal_Int8> aSeq; + aData >>= aSeq; + SvMemoryStream aHtmlStream(aSeq.getArray(), aSeq.getLength(), StreamMode::READ); + static constexpr OUString aExpectedPrefix = u"<!DOCTYPE html>"_ustr; + OUString aActualPrefix; + aHtmlStream.ReadByteStringLine(aActualPrefix, RTL_TEXTENCODING_UTF8, + aExpectedPrefix.getLength()); + if (aActualPrefix == aExpectedPrefix) + { + aNewSelection = Read(aHtmlStream, rBaseURL, EETextFormat::Html, rPaM); + } + bDone = true; + } + catch (const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("editeng", "HTML paste failed"); + } + } + } } if ( !bDone ) {
