summaryrefslogtreecommitdiff
path: root/writerfilter
diff options
context:
space:
mode:
Diffstat (limited to 'writerfilter')
-rw-r--r--writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx54
-rw-r--r--writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx22
-rw-r--r--writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx21
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docxbin0 -> 12900 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf30
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/ptab.docxbin0 -> 15861 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docxbin0 -> 12648 bytes
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx75
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableManager.cxx10
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx345
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.hxx12
-rw-r--r--writerfilter/source/dmapper/GraphicImport.cxx23
-rw-r--r--writerfilter/source/dmapper/GraphicImport.hxx2
-rw-r--r--writerfilter/source/dmapper/NumberingManager.cxx9
-rw-r--r--writerfilter/source/dmapper/PropertyIds.cxx1
-rw-r--r--writerfilter/source/dmapper/PropertyIds.hxx1
-rw-r--r--writerfilter/source/dmapper/PropertyMap.cxx43
-rw-r--r--writerfilter/source/dmapper/PropertyMap.hxx3
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx23
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx3
-rw-r--r--writerfilter/source/dmapper/SettingsTable.cxx6
-rw-r--r--writerfilter/source/dmapper/StyleSheetTable.cxx14
-rw-r--r--writerfilter/source/filter/WriterFilter.cxx1
-rw-r--r--writerfilter/source/rtftok/rtfcharsets.cxx9
-rw-r--r--writerfilter/source/rtftok/rtfcharsets.hxx13
-rw-r--r--writerfilter/source/rtftok/rtfdispatchflag.cxx13
-rw-r--r--writerfilter/source/rtftok/rtfdispatchvalue.cxx149
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.cxx194
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.hxx4
-rw-r--r--writerfilter/source/rtftok/rtfsprm.cxx14
30 files changed, 781 insertions, 313 deletions
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
index 3719a09e3323..962aa63f9ebc 100644
--- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
@@ -19,6 +19,8 @@
#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 <com/sun/star/document/XDocumentInsertable.hpp>
#include <vcl/scheduler.hxx>
@@ -230,6 +232,58 @@ 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());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testPasteOle)
+{
+ // Given an empty document:
+ getComponent() = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+
+ // When pasting RTF into that document:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<document::XDocumentInsertable> xCursor(
+ xText->createTextCursorByRange(xText->getStart()), uno::UNO_QUERY);
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "paste-ole.rtf";
+ xCursor->insertDocumentFromURL(aURL, {});
+
+ // Then make sure that all the 3 paragraphs of the paste data (empty para, OLE obj, text) are
+ // inserted to the document:
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ xParaEnum->nextElement();
+ // Without the accompanying fix in place, this test would have failed, as the paste result was a
+ // single paragaph, containing the OLE object, and the content after the OLE object was lost.
+ CPPUNIT_ASSERT(xParaEnum->hasMoreElements());
+ xParaEnum->nextElement();
+ CPPUNIT_ASSERT(xParaEnum->hasMoreElements());
+ uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("hello"), xPara->getString());
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
index edd6e02ff8ea..2f9faefab55f 100644
--- a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
@@ -366,6 +366,28 @@ CPPUNIT_TEST_FIXTURE(Test, testTextboxTextlineTop)
sal_Int16 nExpectedOrient = text::VertOrientation::BOTTOM;
CPPUNIT_ASSERT_EQUAL(nExpectedOrient, nActualOrient);
}
+
+CPPUNIT_TEST_FIXTURE(Test, testLayoutInCellWrapnoneColumn)
+{
+ // Given a file with a table, then a shape anchored inside the cell:
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "layout-in-cell-wrapnone-column.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the shape can leave the cell:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xNamedShape(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Text Box 1"), xNamedShape->getName());
+ bool bFollowingTextFlow = true;
+ // Without the accompanying fix in place, this test would have failed, the shape was not allowed
+ // to leave the cell, leading to incorrect layout.
+ CPPUNIT_ASSERT(xShape->getPropertyValue("IsFollowingTextFlow") >>= bFollowingTextFlow);
+ CPPUNIT_ASSERT(!bFollowingTextFlow);
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx
index 7b552af94bb0..ae32ce1e4dc7 100644
--- a/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx
@@ -15,6 +15,7 @@
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
using namespace ::com::sun::star;
@@ -87,6 +88,26 @@ CPPUNIT_TEST_FIXTURE(Test, testFollowPageTopMargin)
// i.e. the top margin on page 2 was too large.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(250), nTopMargin);
}
+
+CPPUNIT_TEST_FIXTURE(Test, testTableNegativeVerticalPos)
+{
+ // Given a document with a table which has a negative vertical position (moves up to overlap
+ // with the header):
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "table-negative-vertical-pos.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure we don't import that as a plain table, which can't have a negative top margin:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. this was imported as a plain table, resulting in a 0 top margin (y pos too large).
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xDrawPage->getCount());
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docx b/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docx
new file mode 100644
index 000000000000..d88761421154
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf b/writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf
new file mode 100644
index 000000000000..27ce59baa50b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf
@@ -0,0 +1,30 @@
+{\rtf1
+\pard\plain\par
+\pard\plain
+{\object\objemb\objw1287\objh832\objscalex100\objscaley99
+{\*\objclass Package}
+{\*\objdata 0105000002000000080000005061636b616765000000000000000000eb010000
+020030322e73766700443a5c446e445c54657374646174656e5c416c6c654461746569547970656e5c30322e737667000000030036000000443a5c54454d505c7b42433241443335362d363732422d344345302d394136342d3033373544464134324334377d5c30322e73766700ab0000003c7376672076657273696f6e
+3d22312e31222076696577426f783d223020302034342032362220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667223e0a203c7265637420783d222e352220793d222e35222077696474683d22343322206865696768743d223235222072783d2232222072793d2232222066696c6c3d
+222366666622207374726f6b653d2223303037616666222f3e0a3c2f7376673e0a3500000044003a005c00540045004d0050005c007b00420043003200410044003300350036002d0036003700320042002d0034004300450030002d0039004100360034002d003000330037003500440046004100340032004300340037
+007d005c00300032002e0073007600670006000000300032002e007300760067002600000044003a005c0044006e0044005c00540065007300740064006100740065006e005c0041006c006c0065004400610074006500690054007900700065006e005c00300032002e007300760067000105000000000000}
+{\result
+{\*\shppict
+{\pict
+\picscalex100\picscaley99\picw2270\pich1468\picwgoal1287\pichgoal832\emfblip
+010000006c00000000000000000000009500000095000000000000000000
+0000670f0000630f000020454d4600000100280100000700000002000000
+00000000000000000000000038070000bd030000e9010000fd0000000000
+00000000000000000000f675070016dd0300210000000800000062000000
+0c0000000100000027000000180000000100000000000000ff0000000000
+000047000000700000000000000000000000950000009500000050000000
+010000002000000001000000030000003000000000000000000000009600
+000096000000320000000000000064000000320000000000000032000000
+960000006400000032000000640000006400000096000000220000000c00
+0000ffffffff0e00000014000000000000001000000014000000}
+}
+}
+}
+\pard\plain\par
+\pard\plain hello\par
+}
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
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/ptab.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docx b/writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docx
new file mode 100644
index 000000000000..2031f4769877
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docx
Binary files differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index b5e08cfe5bc9..99fb28fda05f 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -372,19 +372,14 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
if (m_pImpl->GetTopContext())
{
m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, uno::makeAny( sStringValue ));
- if (m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH) && m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->isSet(PROP_NUMBERING_RULES))
- {
- // Font of the paragraph mark should be used for the numbering as well.
- uno::Reference<beans::XPropertySet> xCharStyle(m_pImpl->GetCurrentNumberingCharStyle());
- if (xCharStyle.is())
- xCharStyle->setPropertyValue("CharFontName", uno::makeAny(sStringValue));
- }
}
break;
case NS_ooxml::LN_CT_Fonts_asciiTheme:
m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "asciiTheme", ThemeTable::getStringForTheme(nIntValue));
if (m_pImpl->GetTopContext())
{
+ // note: overwrite Fonts_ascii with Fonts_asciiTheme *even if*
+ // theme font is empty - this is apparently what Word 2013 does
uno::Any aPropValue = uno::makeAny( m_pImpl->GetThemeTable()->getFontNameForTheme( nIntValue ) );
m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, aPropValue );
m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_ASCII, aPropValue, true, CHAR_GRAB_BAG );
@@ -1167,7 +1162,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));
@@ -1468,7 +1465,16 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
eBorderDistId = PROP_RIGHT_BORDER_DISTANCE ;
break;
case NS_ooxml::LN_CT_PBdr_between:
- //not supported
+ if (m_pImpl->handlePreviousParagraphBorderInBetween())
+ {
+ // If previous paragraph also had border in between property
+ // then it is possible to emulate this border as top border
+ // for current paragraph
+ eBorderId = PROP_TOP_BORDER;
+ eBorderDistId = PROP_TOP_BORDER_DISTANCE;
+ }
+ // Since there are borders in between, each paragraph will have own borders. No more joining
+ rContext->Insert(PROP_PARA_CONNECT_BORDERS, uno::makeAny(false));
break;
default:;
}
@@ -1779,9 +1785,6 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
if( nSprmId != NS_ooxml::LN_EG_RPrBase_bCs )
rContext->Insert(PROP_CHAR_WEIGHT_ASIAN, aBold );
- uno::Reference<beans::XPropertySet> xCharStyle(m_pImpl->GetCurrentNumberingCharStyle());
- if (xCharStyle.is())
- xCharStyle->setPropertyValue(getPropertyName(PROP_CHAR_WEIGHT), aBold);
if (nSprmId == NS_ooxml::LN_EG_RPrBase_b)
m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "b", OUString::number(nIntValue));
else if (nSprmId == NS_ooxml::LN_EG_RPrBase_bCs)
@@ -1859,10 +1862,6 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
//Asian get the same value as Western
rContext->Insert( PROP_CHAR_HEIGHT, aVal );
rContext->Insert( PROP_CHAR_HEIGHT_ASIAN, aVal );
-
- uno::Reference<beans::XPropertySet> xCharStyle(m_pImpl->GetCurrentNumberingCharStyle());
- if (xCharStyle.is())
- xCharStyle->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT), aVal);
}
m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, (nSprmId == NS_ooxml::LN_EG_RPrBase_sz ? OUString("sz") : OUString("szCs")), OUString::number(nIntValue));
}
@@ -3223,6 +3222,18 @@ void DomainMapper::lcl_startParagraphGroup()
void DomainMapper::lcl_endParagraphGroup()
{
+ if (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ if (m_pImpl->GetIsLastParagraphInSection())
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+ }
+
m_pImpl->PopProperties(CONTEXT_PARAGRAPH);
if (m_pImpl->hasTableManager())
m_pImpl->getTableManager().endParagraphGroup();
@@ -3372,6 +3383,13 @@ void DomainMapper::lcl_text(const sal_uInt8 * data_, size_t len)
case 0x0e: //column break
m_pImpl->deferBreak(COLUMN_BREAK);
return;
+ case 0x0a: //line break
+ if (m_pImpl->GetIsLastParagraphInSection())
+ {
+ m_pImpl->deferBreak(LINE_BREAK);
+ return;
+ }
+ break;
case 0x07:
m_pImpl->getTableManager().text(data_, len);
return;
@@ -3404,6 +3422,13 @@ void DomainMapper::lcl_text(const sal_uInt8 * data_, size_t len)
// GetTopContext() is changed by inserted breaks, but we want to keep the current context
PropertyMapPtr pContext = m_pImpl->GetTopContext();
+
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", pContext);
+ }
+
if (!m_pImpl->GetFootnoteContext())
{
if (m_pImpl->isBreakDeferred(PAGE_BREAK))
@@ -3627,6 +3652,18 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
m_pImpl->m_bHasFtnSep = true;
return;
}
+ else if (len == 1 && sText[0] == '\r')
+ {
+ // Clear "last" one linebreak at end of section
+ if (m_pImpl->GetIsLastParagraphInSection() && m_pImpl->isBreakDeferred(LINE_BREAK))
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ // And emit all other linebreaks
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+ }
else if (len == 1 && sText[0] == '\t' )
{
if ( m_pImpl->m_bCheckFirstFootnoteTab && m_pImpl->IsInFootOrEndnote() )
@@ -3657,6 +3694,12 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
try
{
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+
m_pImpl->getTableManager().utext(data_, len);
if (bNewLine)
@@ -3722,10 +3765,10 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
static_cast<ParagraphPropertyMap*>(xContext.get())->SetListId(-1);;
xContext->Erase(PROP_NUMBERING_LEVEL);
}
- m_pImpl->SetParaSectpr(false);
finishParagraph(bRemove, bNoNumbering);
if (bRemove)
m_pImpl->RemoveLastParagraph();
+ m_pImpl->SetParaSectpr(false);
}
else
{
diff --git a/writerfilter/source/dmapper/DomainMapperTableManager.cxx b/writerfilter/source/dmapper/DomainMapperTableManager.cxx
index f0b692783a44..c3e44542d5f7 100644
--- a/writerfilter/source/dmapper/DomainMapperTableManager.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableManager.cxx
@@ -387,6 +387,8 @@ bool DomainMapperTableManager::sprm(Sprm & rSprm)
DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentGrid( )
{
+ if (m_aTableGrid.empty())
+ throw std::out_of_range("no current grid");
return m_aTableGrid.back( );
}
@@ -551,6 +553,8 @@ void DomainMapperTableManager::endOfRowAction()
// Compare the table position and style with the previous ones. We may need to split
// into two tables if those are different. We surely don't want to do anything
// if we don't have any row yet.
+ if (m_aTmpPosition.empty())
+ throw std::out_of_range("row without a position");
TablePositionHandlerPtr pTmpPosition = m_aTmpPosition.back();
TablePropertyMapPtr pTablePropMap = m_aTmpTableProperties.back( );
TablePositionHandlerPtr pCurrentPosition = m_aTablePositions.back();
@@ -793,9 +797,6 @@ void DomainMapperTableManager::endOfRowAction()
size_t nWidthsBound = pCellWidths->size() - 1;
if (nWidthsBound)
{
- if (nFullWidthRelative == 0)
- throw o3tl::divide_by_zero();
-
// At incomplete table grids, last cell width can be smaller, than its final width.
// Correct it based on the last but one column width and their span values.
if ( bIsIncompleteGrid && rCurrentSpans.size()-1 == nWidthsBound )
@@ -806,6 +807,9 @@ void DomainMapperTableManager::endOfRowAction()
nFullWidthRelative += nFixLastCellWidth - (*pCellWidths)[nWidthsBound];
}
+ if (nFullWidthRelative == 0)
+ throw o3tl::divide_by_zero();
+
for (size_t i = 0; i < nWidthsBound; ++i)
{
nSum += (*pCellWidths)[i];
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 19868ae74d78..4c0c79085273 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -183,6 +183,45 @@ static void lcl_handleTextField( const uno::Reference< beans::XPropertySet >& rx
}
}
+/**
+ Very similar to DomainMapper_Impl::GetPropertyFromStyleSheet
+ It is focused on paragraph properties search in current & parent stylesheet entries.
+ But it will not take into account propeties with listid: these are "list paragraph styles" and
+ not used in some cases.
+*/
+static uno::Any lcl_GetPropertyFromParaStyleSheetNoNum(PropertyIds eId, StyleSheetEntryPtr pEntry, const StyleSheetTablePtr& rStyleSheet)
+{
+ while (pEntry)
+ {
+ if (pEntry->pProperties)
+ {
+ std::optional<PropertyMap::Property> aProperty =
+ pEntry->pProperties->getProperty(eId);
+ if (aProperty)
+ {
+ if (pEntry->pProperties->GetListId())
+ // It is a paragraph style with list. Paragraph list styles are not taken into account
+ return uno::Any();
+ else
+ return aProperty->second;
+ }
+ }
+ //search until the property is set or no parent is available
+ StyleSheetEntryPtr pNewEntry;
+ if (!pEntry->sBaseStyleIdentifier.isEmpty())
+ pNewEntry = rStyleSheet->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
+
+ SAL_WARN_IF(pEntry == pNewEntry, "writerfilter.dmapper", "circular loop in style hierarchy?");
+
+ if (pEntry == pNewEntry) //fdo#49587
+ break;
+
+ pEntry = pNewEntry;
+ }
+ return uno::Any();
+}
+
+
namespace {
struct FieldConversion
@@ -286,6 +325,7 @@ DomainMapper_Impl::DomainMapper_Impl(
m_bIsFirstSection( true ),
m_bIsColumnBreakDeferred( false ),
m_bIsPageBreakDeferred( false ),
+ m_nLineBreaksDeferred( 0 ),
m_bSdtEndDeferred(false),
m_bParaSdtEndDeferred(false),
m_bStartTOC(false),
@@ -676,6 +716,14 @@ void DomainMapper_Impl::RemoveLastParagraph( )
// delete
xCursor->setString(OUString());
+ // While removing paragraphs that contain section properties, reset list
+ // related attributes to prevent them leaking into the following section's lists
+ if (GetParaSectpr())
+ {
+ uno::Reference<beans::XPropertySet> XCursorProps(xCursor, uno::UNO_QUERY);
+ XCursorProps->setPropertyValue("ResetParagraphListAttributes", uno::Any());
+ }
+
// call to xCursor->setString possibly did remove final bookmark
// from previous paragraph. We need to restore it, if there was any.
if (sLastBookmarkName.getLength())
@@ -1113,9 +1161,12 @@ void DomainMapper_Impl::deferBreak( BreakType deferredBreakType)
{
switch (deferredBreakType)
{
- case COLUMN_BREAK:
- m_bIsColumnBreakDeferred = true;
+ case LINE_BREAK:
+ m_nLineBreaksDeferred++;
break;
+ case COLUMN_BREAK:
+ m_bIsColumnBreakDeferred = true;
+ break;
case PAGE_BREAK:
// See SwWW8ImplReader::HandlePageBreakChar(), page break should be
// ignored inside tables.
@@ -1133,6 +1184,8 @@ bool DomainMapper_Impl::isBreakDeferred( BreakType deferredBreakType )
{
switch (deferredBreakType)
{
+ case LINE_BREAK:
+ return m_nLineBreaksDeferred > 0;
case COLUMN_BREAK:
return m_bIsColumnBreakDeferred;
case PAGE_BREAK:
@@ -1146,6 +1199,10 @@ void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType)
{
switch (deferredBreakType)
{
+ case LINE_BREAK:
+ assert(m_nLineBreaksDeferred > 0);
+ m_nLineBreaksDeferred--;
+ break;
case COLUMN_BREAK:
m_bIsColumnBreakDeferred = false;
break;
@@ -1159,6 +1216,7 @@ void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType)
void DomainMapper_Impl::clearDeferredBreaks()
{
+ m_nLineBreaksDeferred = 0;
m_bIsColumnBreakDeferred = false;
m_bIsPageBreakDeferred = false;
}
@@ -1733,6 +1791,10 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con
if (nParaLeftMargin != 0)
pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::makeAny(nParaLeftMargin), /*bOverwrite=*/false);
+ // Override right margin value with value from current style, if any
+ if (pStyleSheetProperties && pStyleSheetProperties->isSet(PROP_PARA_RIGHT_MARGIN))
+ nParaRightMargin = pStyleSheetProperties->getProperty(PROP_PARA_RIGHT_MARGIN)->second.get<sal_Int32>();
+
pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, uno::makeAny(nParaRightMargin), /*bOverwrite=*/false);
}
}
@@ -1756,11 +1818,21 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con
if (nListId == 0 && !pList)
{
- // Seems situation with listid=0 and missing list definition is used by DOCX
- // to remove numbering defined previously. But some default numbering attributes
- // are still applied. This is first line indent, probably something more?
- if (!pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT))
- pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::makeAny(sal_Int16(0)), false);
+ // listid = 0 and no list definition is used in DOCX to stop numbering
+ // defined somewhere in parent styles
+ // And here we should explicitly set left margin and first-line margin.
+ // They can be taken from referred style, but not from styles with listid!
+ uno::Any aProp = lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_FIRST_LINE_INDENT, pEntry, m_pStyleSheetTable);
+ if (aProp.hasValue())
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, aProp, false);
+ else
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::makeAny(sal_uInt32(0)), false);
+
+ aProp = lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_LEFT_MARGIN, pEntry, m_pStyleSheetTable);
+ if (aProp.hasValue())
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, aProp, false);
+ else
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::makeAny(sal_uInt32(0)), false);
}
}
@@ -1915,8 +1987,7 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con
{
aProperties = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pPropertyMap->GetPropertyValues());
}
- // TODO: this *should* work for RTF but there are test failures, maybe rtftok doesn't distinguish between formatting for the paragraph marker and for the paragraph as a whole; needs investigation
- if (pPropertyMap && IsOOXMLImport())
+ if (pPropertyMap)
{
// tdf#64222 filter out the "paragraph marker" formatting and
// set it as a separate paragraph property, not a empty hint at
@@ -2097,9 +2168,15 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con
}
}
}
- if (pList->GetCurrentLevel())
+
+ sal_Int16 nCurrentLevel = GetListLevel(pEntry, pPropertyMap);
+ if (nCurrentLevel == -1)
+ nCurrentLevel = 0;
+
+ const ListLevel::Pointer pListLevel = pList->GetLevel(nCurrentLevel);
+ if (pListLevel)
{
- sal_Int16 nOverrideLevel = pList->GetCurrentLevel()->GetStartOverride();
+ sal_Int16 nOverrideLevel = pListLevel->GetStartOverride();
if (nOverrideLevel != -1 && m_aListOverrideApplied.find(nListId) == m_aListOverrideApplied.end())
{
// Apply override: we have override instruction for this level
@@ -3080,7 +3157,16 @@ void DomainMapper_Impl::CreateRedline(uno::Reference<text::XTextRange> const& xR
pRedlineProperties[0].Name = getPropertyName( PROP_REDLINE_AUTHOR );
pRedlineProperties[0].Value <<= pRedline->m_sAuthor;
pRedlineProperties[1].Name = getPropertyName( PROP_REDLINE_DATE_TIME );
- pRedlineProperties[1].Value <<= ConversionHelper::ConvertDateStringToDateTime( pRedline->m_sDate );
+ util::DateTime aDateTime = ConversionHelper::ConvertDateStringToDateTime( pRedline->m_sDate );
+ // tdf#146171 import not specified w:date (or specified as zero date "0-00-00")
+ // as Epoch time to avoid of losing change tracking data during ODF roundtrip
+ if ( aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0 )
+ {
+ aDateTime.Year = 1970;
+ aDateTime.Month = 1;
+ aDateTime.Day = 1;
+ }
+ pRedlineProperties[1].Value <<= aDateTime;
pRedlineProperties[2].Name = getPropertyName( PROP_REDLINE_REVERT_PROPERTIES );
pRedlineProperties[2].Value <<= pRedline->m_aRevertProperties;
pRedlineProperties[3].Name = "RedlineMoved";
@@ -3553,10 +3639,17 @@ void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape
}
else
{
- uno::Reference< text::XTextRange > xShapeText( xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRange> xShapeTextRange(xShape, uno::UNO_QUERY_THROW);
// Add the shape to the text append stack
- m_aTextAppendStack.push( TextAppendContext(uno::Reference< text::XTextAppend >( xShape, uno::UNO_QUERY_THROW ),
- m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xShapeText->getStart() )));
+ uno::Reference<text::XTextAppend> xShapeTextAppend(xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextCursor> xTextCursor;
+ if (!m_bIsNewDoc)
+ {
+ xTextCursor = xShapeTextRange->getText()->createTextCursorByRange(
+ xShapeTextRange->getStart());
+ }
+ TextAppendContext aContext(xShapeTextAppend, xTextCursor);
+ m_aTextAppendStack.push(aContext);
// Add the shape to the anchored objects stack
uno::Reference< text::XTextContent > xTxtContent( xShape, uno::UNO_QUERY_THROW );
@@ -3866,6 +3959,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;
@@ -4147,7 +4296,7 @@ static OUString lcl_ExtractVariableAndHint( const OUString& rCommand, OUString&
sal_Int32 nIndex = rCommand.indexOf( ' ', 2); //find last space after 'ASK'
if (nIndex == -1)
return OUString();
- while(rCommand[nIndex] == ' ')
+ while (nIndex < rCommand.getLength() && rCommand[nIndex] == ' ')
++nIndex;
OUString sShortCommand( rCommand.copy( nIndex ) ); //cut off the " ASK "
@@ -4271,14 +4420,15 @@ void DomainMapper_Impl::ChainTextFrames()
sal_Int32 nId;
sal_Int32 nSeq;
OUString s_mso_next_textbox;
- bool bShapeNameSet;
- TextFramesForChaining(): nId(0), nSeq(0), bShapeNameSet(false) {}
+ OUString shapeName;
+ TextFramesForChaining() : nId(0), nSeq(0) {}
} ;
typedef std::map <OUString, TextFramesForChaining> ChainMap;
try
{
ChainMap aTextFramesForChainingHelper;
+ ::std::vector<TextFramesForChaining> chainingWPS;
OUString sChainNextName("ChainNextName");
//learn about ALL of the textboxes and their chaining values first - because frames are processed in no specific order.
@@ -4316,19 +4466,22 @@ void DomainMapper_Impl::ChainTextFrames()
//Sometimes the shape names have not been imported. If not, we may have a fallback name.
//Set name later, only if required for linking.
- if( sShapeName.isEmpty() )
- aChainStruct.bShapeNameSet = false;
- else
- {
- aChainStruct.bShapeNameSet = true;
- sLinkChainName = sShapeName;
- }
+ aChainStruct.shapeName = sShapeName;
- if( !sLinkChainName.isEmpty() )
+ if (!sLinkChainName.isEmpty())
{
aChainStruct.xShape = rTextFrame;
aTextFramesForChainingHelper[sLinkChainName] = aChainStruct;
}
+ if (aChainStruct.s_mso_next_textbox.isEmpty())
+ { // no VML chaining => try to chain DrawingML via IDs
+ aChainStruct.xShape = rTextFrame;
+ if (!sLinkChainName.isEmpty())
+ { // for member of group shapes, TestTdf73499
+ aChainStruct.shapeName = sLinkChainName;
+ }
+ chainingWPS.emplace_back(aChainStruct);
+ }
}
//if mso-next-textbox tags are provided, create those vml-style links first. Afterwards we will make dml-style id/seq links.
@@ -4343,22 +4496,22 @@ void DomainMapper_Impl::ChainTextFrames()
if( nextFinder != aTextFramesForChainingHelper.end() )
{
//if the frames have no name yet, then set them. LinkDisplayName / ChainName are read-only.
- if( !msoItem.second.bShapeNameSet )
+ if (msoItem.second.shapeName.isEmpty())
{
uno::Reference< container::XNamed > xNamed( msoItem.second.xShape, uno::UNO_QUERY );
if ( xNamed.is() )
{
xNamed->setName( msoItem.first );
- msoItem.second.bShapeNameSet = true;
+ msoItem.second.shapeName = msoItem.first;
}
}
- if( !nextFinder->second.bShapeNameSet )
+ if (nextFinder->second.shapeName.isEmpty())
{
uno::Reference< container::XNamed > xNamed( nextFinder->second.xShape, uno::UNO_QUERY );
if ( xNamed.is() )
{
xNamed->setName( nextFinder->first );
- nextFinder->second.bShapeNameSet = true;
+ nextFinder->second.shapeName = msoItem.first;
}
}
@@ -4366,7 +4519,7 @@ void DomainMapper_Impl::ChainTextFrames()
uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
//The reverse chaining happens automatically, so only one direction needs to be set
- xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(nextFinder->first));
+ xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(nextFinder->second.shapeName));
//the last item in an mso-next-textbox chain is indistinguishable from id/seq items. Now that it is handled, remove it.
if( nextFinder->second.s_mso_next_textbox.isEmpty() )
@@ -4379,26 +4532,23 @@ void DomainMapper_Impl::ChainTextFrames()
const sal_Int32 nDirection = 1;
//Finally - go through and attach the chains based on matching ID and incremented sequence number (dml-style).
- for (const auto& rOuter : aTextFramesForChainingHelper)
+ for (const auto& rOuter : chainingWPS)
{
- if( rOuter.second.s_mso_next_textbox.isEmpty() ) //non-empty ones already handled earlier - so skipping them now.
- {
- for (const auto& rInner : aTextFramesForChainingHelper)
+ for (const auto& rInner : chainingWPS)
{
- if ( rInner.second.nId == rOuter.second.nId )
+ if (rInner.nId == rOuter.nId)
{
- if ( rInner.second.nSeq == ( rOuter.second.nSeq + nDirection ) )
+ if (rInner.nSeq == (rOuter.nSeq + nDirection))
{
- uno::Reference<text::XTextContent> xTextContent(rOuter.second.xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextContent> const xTextContent(rOuter.xShape, uno::UNO_QUERY_THROW);
uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
//The reverse chaining happens automatically, so only one direction needs to be set
- xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(rInner.first));
+ xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(rInner.shapeName));
break ; //there cannot be more than one next frame
}
}
}
- }
}
m_vTextFramesForChaining.clear(); //clear the vector
}
@@ -6886,13 +7036,23 @@ void DomainMapper_Impl::PopFieldContext()
// End of index is the first item on a new paragraph - this paragraph
// should not be part of index
auto xCursor
- = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
- xCursor->gotoEnd(false);
+ = xTextAppend->createTextCursorByRange(
+ m_aTextAppendStack.top().xInsertPosition.is()
+ ? m_aTextAppendStack.top().xInsertPosition
+ : xTextAppend->getEnd());
xCursor->goLeft(1, true);
// delete
xCursor->setString(OUString());
// But a new paragraph should be started after the index instead
- xTextAppend->finishParagraph(css::beans::PropertyValues());
+ if (m_bIsNewDoc) // this check - see testTdf129402
+ { // where finishParagraph inserts between 2 EndNode
+ xTextAppend->finishParagraph(css::beans::PropertyValues());
+ }
+ else
+ {
+ xTextAppend->finishParagraphInsert(css::beans::PropertyValues(),
+ m_aTextAppendStack.top().xInsertPosition);
+ }
}
m_bStartedTOC = false;
m_aTextAppendStack.pop();
@@ -6954,7 +7114,14 @@ void DomainMapper_Impl::PopFieldContext()
}
else if (!pContext->GetHyperlinkURL().isEmpty() && xCrsr.is())
{
- xCrsr->gotoEnd( true );
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ {
+ xCrsr->gotoRange(m_aTextAppendStack.top().xInsertPosition, true);
+ }
+ else
+ {
+ xCrsr->gotoEnd(true);
+ }
// Draw components (like comments) need hyperlinks set differently
SvxUnoTextRangeBase* pDrawText = dynamic_cast<SvxUnoTextRangeBase*>(xCrsr.get());
@@ -7390,6 +7557,7 @@ void DomainMapper_Impl::ImportGraphic(const writerfilter::Reference< Properties
{
uno::Reference<beans::XPropertySet> xEmbeddedProps(m_xEmbedded, uno::UNO_QUERY);
xEmbeddedProps->setPropertyValue("AnchorType", uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
+ xEmbeddedProps->setPropertyValue("IsFollowingTextFlow", uno::makeAny(m_pGraphicImport->GetLayoutInCell()));
uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
xEmbeddedProps->setPropertyValue("HoriOrient", xShapeProps->getPropertyValue("HoriOrient"));
xEmbeddedProps->setPropertyValue("HoriOrientPosition", xShapeProps->getPropertyValue("HoriOrientPosition"));
@@ -7826,70 +7994,6 @@ uno::Reference<container::XIndexAccess> DomainMapper_Impl::GetCurrentNumberingRu
return xRet;
}
-uno::Reference<beans::XPropertySet> DomainMapper_Impl::GetCurrentNumberingCharStyle()
-{
- uno::Reference<beans::XPropertySet> xRet;
- try
- {
- sal_Int32 nListLevel = -1;
- uno::Reference<container::XIndexAccess> xLevels;
- if ( GetTopContextType() == CONTEXT_PARAGRAPH )
- xLevels = GetCurrentNumberingRules(&nListLevel);
- if (!xLevels.is())
- {
- if (IsOOXMLImport())
- return xRet;
-
- PropertyMapPtr pContext = m_pTopContext;
- if (IsRTFImport() && !IsOpenField())
- {
- // Looking up the paragraph context explicitly (and not just taking
- // the top context) is necessary for RTF, where formatting of a run
- // and of the paragraph mark is not separated.
- // We know that the formatting inside a field won't affect the
- // paragraph marker formatting, though.
- pContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
- if (!pContext)
- return xRet;
- }
-
- // In case numbering rules is not found via a style, try the direct formatting instead.
- std::optional<PropertyMap::Property> oProp = pContext->getProperty(PROP_NUMBERING_RULES);
- if (oProp)
- {
- xLevels.set(oProp->second, uno::UNO_QUERY);
- // Found the rules, then also try to look up our numbering level.
- oProp = pContext->getProperty(PROP_NUMBERING_LEVEL);
- if (oProp)
- oProp->second >>= nListLevel;
- else
- nListLevel = 0;
- }
-
- if (!xLevels.is())
- return xRet;
- }
- uno::Sequence<beans::PropertyValue> aProps;
- xLevels->getByIndex(nListLevel) >>= aProps;
- auto pProp = std::find_if(std::cbegin(aProps), std::cend(aProps),
- [](const beans::PropertyValue& rProp) { return rProp.Name == "CharStyleName"; });
- if (pProp != std::cend(aProps))
- {
- OUString aCharStyle;
- pProp->Value >>= aCharStyle;
- uno::Reference<container::XNameAccess> xCharacterStyles;
- uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY);
- uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
- xStyleFamilies->getByName("CharacterStyles") >>= xCharacterStyles;
- xRet.set(xCharacterStyles->getByName(aCharStyle), uno::UNO_QUERY_THROW);
- }
- }
- catch( const uno::Exception& )
- {
- }
- return xRet;
-}
-
SectionPropertyMap * DomainMapper_Impl::GetSectionContext()
{
SectionPropertyMap* pSectionContext = nullptr;
@@ -8132,6 +8236,31 @@ void DomainMapper_Impl::commentProps(const OUString& sId, const CommentPropertie
m_aCommentProps[sId] = rProps;
}
+
+bool DomainMapper_Impl::handlePreviousParagraphBorderInBetween() const
+{
+ if (!m_xPreviousParagraph.is())
+ return false;
+
+ // Connected borders ("ParaIsConnectBorder") are always on by default
+ // and never changed by DomainMapper. Except one case when border in
+ // between is used. So this is not the best, but easiest way to check
+ // is previous paragraph has border in between.
+ bool bConnectBorders = true;
+ m_xPreviousParagraph->getPropertyValue(getPropertyName(PROP_PARA_CONNECT_BORDERS)) >>= bConnectBorders;
+
+ if (bConnectBorders)
+ return false;
+
+ // Previous paragraph has border in between. Current one also has (since this
+ // method is called). So current paragraph will get border above, but
+ // also need to ensure, that no unexpected bottom border are remaining in previous
+ // paragraph: since ParaIsConnectBorder=false it will be displayed in unexpected way.
+ m_xPreviousParagraph->setPropertyValue(getPropertyName(PROP_BOTTOM_BORDER), uno::makeAny(table::BorderLine2()));
+
+ return true;
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index ee6813f9d293..2abd229ba3d3 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -112,7 +112,8 @@ enum { NUMBER_OF_CONTEXTS = CONTEXT_LIST + 1 };
enum BreakType
{
PAGE_BREAK,
- COLUMN_BREAK
+ COLUMN_BREAK,
+ LINE_BREAK
};
/**
@@ -476,6 +477,7 @@ private:
bool m_bIsFirstSection;
bool m_bIsColumnBreakDeferred;
bool m_bIsPageBreakDeferred;
+ sal_Int32 m_nLineBreaksDeferred;
/// If we want to set "sdt end" on the next character context.
bool m_bSdtEndDeferred;
/// If we want to set "paragraph sdt end" on the next paragraph context.
@@ -1032,8 +1034,6 @@ public:
}
SectionPropertyMap * GetSectionContext();
- /// If the current paragraph has a numbering style associated, this method returns its character style (part of the numbering rules)
- css::uno::Reference<css::beans::XPropertySet> GetCurrentNumberingCharStyle();
/// If the current paragraph has a numbering style associated, this method returns its numbering rules
css::uno::Reference<css::container::XIndexAccess> GetCurrentNumberingRules(sal_Int32* pListLevel);
@@ -1142,6 +1142,9 @@ public:
/// start/end node.
void ClearPreviousParagraph();
+ /// Check if previous paragraph has borders in between and do the border magic to it if so
+ bool handlePreviousParagraphBorderInBetween() const;
+
/// Handle redline text portions in a frame, footnotes and redlines:
/// store their data, and create them after frame creation or footnote/endnote copying
bool m_bIsActualParagraphFramed;
@@ -1154,6 +1157,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:
diff --git a/writerfilter/source/dmapper/GraphicImport.cxx b/writerfilter/source/dmapper/GraphicImport.cxx
index 704774ec504a..6871c7c0974f 100644
--- a/writerfilter/source/dmapper/GraphicImport.cxx
+++ b/writerfilter/source/dmapper/GraphicImport.cxx
@@ -403,11 +403,12 @@ public:
{
try
{
- // Ask the graphic naming helper to find out the name for this
- // object: It's around till the end of the import, so it remembers
- // what's the first free name.
- uno::Reference< container::XNamed > xNamed( xGraphicObjectProperties, uno::UNO_QUERY_THROW );
- xNamed->setName(rDomainMapper.GetGraphicNamingHelper().NameGraphic(sName));
+ if (!sName.isEmpty())
+ {
+ uno::Reference<container::XNamed> const xNamed(xGraphicObjectProperties, uno::UNO_QUERY_THROW);
+ xNamed->setName(sName);
+ }
+ // else: name is automatically generated by SwDoc::MakeFlySection_()
xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_DESCRIPTION ),
uno::makeAny( sAlternativeText ));
@@ -474,6 +475,11 @@ com::sun::star::awt::Point GraphicImport::GetGraphicObjectPosition() const
return (com::sun::star::awt::Point(m_pImpl->nLeftPosition, m_pImpl->nTopPosition));
}
+bool GraphicImport::GetLayoutInCell() const
+{
+ return m_pImpl->bLayoutInCell;
+}
+
void GraphicImport::handleWrapTextValue(sal_uInt32 nVal)
{
switch (nVal)
@@ -1228,6 +1234,13 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue)
// But they aren't Writer pictures, either (which are already handled above).
uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
+ if (m_pImpl->nWrap == text::WrapTextMode_THROUGH && m_pImpl->nHoriRelation == text::RelOrientation::FRAME)
+ {
+ // text::RelOrientation::FRAME is OOXML's "column", which behaves as if
+ // layout-in-cell would be always off.
+ m_pImpl->bLayoutInCell = false;
+ }
+
// Anchored: Word only supports at-char in that case.
text::TextContentAnchorType eAnchorType = text::TextContentAnchorType_AT_CHARACTER;
diff --git a/writerfilter/source/dmapper/GraphicImport.hxx b/writerfilter/source/dmapper/GraphicImport.hxx
index 7ca4e09ed30d..3ff83de5b713 100644
--- a/writerfilter/source/dmapper/GraphicImport.hxx
+++ b/writerfilter/source/dmapper/GraphicImport.hxx
@@ -100,6 +100,8 @@ public:
com::sun::star::awt::Point GetGraphicObjectPosition() const;
+ bool GetLayoutInCell() const;
+
private:
// Properties
virtual void lcl_attribute(Id Name, Value & val) override;
diff --git a/writerfilter/source/dmapper/NumberingManager.cxx b/writerfilter/source/dmapper/NumberingManager.cxx
index 8829aa52697f..1c79e0eece99 100644
--- a/writerfilter/source/dmapper/NumberingManager.cxx
+++ b/writerfilter/source/dmapper/NumberingManager.cxx
@@ -371,9 +371,12 @@ void AbstractListDef::AddLevel( sal_uInt16 nLvl )
if ( nLvl >= m_aLevels.size() )
m_aLevels.resize( nLvl+1 );
- ListLevel::Pointer pLevel( new ListLevel );
- m_pCurrentLevel = pLevel;
- m_aLevels[nLvl] = pLevel;
+ if (!m_aLevels[nLvl])
+ {
+ m_aLevels[nLvl] = new ListLevel;
+ }
+
+ m_pCurrentLevel = m_aLevels[nLvl];
}
uno::Sequence<uno::Sequence<beans::PropertyValue>> AbstractListDef::GetPropertyValues(bool bDefaults)
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx
index b339a83f8ae6..1189bc0b1410 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -364,6 +364,7 @@ OUString getPropertyName( PropertyIds eId )
sName = "RtlGutter";
break;
case PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF: sName = "CursorNotIgnoreTables"; break;
+ case PROP_PARA_CONNECT_BORDERS: sName= "ParaIsConnectBorder"; break;
}
assert(sName.getLength()>0);
return sName;
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx
index b09170d2da36..7b6fe9a05275 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -361,6 +361,7 @@ enum PropertyIds
,PROP_GUTTER_MARGIN
,PROP_RTL_GUTTER
,PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF
+ ,PROP_PARA_CONNECT_BORDERS
};
//Returns the UNO string equivalent to eId.
diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx
index 8634d66e1ae5..34058d9c4702 100644
--- a/writerfilter/source/dmapper/PropertyMap.cxx
+++ b/writerfilter/source/dmapper/PropertyMap.cxx
@@ -882,13 +882,18 @@ void SectionPropertyMap::CopyHeaderFooterTextProperty( const uno::Reference< bea
}
// Copy headers and footers from the previous page style.
-void SectionPropertyMap::CopyHeaderFooter( const uno::Reference< beans::XPropertySet >& xPrevStyle,
+void SectionPropertyMap::CopyHeaderFooter( DomainMapper_Impl& rDM_Impl,
+ const uno::Reference< beans::XPropertySet >& xPrevStyle,
const uno::Reference< beans::XPropertySet >& xStyle,
bool bOmitRightHeader,
bool bOmitLeftHeader,
bool bOmitRightFooter,
bool bOmitLeftFooter )
{
+ if (!rDM_Impl.IsNewDoc())
+ { // see also DomainMapper_Impl::PushPageHeaderFooter()
+ return; // tdf#139737 SwUndoInserts cannot deal with new header/footer
+ }
bool bHasPrevHeader = false;
bool bHeaderIsShared = true;
OUString sHeaderIsOn = getPropertyName( PROP_HEADER_IS_ON );
@@ -966,13 +971,13 @@ void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Imp
if ( bFirstPage )
{
- CopyHeaderFooter( xPrevStyle, xStyle,
+ CopyHeaderFooter(rDM_Impl, xPrevStyle, xStyle,
!m_bFirstPageHeaderLinkToPrevious, true,
!m_bFirstPageFooterLinkToPrevious, true );
}
else
{
- CopyHeaderFooter( xPrevStyle, xStyle,
+ CopyHeaderFooter(rDM_Impl, xPrevStyle, xStyle,
!m_bDefaultHeaderLinkToPrevious,
!(m_bEvenPageHeaderLinkToPrevious && bUseEvenPages),
!m_bDefaultFooterLinkToPrevious,
@@ -1146,6 +1151,15 @@ bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_I
if (rDM_Impl.m_bConvertedTable && !rDM_Impl.GetIsLastSectionGroup() && rInfo.m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextPage)
return false;
+ sal_Int32 nVertOrientPosition = rInfo.getPropertyValue(u"VertOrientPosition").get<sal_Int32>();
+ sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue( u"HoriOrientRelation" ).get<sal_Int16>();
+ if (nVertOrientPosition < 0 && nHoriOrientRelation != text::RelOrientation::PAGE_FRAME)
+ {
+ // Negative vertical position: then need a floating table, as normal tables can't have
+ // negative top margins.
+ return true;
+ }
+
sal_Int32 nPageWidth = GetPageWidth();
sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
// Count the layout width of the table.
@@ -1161,7 +1175,6 @@ bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_I
if ( rInfo.getPropertyValue( u"RightMargin" ) >>= nRightMargin )
nTableWidth += nRightMargin;
- sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue( u"HoriOrientRelation" ).get<sal_Int16>();
sal_Int16 nVertOrientRelation = rInfo.getPropertyValue( u"VertOrientRelation" ).get<sal_Int16>();
if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME && nVertOrientRelation == text::RelOrientation::PAGE_FRAME )
{
@@ -1174,7 +1187,6 @@ bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_I
// The more close we are to the bottom, the more likely the table will span over to the next page
// So if we're in the bottom left quarter, don't do any conversion.
sal_Int32 nHoriOrientPosition = rInfo.getPropertyValue( u"HoriOrientPosition" ).get<sal_Int32>();
- sal_Int32 nVertOrientPosition = rInfo.getPropertyValue( u"VertOrientPosition" ).get<sal_Int32>();
sal_Int32 nPageHeight = getProperty( PROP_HEIGHT )->second.get<sal_Int32>();
if ( nHoriOrientPosition < (nPageWidth / 2) && nVertOrientPosition >( nPageHeight / 2 ) )
return false;
@@ -1456,9 +1468,26 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
}
}
- xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd,
+ const uno::Reference< text::XTextContent >& xTextContent =
+ xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd,
rInfo.m_aFrameProperties);
+ // paragraph of the anchoring point of the floating table needs zero top and bottom
+ // margins, if the table was a not floating table in the footnote, otherwise
+ // docDefault margins could result bigger vertical spaces around the table
+ if ( rInfo.m_bConvertToFloatingInFootnote && xTextContent.is() )
+ {
+ uno::Reference<beans::XPropertySet> xParagraph(
+ xTextContent->getAnchor(), uno::UNO_QUERY);
+ if ( xParagraph.is() )
+ {
+ xParagraph->setPropertyValue("ParaTopMargin",
+ uno::makeAny(static_cast<sal_Int32>(0)));
+ xParagraph->setPropertyValue("ParaBottomMargin",
+ uno::makeAny(static_cast<sal_Int32>(0)));
+ }
+ }
+
uno::Reference<text::XTextTablesSupplier> xTextDocument(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
uno::Reference<container::XNameAccess> xTables = xTextDocument->getTextTables();
for( size_t i = 0; i < aFramedRedlines.size(); i+=3)
@@ -1844,7 +1873,7 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
rDM_Impl.GetPageStyles()->insertByName( evenOddStyleName, uno::makeAny( evenOddStyle ) );
evenOddStyle->setPropertyValue( "HeaderIsOn", uno::makeAny( false ) );
evenOddStyle->setPropertyValue( "FooterIsOn", uno::makeAny( false ) );
- CopyHeaderFooter( pageProperties, evenOddStyle );
+ CopyHeaderFooter(rDM_Impl, pageProperties, evenOddStyle);
*pageStyle = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one).
if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) )
evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_LEFT ) );
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
index 3314ce7451ae..b03ef7bd664c 100644
--- a/writerfilter/source/dmapper/PropertyMap.hxx
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -299,7 +299,8 @@ private:
void CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl );
- static void CopyHeaderFooter( const css::uno::Reference< css::beans::XPropertySet >& xPrevStyle,
+ static void CopyHeaderFooter( DomainMapper_Impl& rDM_Impl,
+ const css::uno::Reference< css::beans::XPropertySet >& xPrevStyle,
const css::uno::Reference< css::beans::XPropertySet >& xStyle,
bool bOmitRightHeader = false, bool bOmitLeftHeader = false,
bool bOmitRightFooter = false, bool bOmitLeftFooter = false );
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx
index c5ec47f2be23..f4b02fab4d02 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -197,7 +197,8 @@ std::optional<OUString> SdtHelper::getValueFromDataBinding()
{
uno::Reference<XXPathObject> xResult = xXpathAPI->eval(xDocument, m_sDataBindingXPath);
- if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength())
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength()
+ && xResult->getString().getLength())
{
return xResult->getString();
}
@@ -263,8 +264,7 @@ void SdtHelper::createDropDownControl()
}
// clean up
- m_aDropDownItems.clear();
- setControlType(SdtControlType::unknown);
+ clear();
}
void SdtHelper::createPlainTextControl()
@@ -295,8 +295,7 @@ void SdtHelper::createPlainTextControl()
uno::makeAny(getInteropGrabBagAndClear()));
// clean up
- m_aDropDownItems.clear();
- setControlType(SdtControlType::unknown);
+ clear();
}
void SdtHelper::createDateContentControl()
@@ -371,11 +370,11 @@ void SdtHelper::createDateContentControl()
uno::UNO_QUERY);
xRefreshable->refresh();
- setControlType(SdtControlType::unknown);
-
// Store all unused sdt parameters from grabbag
xNameCont->insertByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
uno::makeAny(getInteropGrabBagAndClear()));
+
+ clear();
}
void SdtHelper::createControlShape(awt::Size aSize,
@@ -422,6 +421,16 @@ bool SdtHelper::containedInInteropGrabBag(const OUString& rValueName)
[&rValueName](const beans::PropertyValue& i) { return i.Name == rValueName; });
}
+void SdtHelper::clear()
+{
+ m_aDropDownItems.clear();
+ setControlType(SdtControlType::unknown);
+ m_sDataBindingPrefixMapping.clear();
+ m_sDataBindingXPath.clear();
+ m_sDataBindingStoreItemID.clear();
+ m_aGrabBag.clear();
+}
+
} // namespace writerfilter::dmapper
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx
index e58d73168d79..d9a6115a1251 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -102,6 +102,9 @@ class SdtHelper final : public virtual SvRefBase
void loadPropertiesXMLs();
+ /// Clear all collected attributes for futher reuse
+ void clear();
+
public:
explicit SdtHelper(DomainMapper_Impl& rDM_Impl,
css::uno::Reference<css::uno::XComponentContext> const& xContext);
diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx
index 732b96ff96db..3e6afe7b5fa1 100644
--- a/writerfilter/source/dmapper/SettingsTable.cxx
+++ b/writerfilter/source/dmapper/SettingsTable.cxx
@@ -539,11 +539,13 @@ static bool lcl_isDefault(const uno::Reference<beans::XPropertyState>& xProperty
void SettingsTable::ApplyProperties(uno::Reference<text::XTextDocument> const& xDoc)
{
uno::Reference< beans::XPropertySet> xDocProps( xDoc, uno::UNO_QUERY );
+ uno::Reference<lang::XMultiServiceFactory> xTextFactory(xDoc, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xDocumentSettings(xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW);
+
+ xDocumentSettings->setPropertyValue("TableRowKeep", uno::makeAny(true));
if (GetWordCompatibilityMode() <= 14)
{
- uno::Reference<lang::XMultiServiceFactory> xTextFactory(xDoc, uno::UNO_QUERY_THROW);
- uno::Reference<beans::XPropertySet> xDocumentSettings(xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW);
xDocumentSettings->setPropertyValue("MsWordCompMinLineHeightByFly", uno::makeAny(true));
xDocumentSettings->setPropertyValue("TabOverMargin", uno::makeAny(true));
}
diff --git a/writerfilter/source/dmapper/StyleSheetTable.cxx b/writerfilter/source/dmapper/StyleSheetTable.cxx
index 5f45672fe915..8b3bc02b44a6 100644
--- a/writerfilter/source/dmapper/StyleSheetTable.cxx
+++ b/writerfilter/source/dmapper/StyleSheetTable.cxx
@@ -464,8 +464,12 @@ void StyleSheetTable::lcl_attribute(Id Name, Value & val)
if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN)
{
// "If this attribute is specified by multiple styles, then the last instance shall be used."
- if ( m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_PARA && !m_pImpl->m_pCurrentEntry->sStyleIdentifierD.isEmpty() )
+ if (m_pImpl->m_pCurrentEntry->bIsDefaultStyle
+ && m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_PARA
+ && !m_pImpl->m_pCurrentEntry->sStyleIdentifierD.isEmpty())
+ {
m_pImpl->m_sDefaultParaStyleName = m_pImpl->m_pCurrentEntry->sStyleIdentifierD;
+ }
beans::PropertyValue aValue;
aValue.Name = "default";
@@ -1489,13 +1493,13 @@ OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExten
// { "Table of Figures", "" },
{ "Envelope Address", "Addressee" },
{ "Envelope Return", "Sender" },
- { "footnote reference", "Footnote Characters" },
- { "Footnote Reference", "Footnote Characters" },
+ { "footnote reference", "Footnote Symbol" },
+ { "Footnote Reference", "Footnote Symbol" },
// { "Annotation Reference", "" },
{ "Line Number", "Line numbering" },
{ "Page Number", "Page Number" },
- { "endnote reference", "Endnote Characters" },
- { "Endnote Reference", "Endnote Characters" },
+ { "endnote reference", "Endnote Symbol" },
+ { "Endnote Reference", "Endnote Symbol" },
{ "endnote text", "Endnote" },
{ "Endnote Text", "Endnote" },
// { "Table of Authorities", "" },
diff --git a/writerfilter/source/filter/WriterFilter.cxx b/writerfilter/source/filter/WriterFilter.cxx
index f62dff1fe19a..945a00f95258 100644
--- a/writerfilter/source/filter/WriterFilter.cxx
+++ b/writerfilter/source/filter/WriterFilter.cxx
@@ -314,7 +314,6 @@ void WriterFilter::setTargetDocument(const uno::Reference<lang::XComponent>& xDo
xSettings->setPropertyValue("UseFormerObjectPositioning", uno::makeAny(false));
xSettings->setPropertyValue("ConsiderTextWrapOnObjPos", uno::makeAny(true));
xSettings->setPropertyValue("UseFormerTextWrapping", uno::makeAny(false));
- xSettings->setPropertyValue("TableRowKeep", uno::makeAny(true));
xSettings->setPropertyValue("IgnoreTabsAndBlanksForLineCalculation", uno::makeAny(true));
xSettings->setPropertyValue("InvertBorderSpacing", uno::makeAny(true));
xSettings->setPropertyValue("CollapseEmptyCellPara", uno::makeAny(true));
diff --git a/writerfilter/source/rtftok/rtfcharsets.cxx b/writerfilter/source/rtftok/rtfcharsets.cxx
index 69e416ce8bc5..886e161e3c89 100644
--- a/writerfilter/source/rtftok/rtfcharsets.cxx
+++ b/writerfilter/source/rtftok/rtfcharsets.cxx
@@ -9,6 +9,7 @@
#include "rtfcharsets.hxx"
#include <sal/macros.h>
+#include <rtl/textenc.h>
namespace writerfilter::rtftok
{
@@ -50,6 +51,14 @@ RTFEncoding const aRTFEncodings[] = {
int nRTFEncodings = SAL_N_ELEMENTS(aRTFEncodings);
+RTFFontNameSuffix const aRTFFontNameSuffixes[] = {
+ { "Baltic", RTL_TEXTENCODING_MS_1257 }, { "CE", RTL_TEXTENCODING_MS_1250 },
+ { "Cyr", RTL_TEXTENCODING_MS_1251 }, { "Greek", RTL_TEXTENCODING_MS_1253 },
+ { "Tur", RTL_TEXTENCODING_MS_1254 }, { "(Hebrew)", RTL_TEXTENCODING_MS_1255 },
+ { "(Arabic)", RTL_TEXTENCODING_MS_1256 }, { "(Vietnamese)", RTL_TEXTENCODING_MS_1258 },
+ { "", RTL_TEXTENCODING_DONTKNOW } // End of array
+};
+
} // namespace writerfilter::rtftok
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcharsets.hxx b/writerfilter/source/rtftok/rtfcharsets.hxx
index 865a9310289e..826dea271f6b 100644
--- a/writerfilter/source/rtftok/rtfcharsets.hxx
+++ b/writerfilter/source/rtftok/rtfcharsets.hxx
@@ -19,6 +19,19 @@ struct RTFEncoding
};
extern RTFEncoding const aRTFEncodings[];
extern int nRTFEncodings;
+
+/// Font name can contain special suffixes used
+/// to determine encoding for given font table entry
+/// For example "Arial CE" is "Arial" with CP1250 encoding
+/// List of these suffixes is not official and detected in a empirical
+/// way thus may be inexact and incomplete.
+struct RTFFontNameSuffix
+{
+ const char* suffix;
+ int codepage;
+};
+extern RTFFontNameSuffix const aRTFFontNameSuffixes[];
+
} // namespace writerfilter::rtftok
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchflag.cxx b/writerfilter/source/rtftok/rtfdispatchflag.cxx
index 2acb4d59f977..9d891384360c 100644
--- a/writerfilter/source/rtftok/rtfdispatchflag.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx
@@ -421,8 +421,7 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
nParam = NS_ooxml::LN_CT_PPrBase_keepLines;
break;
case RTFKeyword::KEEPN:
- if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
- nParam = NS_ooxml::LN_CT_PPrBase_keepNext;
+ nParam = NS_ooxml::LN_CT_PPrBase_keepNext;
break;
case RTFKeyword::INTBL:
{
@@ -520,12 +519,8 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
{
m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
new RTFValue(aName));
- m_aStates.top().setCurrentStyleIndex(0);
- }
- else
- {
- m_aStates.top().setCurrentStyleIndex(-1);
}
+ m_aStates.top().setCurrentStyleIndex(0);
}
// Need to send paragraph properties again, if there will be any.
m_bNeedPap = true;
@@ -677,6 +672,7 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
case RTFKeyword::BRDRL:
case RTFKeyword::BRDRB:
case RTFKeyword::BRDRR:
+ case RTFKeyword::BRDRBTW:
{
RTFSprms aAttributes;
RTFSprms aSprms;
@@ -695,6 +691,9 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
case RTFKeyword::BRDRR:
nParam = getParagraphBorder(3);
break;
+ case RTFKeyword::BRDRBTW:
+ nParam = getParagraphBorder(4);
+ break;
default:
break;
}
diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
index 14d0b3993a54..467ef8589a5b 100644
--- a/writerfilter/source/rtftok/rtfdispatchvalue.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
@@ -194,7 +194,14 @@ bool RTFDocumentImpl::dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam
}
if (nSprm > 0)
{
- m_aStates.top().getCharacterSprms().set(nSprm, pIntValue);
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pIntValue);
+ }
return true;
}
@@ -485,84 +492,64 @@ bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
case RTFKeyword::CLSHDNG:
{
int nValue = -1;
- switch (nParam)
- {
- case 500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
- break;
- case 1000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
- break;
- case 1200:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
- break;
- case 1500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
- break;
- case 2000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
- break;
- case 2500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
- break;
- case 3000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
- break;
- case 3500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
- break;
- case 3700:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
- break;
- case 4000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
- break;
- case 4500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
- break;
- case 5000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
- break;
- case 5500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
- break;
- case 6000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
- break;
- case 6200:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
- break;
- case 6500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
- break;
- case 7000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
- break;
- case 7500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
- break;
- case 8000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
- break;
- case 8500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
- break;
- case 8700:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
- break;
- case 9000:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
- break;
- case 9500:
- nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
- break;
- default:
- break;
- }
- if (nValue != -1)
- putNestedAttribute(m_aStates.top().getTableCellSprms(),
- NS_ooxml::LN_CT_TcPrBase_shd, NS_ooxml::LN_CT_Shd_val,
- new RTFValue(nValue));
+
+ if (nParam < 1)
+ nValue = NS_ooxml::LN_Value_ST_Shd_clear;
+ else if (nParam < 750)
+ // Values in between 1 and 250 visually closer to 0% shading (white)
+ // But this will mean "no shading" while cell actually have some.
+ // So lets use minimal available value.
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
+ else if (nParam < 1100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
+ else if (nParam < 1350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
+ else if (nParam < 1750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
+ else if (nParam < 2250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
+ else if (nParam < 2750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
+ else if (nParam < 3250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
+ else if (nParam < 3600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
+ else if (nParam < 3850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
+ else if (nParam < 4250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
+ else if (nParam < 4750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
+ else if (nParam < 5250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
+ else if (nParam < 5750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
+ else if (nParam < 6100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
+ else if (nParam < 6350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
+ else if (nParam < 6750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
+ else if (nParam < 7250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
+ else if (nParam < 7750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
+ else if (nParam < 8250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
+ else if (nParam < 8600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
+ else if (nParam < 8850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
+ else if (nParam < 9250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
+ else if (nParam < 9750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
+ else
+ // Solid fill
+ nValue = NS_ooxml::LN_Value_ST_Shd_solid;
+
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_val, new RTFValue(nValue));
return true;
}
break;
@@ -782,6 +769,10 @@ RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
if (m_aStates.top().getDestination() == Destination::FONTTABLE
|| m_aStates.top().getDestination() == Destination::FONTENTRY)
{
+ // Some text in buffer? It is font name. So previous font definition is complete
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
m_aFontIndexes.push_back(nParam);
m_nCurrentFontIndex = getFontIndex(nParam);
}
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 663ac935047d..41fc0cdec523 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -50,6 +50,7 @@
#include "rtfskipdestination.hxx"
#include "rtftokenizer.hxx"
#include "rtflookahead.hxx"
+#include "rtfcharsets.hxx"
using namespace com::sun::star;
@@ -80,8 +81,9 @@ namespace writerfilter::rtftok
{
Id getParagraphBorder(sal_uInt32 nIndex)
{
- static const Id aBorderIds[] = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left,
- NS_ooxml::LN_CT_PBdr_bottom, NS_ooxml::LN_CT_PBdr_right };
+ static const Id aBorderIds[]
+ = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left, NS_ooxml::LN_CT_PBdr_bottom,
+ NS_ooxml::LN_CT_PBdr_right, NS_ooxml::LN_CT_PBdr_between };
return aBorderIds[nIndex];
}
@@ -324,6 +326,8 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x
m_pTokenizer = new RTFTokenizer(*this, m_pInStream.get(), m_xStatusIndicator);
m_pSdrImport = new RTFSdrImport(*this, m_xDstDoc);
+
+ m_pStyleTableEntries = std::make_shared<RTFReferenceTable::Entries_t>();
}
RTFDocumentImpl::~RTFDocumentImpl() = default;
@@ -363,6 +367,7 @@ void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const&
m_aAuthorInitials.clear();
}
pImpl->m_nDefaultFontIndex = m_nDefaultFontIndex;
+ pImpl->m_pStyleTableEntries = m_pStyleTableEntries;
pImpl->Strm().Seek(nPos);
SAL_INFO("writerfilter.rtf", "substream start");
Mapper().substream(nId, pImpl);
@@ -394,16 +399,22 @@ void RTFDocumentImpl::checkFirstRun()
assert(!m_bNeedSect || m_bFirstRunException);
setNeedSect(true); // first call that succeeds
- // set the requested default font, if there are none
+ // set the requested default font, if there are none for each state in stack
RTFValue::Pointer_t pFont
= getNestedAttribute(m_aDefaultState.getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
NS_ooxml::LN_CT_Fonts_ascii);
- RTFValue::Pointer_t pCurrentFont
- = getNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
- NS_ooxml::LN_CT_Fonts_ascii);
- if (pFont && !pCurrentFont)
- putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
- NS_ooxml::LN_CT_Fonts_ascii, pFont);
+ if (!pFont)
+ return;
+
+ for (size_t i = 0; i < m_aStates.size(); i++)
+ {
+ RTFValue::Pointer_t pCurrentFont
+ = getNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pCurrentFont)
+ putNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii, pFont);
+ }
}
void RTFDocumentImpl::setNeedPar(bool bNeedPar) { m_bNeedPar = bNeedPar; }
@@ -497,16 +508,16 @@ RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSpr
int nStyle = 0;
if (!m_aStates.empty())
nStyle = m_aStates.top().getCurrentStyleIndex();
- auto it = m_aStyleTableEntries.find(nStyle);
- if (it != m_aStyleTableEntries.end())
+ auto it = m_pStyleTableEntries->find(nStyle);
+ if (it != m_pStyleTableEntries->end())
{
// cloneAndDeduplicate() wants to know about only a single "style", so
// let's merge paragraph and character style properties here.
- auto itChar = m_aStyleTableEntries.end();
+ auto itChar = m_pStyleTableEntries->end();
if (!m_aStates.empty())
{
int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex();
- itChar = m_aStyleTableEntries.find(nCharStyle);
+ itChar = m_pStyleTableEntries->find(nCharStyle);
}
RTFSprms aStyleSprms;
@@ -517,7 +528,7 @@ RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSpr
RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get());
lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms);
- if (itChar != m_aStyleTableEntries.end())
+ if (itChar != m_pStyleTableEntries->end())
{
// Found active character style, then update aStyleSprms/Attributes.
if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
@@ -1322,6 +1333,74 @@ void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
}
}
+void RTFDocumentImpl::handleFontTableEntry()
+{
+ OUString aName = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ if (aName.isEmpty())
+ return;
+
+ if (aName.endsWith(";"))
+ {
+ aName = aName.copy(0, aName.getLength() - 1);
+ }
+
+ // Old documents can contain no encoding information in fontinfo,
+ // but there can be font name suffixes: Arial CE is not a special
+ // font, it is ordinal Arial, but with used cp 1250 encoding.
+ // Moreover these suffixes have priority over \cpgN and \fcharsetN
+ // in MS Word.
+ OUString aFontSuffix;
+ OUString aNameNoSuffix(aName);
+ sal_Int32 nLastSpace = aName.lastIndexOf(' ');
+ if (nLastSpace >= 0)
+ {
+ aFontSuffix = aName.copy(nLastSpace + 1);
+ aNameNoSuffix = aName.copy(0, nLastSpace);
+ sal_Int32 nEncoding = RTL_TEXTENCODING_DONTKNOW;
+ for (int i = 0; aRTFFontNameSuffixes[i].codepage != RTL_TEXTENCODING_DONTKNOW; i++)
+ {
+ if (aFontSuffix.equalsAscii(aRTFFontNameSuffixes[i].suffix))
+ {
+ nEncoding = aRTFFontNameSuffixes[i].codepage;
+ break;
+ }
+ }
+ if (nEncoding > RTL_TEXTENCODING_DONTKNOW)
+ {
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ else
+ {
+ // Unknown suffix: looks like it is just a part of font name, restore it
+ aNameNoSuffix = aName;
+ }
+ }
+
+ m_aFontNames[m_nCurrentFontIndex] = aNameNoSuffix;
+ if (m_nCurrentEncoding >= 0)
+ {
+ m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
+ m_nCurrentEncoding = -1;
+ }
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
+ new RTFValue(aNameNoSuffix));
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+
+ //See fdo#47347 initial invalid font entry properties are inserted first,
+ //so when we attempt to insert the correct ones, there's already an
+ //entry in the map for them, so the new ones aren't inserted.
+ auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
+ if (lb != m_aFontTableEntries.end()
+ && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
+ lb->second = pProp;
+ else
+ m_aFontTableEntries.insert(lb, std::make_pair(m_nCurrentFontIndex, pProp));
+}
+
void RTFDocumentImpl::text(OUString& rString)
{
if (rString.getLength() == 1 && m_aStates.top().getDestination() != Destination::DOCCOMM)
@@ -1335,10 +1414,7 @@ void RTFDocumentImpl::text(OUString& rString)
bool bRet = true;
switch (m_aStates.top().getDestination())
{
- // Note: in fonttbl there may or may not be groups; in stylesheet
- // and revtbl groups are mandatory
- case Destination::FONTTABLE:
- case Destination::FONTENTRY:
+ // Note: in stylesheet and revtbl groups are mandatory
case Destination::STYLEENTRY:
case Destination::LISTNAME:
case Destination::REVISIONENTRY:
@@ -1358,34 +1434,6 @@ void RTFDocumentImpl::text(OUString& rString)
= m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
switch (m_aStates.top().getDestination())
{
- case Destination::FONTTABLE:
- case Destination::FONTENTRY:
- {
- m_aFontNames[m_nCurrentFontIndex] = aName;
- if (m_nCurrentEncoding >= 0)
- {
- m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
- m_nCurrentEncoding = -1;
- }
- m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
- new RTFValue(aName));
-
- writerfilter::Reference<Properties>::Pointer_t const pProp(
- new RTFReferenceProperties(m_aStates.top().getTableAttributes(),
- m_aStates.top().getTableSprms()));
-
- //See fdo#47347 initial invalid font entry properties are inserted first,
- //so when we attempt to insert the correct ones, there's already an
- //entry in the map for them, so the new ones aren't inserted.
- auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
- if (lb != m_aFontTableEntries.end()
- && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
- lb->second = pProp;
- else
- m_aFontTableEntries.insert(lb,
- std::make_pair(m_nCurrentFontIndex, pProp));
- }
- break;
case Destination::STYLEENTRY:
{
RTFValue::Pointer_t pType
@@ -1402,7 +1450,7 @@ void RTFDocumentImpl::text(OUString& rString)
writerfilter::Reference<Properties>::Pointer_t const pProp(
createStyleProperties());
- m_aStyleTableEntries.insert(
+ m_pStyleTableEntries->insert(
std::make_pair(m_nCurrentStyleIndex, pProp));
}
else
@@ -1423,6 +1471,8 @@ void RTFDocumentImpl::text(OUString& rString)
}
}
break;
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
case Destination::LEVELTEXT:
case Destination::SHAPEPROPERTYNAME:
case Destination::SHAPEPROPERTYVALUE:
@@ -1862,13 +1912,13 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n
case RTFParserState::RunType::HICH:
case RTFParserState::RunType::RTLCH_LTRCH_1:
case RTFParserState::RunType::LTRCH_RTLCH_2:
- case RTFParserState::RunType::DBCH:
nSprm = NS_ooxml::LN_EG_RPrBase_bCs;
break;
case RTFParserState::RunType::NONE:
case RTFParserState::RunType::LOCH:
case RTFParserState::RunType::LTRCH_RTLCH_1:
case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
default:
nSprm = NS_ooxml::LN_EG_RPrBase_b;
break;
@@ -1881,13 +1931,13 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n
case RTFParserState::RunType::HICH:
case RTFParserState::RunType::RTLCH_LTRCH_1:
case RTFParserState::RunType::LTRCH_RTLCH_2:
- case RTFParserState::RunType::DBCH:
nSprm = NS_ooxml::LN_EG_RPrBase_iCs;
break;
case RTFParserState::RunType::NONE:
case RTFParserState::RunType::LOCH:
case RTFParserState::RunType::LTRCH_RTLCH_1:
case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
default:
nSprm = NS_ooxml::LN_EG_RPrBase_i;
break;
@@ -1922,7 +1972,14 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n
}
if (nSprm >= 0)
{
- m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pBoolValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
+ }
return RTFError::OK;
}
@@ -2091,7 +2148,7 @@ writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStylePrope
/** 2 different representations of the styles are needed:
1) flat content, as read from the input file:
- stored in m_aStyleTableEntries, used as reference input for
+ stored in m_pStyleTableEntries, used as reference input for
deduplication both here and for hard formatting in getProperties()
2) real content, with proper override of sprms/attributes where it differs
@@ -2100,7 +2157,7 @@ writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStylePrope
RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
{
RTFReferenceTable::Entries_t ret;
- for (auto const& it : m_aStyleTableEntries)
+ for (auto const& it : *m_pStyleTableEntries)
{
auto pStyle = it.second;
ret[it.first] = pStyle;
@@ -2116,8 +2173,8 @@ RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
if (it.first == nBasedOn)
continue;
- auto const itParent(m_aStyleTableEntries.find(nBasedOn)); // definition as read!
- if (itParent != m_aStyleTableEntries.end())
+ auto const itParent(m_pStyleTableEntries->find(nBasedOn)); // definition as read!
+ if (itParent != m_pStyleTableEntries->end())
{
auto const pStyleType(
static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find(
@@ -2143,7 +2200,7 @@ RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
}
}
}
- assert(ret.size() == m_aStyleTableEntries.size());
+ assert(ret.size() == m_pStyleTableEntries->size());
return ret;
}
@@ -2172,17 +2229,26 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState)
{
switch (rState.getDestination())
{
+ //Note: in fonttbl there may or may not be groups, so process it as no groups
case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
{
- writerfilter::Reference<Table>::Pointer_t const pTable(
- new RTFReferenceTable(m_aFontTableEntries));
- Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
- if (m_nDefaultFontIndex >= 0)
+ // Some text unhandled? Seems it is last font name
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ if (rState.getDestination() == Destination::FONTTABLE)
{
- auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
- putNestedAttribute(m_aDefaultState.getCharacterSprms(),
- NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
- pValue);
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(m_aFontTableEntries));
+ Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
+ if (m_nDefaultFontIndex >= 0)
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
+ putNestedAttribute(m_aDefaultState.getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
+ pValue);
+ }
}
}
break;
@@ -3668,7 +3734,7 @@ RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl)
, m_nHour(0)
, m_nMinute(0)
, m_pCurrentDestinationText(nullptr)
- , m_nCurrentStyleIndex(-1)
+ , m_nCurrentStyleIndex(0)
, m_nCurrentCharacterStyleIndex(-1)
, m_pCurrentBuffer(nullptr)
, m_bInListpicture(false)
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index fc5c8802b5d7..14ffc2f630a4 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -777,6 +777,7 @@ private:
writerfilter::Reference<Properties>::Pointer_t
getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType);
void checkNeedPap();
+ void handleFontTableEntry();
void sectBreak(bool bFinal = false);
void prepareProperties(RTFParserState& rState,
writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
@@ -933,7 +934,8 @@ private:
/// Raw default font index, use getFont() on it to get a real one.
int m_nDefaultFontIndex;
- RTFReferenceTable::Entries_t m_aStyleTableEntries;
+ /// To avoid copying entries between DomainMapper instances it is stored as pointer
+ std::shared_ptr<RTFReferenceTable::Entries_t> m_pStyleTableEntries;
int m_nCurrentStyleIndex;
bool m_bFormField;
/// For the INCLUDEPICTURE field's argument.
diff --git a/writerfilter/source/rtftok/rtfsprm.cxx b/writerfilter/source/rtftok/rtfsprm.cxx
index 8c54fe95e345..2edfec829edf 100644
--- a/writerfilter/source/rtftok/rtfsprm.cxx
+++ b/writerfilter/source/rtftok/rtfsprm.cxx
@@ -159,12 +159,24 @@ void RTFSprms::eraseLast(Id nKeyword)
static RTFValue::Pointer_t getDefaultSPRM(Id const id, Id nStyleType)
{
- if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ if (nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
{
switch (id)
{
+ case NS_ooxml::LN_EG_RPrBase_szCs:
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ return new RTFValue(24);
+ case NS_ooxml::LN_CT_Color_val:
+ return new RTFValue(0);
case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_i:
return new RTFValue(0);
+ case NS_ooxml::LN_CT_Underline_val:
+ return new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ case NS_ooxml::LN_CT_Fonts_ascii:
+ case NS_ooxml::LN_CT_Fonts_eastAsia:
+ case NS_ooxml::LN_CT_Fonts_cs:
+ return new RTFValue("Times New Roman");
default:
break;
}