diff options
Diffstat (limited to 'editeng')
-rw-r--r-- | editeng/qa/unit/core-test.cxx | 92 | ||||
-rw-r--r-- | editeng/source/editeng/editeng.cxx | 7 | ||||
-rw-r--r-- | editeng/source/editeng/impedit2.cxx | 26 | ||||
-rw-r--r-- | editeng/source/editeng/impedit4.cxx | 2 | ||||
-rw-r--r-- | editeng/source/misc/acorrcfg.cxx | 7 |
5 files changed, 128 insertions, 6 deletions
diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx index b5320f90e4..8d2a6c11d4 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,12 @@ public: /// Test Copy/Paste using Legacy Format void testCopyPaste(); + /// Test Paste using HTML + void testHTMLPaste(); + + /// Test Paste using an HTML fragment + void testHTMLFragmentPaste(); + /// Test Copy/Paste with selective selection over multiple paragraphs void testMultiParaSelCopyPaste(); @@ -125,6 +132,8 @@ public: CPPUNIT_TEST(testAutocorrect); CPPUNIT_TEST(testHyperlinkCopyPaste); CPPUNIT_TEST(testCopyPaste); + CPPUNIT_TEST(testHTMLPaste); + CPPUNIT_TEST(testHTMLFragmentPaste); CPPUNIT_TEST(testMultiParaSelCopyPaste); CPPUNIT_TEST(testTabsCopyPaste); CPPUNIT_TEST(testHyperlinkSearch); @@ -708,6 +717,89 @@ 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> +{ + OString m_aHTML; +public: + TestHTMLTransferable(const OString& rHTML); + 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; +}; + +TestHTMLTransferable::TestHTMLTransferable(const OString& rHTML) + : m_aHTML(rHTML) +{ +} + +uno::Any TestHTMLTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor) +{ + if (rFlavor.MimeType != "text/html") + { + return {}; + } + + uno::Any aRet; + SvMemoryStream aStream; + aStream.WriteOString(m_aHTML); + 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(); + OString aHTML("<!DOCTYPE html>\n<html><body>test</body></html>"_ostr); + uno::Reference< datatransfer::XTransferable > xData(new TestHTMLTransferable(aHTML)); + + // 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::testHTMLFragmentPaste() +{ + // Given an empty editeng document: + EditEngine aEditEngine(mpItemPool.get()); + EditDoc &rDoc = aEditEngine.GetEditDoc(); + OString aHTML("a<b>b</b>c"_ostr); + uno::Reference< datatransfer::XTransferable > xData(new TestHTMLTransferable(aHTML)); + + // When trying to paste an HTML fragment: + 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: abc + // - Actual : + // i.e. a HTML fragment without a proper header was ignored on paste. + CPPUNIT_ASSERT_EQUAL(OUString("abc"), 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 4dbb93ce2c..260e8dfb50 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 4b8f0a6379..40f111b72e 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,30 @@ 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); + aNewSelection = Read(aHtmlStream, rBaseURL, EETextFormat::Html, rPaM); + bDone = true; + } + catch (const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("editeng", "HTML paste failed"); + } + } + } } if ( !bDone ) { diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx index 57b3d65c54..3bf44cdb91 100644 --- a/editeng/source/editeng/impedit4.cxx +++ b/editeng/source/editeng/impedit4.cxx @@ -905,7 +905,7 @@ void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, break; case EE_FEATURE_LINEBR: { - rOutput.WriteOString( OOO_STRING_SVTOOLS_RTF_SL ); + rOutput.WriteOString( OOO_STRING_SVTOOLS_RTF_LINE ); } break; case EE_CHAR_KERNING: diff --git a/editeng/source/misc/acorrcfg.cxx b/editeng/source/misc/acorrcfg.cxx index 616d75c696..49e48bb48b 100644 --- a/editeng/source/misc/acorrcfg.cxx +++ b/editeng/source/misc/acorrcfg.cxx @@ -65,13 +65,12 @@ static void scanAutoCorrectDirForLanguageTags( const OUString& rURL ) continue; const OUString aBcp47( aTitle.copy( 5, aTitle.getLength() - 9)); - OUString aCanonicalized; // Ignore invalid langtags and canonicalize for good, // allow private-use tags. - if (!LanguageTag::isValidBcp47( aBcp47, &aCanonicalized)) + const LanguageTag aLanguageTag (aBcp47, true); + if (!aLanguageTag.isValidBcp47()) continue; - const LanguageTag aLanguageTag( aCanonicalized); if (SvtLanguageTable::HasLanguageType( aLanguageTag.getLanguageType())) continue; @@ -83,7 +82,7 @@ static void scanAutoCorrectDirForLanguageTags( const OUString& rURL ) // other private-use tag (which should not fallback, // but avoid). if (aLanguageTag.getCountry().isEmpty() - && LanguageTag::isValidBcp47( aCanonicalized, nullptr, + && LanguageTag::isValidBcp47( aLanguageTag.getBcp47(), nullptr, LanguageTag::PrivateUse::DISALLOW)) { LanguageTag aFallback( aLanguageTag); |