writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx | 34 ++++++++ writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx |binary writerfilter/source/dmapper/DomainMapper.cxx | 18 +++- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 38 ++++++++++ writerfilter/source/dmapper/DomainMapper_Impl.hxx | 8 ++ writerfilter/source/ooxml/Handler.cxx | 9 ++ writerfilter/source/ooxml/Handler.hxx | 3 writerfilter/source/ooxml/OOXMLFastContextHandler.cxx | 2 writerfilter/source/ooxml/OOXMLParserState.cxx | 2 9 files changed, 106 insertions(+), 8 deletions(-)
New commits: commit 4a65bd82fdca12171319b07adf9de6f1d4a24913 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Mar 8 08:42:44 2022 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Mar 29 08:47:22 2022 +0200 sw clearing breaks: add DOCX import Map <w:br w:clear="..."> to the com.sun.star.text.LineBreak UNO service, but keep the default clear=none case unchanged. (cherry picked from commit f86d1482bef285f90079b5130e410646db96cf58) Change-Id: I145e891c1df0bbd0fdac2c62463dc801bca827fb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132165 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx index 962aa63f9ebc..3012ab8d0e2f 100644 --- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx @@ -284,6 +284,40 @@ CPPUNIT_TEST_FIXTURE(Test, testPasteOle) uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(OUString("hello"), xPara->getString()); } + +CPPUNIT_TEST_FIXTURE(Test, testClearingBreak) +{ + // Given a document with a clearing break: + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "clearing-break.docx"; + + // When loading that file: + getComponent() = loadFromDesktop(aURL); + + // Then make sure that the clear property of the break is not ignored: + uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xText, uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParagraphs = xParaEnumAccess->createEnumeration(); + uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration(); + xPortions->nextElement(); + xPortions->nextElement(); + // Without the accompanying fix in place, this test would have failed with: + // An uncaught exception of type com.sun.star.container.NoSuchElementException + // i.e. the first para was just a fly + text portion, the clearing break was lost. + uno::Reference<beans::XPropertySet> xPortion(xPortions->nextElement(), uno::UNO_QUERY); + OUString aPortionType; + xPortion->getPropertyValue("TextPortionType") >>= aPortionType; + CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aPortionType); + uno::Reference<text::XTextContent> xLineBreak; + xPortion->getPropertyValue("LineBreak") >>= xLineBreak; + sal_Int16 eClear{}; + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + xLineBreakProps->getPropertyValue("Clear") >>= eClear; + // SwLineBreakClear::ALL + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(3), eClear); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx b/writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx new file mode 100644 index 000000000000..453a4c2b83d1 Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx differ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index ffa829351baa..16814d850ae1 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -749,9 +749,12 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) case NS_ooxml::LN_CT_SmartTagRun_element: m_pImpl->getSmartTagHandler().setElement(val.getString()); break; - case NS_ooxml::LN_CT_Br_type : - //TODO: attributes for break (0x12) are not supported - break; + case NS_ooxml::LN_CT_Br_type: + // Handled in the OOXMLBreakHandler dtor. + break; + case NS_ooxml::LN_CT_Br_clear: + m_pImpl->HandleLineBreakClear(val.getInt()); + break; case NS_ooxml::LN_CT_Fonts_hint : /* assigns script type to ambiguous characters, values can be: NS_ooxml::LN_Value_ST_Hint_default @@ -3460,7 +3463,14 @@ void DomainMapper::lcl_text(const sal_uInt8 * data_, size_t len) if (pContext == nullptr) pContext = new PropertyMap(); - m_pImpl->appendTextPortion( sText, pContext ); + if (sText == "\n") + { + m_pImpl->HandleLineBreak(pContext); + } + else + { + m_pImpl->appendTextPortion(sText, pContext); + } } } catch( const uno::RuntimeException& ) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 8afcede51d13..8ab4e9b65235 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -4002,6 +4002,44 @@ void DomainMapper_Impl::HandlePTab(sal_Int32 nAlignment) xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::LINE_BREAK, true); } +void DomainMapper_Impl::HandleLineBreakClear(sal_Int32 nClear) +{ + switch (nClear) + { + case NS_ooxml::LN_Value_ST_BrClear_left: + // SwLineBreakClear::LEFT + m_oLineBreakClear = 1; + break; + case NS_ooxml::LN_Value_ST_BrClear_right: + // SwLineBreakClear::RIGHT + m_oLineBreakClear = 2; + break; + case NS_ooxml::LN_Value_ST_BrClear_all: + // SwLineBreakClear::ALL + m_oLineBreakClear = 3; + break; + } +} + +void DomainMapper_Impl::HandleLineBreak(const PropertyMapPtr& pPropertyMap) +{ + if (!m_oLineBreakClear.has_value()) + { + appendTextPortion("\n", pPropertyMap); + return; + } + + if (GetTextFactory().is()) + { + uno::Reference<text::XTextContent> xLineBreak( + GetTextFactory()->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + xLineBreakProps->setPropertyValue("Clear", uno::makeAny(*m_oLineBreakClear)); + appendTextContent(xLineBreak, pPropertyMap->GetPropertyValues()); + } + m_oLineBreakClear.reset(); +} + static sal_Int16 lcl_ParseNumberingType( const OUString& rCommand ) { sal_Int16 nRet = style::NumberingType::PAGE_DESCRIPTOR; diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index bb37c556ebc6..3b5827aff7ae 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -627,6 +627,8 @@ private: bool m_bIsNewDoc; bool m_bIsAltChunk = false; bool m_bIsReadGlossaries; + std::optional<sal_Int16> m_oLineBreakClear; + public: DomainMapper_Impl( DomainMapper& rDMapper, @@ -1159,6 +1161,12 @@ public: /// Handles <w:ptab>. void HandlePTab(sal_Int32 nAlignment); + /// Handles <w:br w:clear="...">. + void HandleLineBreakClear(sal_Int32 nClear); + + /// Handles <w:br>. + void HandleLineBreak(const PropertyMapPtr& pPropertyMap); + void commentProps(const OUString& sId, const CommentProperties& rProps); private: diff --git a/writerfilter/source/ooxml/Handler.cxx b/writerfilter/source/ooxml/Handler.cxx index d58453c8ee32..7cbd9b6bfdc3 100644 --- a/writerfilter/source/ooxml/Handler.cxx +++ b/writerfilter/source/ooxml/Handler.cxx @@ -236,14 +236,21 @@ void OOXMLHeaderHandler::sprm(Sprm & /*sprm*/) /* class OOXMLBreakHandler */ -OOXMLBreakHandler::OOXMLBreakHandler(Stream &rStream) +OOXMLBreakHandler::OOXMLBreakHandler(OOXMLFastContextHandler* pContext, Stream &rStream) : mnType(0), + mpFastContext(pContext), mrStream(rStream) { } OOXMLBreakHandler::~OOXMLBreakHandler() { + if (mpFastContext) + { + mrStream.props(mpFastContext->getPropertySet().get()); + mpFastContext->clearProps(); + } + sal_uInt8 tmpBreak[1]; switch (mnType) { diff --git a/writerfilter/source/ooxml/Handler.hxx b/writerfilter/source/ooxml/Handler.hxx index 42ea025538f0..df6673d44318 100644 --- a/writerfilter/source/ooxml/Handler.hxx +++ b/writerfilter/source/ooxml/Handler.hxx @@ -111,10 +111,11 @@ public: class OOXMLBreakHandler : public Properties { sal_Int32 mnType; + OOXMLFastContextHandler* mpFastContext; Stream& mrStream; public: - explicit OOXMLBreakHandler(Stream& rStream); + explicit OOXMLBreakHandler(OOXMLFastContextHandler* pContext, Stream& rStream); virtual ~OOXMLBreakHandler() override; virtual void attribute(Id name, Value& val) override; virtual void sprm(Sprm& sprm) override; diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx index 773451d5dc87..a915380fc203 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -1117,7 +1117,7 @@ void OOXMLFastContextHandlerProperties::handleBreak() { if(isForwardEvents()) { - OOXMLBreakHandler aBreakHandler(*mpStream); + OOXMLBreakHandler aBreakHandler(this, *mpStream); getPropertySet()->resolve(aBreakHandler); } } diff --git a/writerfilter/source/ooxml/OOXMLParserState.cxx b/writerfilter/source/ooxml/OOXMLParserState.cxx index 3d35cbb9deac..a11afde8fb37 100644 --- a/writerfilter/source/ooxml/OOXMLParserState.cxx +++ b/writerfilter/source/ooxml/OOXMLParserState.cxx @@ -212,7 +212,7 @@ void OOXMLParserState::resolvePostponedBreak(Stream & rStream) { for (const auto & rBreak: mvPostponedBreaks) { - OOXMLBreakHandler aBreakHandler(rStream); + OOXMLBreakHandler aBreakHandler(nullptr, rStream); rBreak->resolve(aBreakHandler); } mvPostponedBreaks.clear();