writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx |   26 ++++++
 writerfilter/qa/cppunittests/dmapper/data/ptab.docx        |binary
 writerfilter/source/dmapper/DomainMapper.cxx               |    2 
 writerfilter/source/dmapper/DomainMapper_Impl.cxx          |   56 +++++++++++++
 writerfilter/source/dmapper/DomainMapper_Impl.hxx          |    3 
 5 files changed, 87 insertions(+)

New commits:
commit 8bac48991857d222f0e8f0c07b8c4e06649e1632
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Jan 28 13:38:20 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Jan 28 19:15:37 2022 +0100

    DOCX import: handle a subset of <w:ptab w:alignment="left">
    
    The case when we can map it to a line break. This way the page number is
    visually inside the rectangle shape that is behind the field.
    
    The test intentionally uses \n as-is for line-break, because
    SwASCWriter::WriteStream() uses \n in the LINEEND_LF case even on
    Windows (and not SAL_NEWLINE_STRING), while SAL_NEWLINE_STRING is used
    for paragraph-break.
    
    Change-Id: Ic85e57b2391bfac73507727b17240f4d85fc2698
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129059
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
index 3719a09e3323..c0468d9d55cc 100644
--- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
@@ -19,6 +19,7 @@
 #include <com/sun/star/text/XTextTablesSupplier.hpp>
 #include <com/sun/star/text/XTextTable.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
 
 #include <vcl/scheduler.hxx>
 
@@ -230,6 +231,31 @@ CPPUNIT_TEST_FIXTURE(Test, testChartZOrder)
     // of the shape.
     
CPPUNIT_ASSERT(xChart->supportsService("com.sun.star.text.TextEmbeddedObject"));
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testPTab)
+{
+    // Given a document that has a <w:ptab> to render a linebreak:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "ptab.docx";
+
+    // When opening that file:
+    getComponent() = loadFromDesktop(aURL);
+
+    // Then make sure that the Writer doc model contains that linebreak:
+    uno::Reference<style::XStyleFamiliesSupplier> 
xStyleFamiliesSupplier(getComponent(),
+                                                                         
uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> xStyleFamilies
+        = xStyleFamiliesSupplier->getStyleFamilies();
+    uno::Reference<container::XNameAccess> 
xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+                                                        uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> 
xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY);
+    auto xFooter = 
xStyle->getPropertyValue("FooterText").get<uno::Reference<text::XTextRange>>();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: <space><newline>1\n
+    // - Actual:   <space><tab>1\n
+    // i.e. the layout height of the footer text was incorrect, the page 
number field was not
+    // visually inside the background shape.
+    CPPUNIT_ASSERT_EQUAL(OUString(" \n1" SAL_NEWLINE_STRING), 
xFooter->getString());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/data/ptab.docx 
b/writerfilter/qa/cppunittests/dmapper/data/ptab.docx
new file mode 100644
index 000000000000..d1ae18a27a55
Binary files /dev/null and 
b/writerfilter/qa/cppunittests/dmapper/data/ptab.docx differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index e8b5a3f40e5b..6a18d8d12da0 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1167,7 +1167,9 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
             break;
         case NS_ooxml::LN_CT_PTab_leader:
         case NS_ooxml::LN_CT_PTab_relativeTo:
+            break;
         case NS_ooxml::LN_CT_PTab_alignment:
+            m_pImpl->HandlePTab(nIntValue);
             break;
         case NS_ooxml::LN_CT_Cnf_lastRowLastColumn:
             m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, 
"lastRowLastColumn", OUString::number(nIntValue));
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index f0902918e0ff..952d225f52f7 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -3868,6 +3868,62 @@ void DomainMapper_Impl::HandleAltChunk(const OUString& 
rStreamName)
     }
 }
 
+void DomainMapper_Impl::HandlePTab(sal_Int32 nAlignment)
+{
+    // We only handle the case when the line already has content, so the 
left-aligned ptab is
+    // equivalent to a line break.
+    if (nAlignment != NS_ooxml::LN_Value_ST_PTabAlignment_left)
+    {
+        return;
+    }
+
+    if (m_aTextAppendStack.empty())
+    {
+        return;
+    }
+
+    uno::Reference<text::XTextAppend> xTextAppend = 
m_aTextAppendStack.top().xTextAppend;
+    if (!xTextAppend.is())
+    {
+        return;
+    }
+
+    uno::Reference<css::text::XTextRange> xInsertPosition
+        = m_aTextAppendStack.top().xInsertPosition;
+    if (!xInsertPosition.is())
+    {
+        xInsertPosition = xTextAppend->getEnd();
+    }
+    uno::Reference<text::XTextCursor> xCursor
+        = xTextAppend->createTextCursorByRange(xInsertPosition);
+
+    // Assume that we just inserted a tab character.
+    xCursor->goLeft(1, true);
+    if (xCursor->getString() != "\t")
+    {
+        return;
+    }
+
+    // Assume that there is some content before the tab character.
+    uno::Reference<text::XParagraphCursor> xParagraphCursor(xCursor, 
uno::UNO_QUERY);
+    if (!xParagraphCursor.is())
+    {
+        return;
+    }
+
+    xCursor->collapseToStart();
+    xParagraphCursor->gotoStartOfParagraph(true);
+    if (xCursor->isCollapsed())
+    {
+        return;
+    }
+
+    // Then select the tab again and replace with a line break.
+    xCursor->collapseToEnd();
+    xCursor->goRight(1, true);
+    xTextAppend->insertControlCharacter(xCursor, 
text::ControlCharacter::LINE_BREAK, true);
+}
+
 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 7238d129f766..7ede5cb2f91d 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -1164,6 +1164,9 @@ public:
     /// Handles <w:altChunk>.
     void HandleAltChunk(const OUString& rStreamName);
 
+    /// Handles <w:ptab>.
+    void HandlePTab(sal_Int32 nAlignment);
+
     void commentProps(const OUString& sId, const CommentProperties& rProps);
 
 private:

Reply via email to