[Libreoffice-commits] core.git: Branch 'libreoffice-4-2-2' - sw/qa writerfilter/source

Michael Stahl mstahl at redhat.com
Tue Feb 25 12:02:50 PST 2014


 sw/qa/extras/rtfimport/data/rhbz1065629.rtf    |   20 +
 sw/qa/extras/rtfimport/rtfimport.cxx           |   32 +
 writerfilter/source/rtftok/rtfdocumentimpl.cxx |  439 ++++++++++++++++---------
 writerfilter/source/rtftok/rtfdocumentimpl.hxx |   93 ++++-
 4 files changed, 413 insertions(+), 171 deletions(-)

New commits:
commit bfa6d3bcea13670715ccfdb0ce3500dbf8d18c88
Author: Michael Stahl <mstahl at redhat.com>
Date:   Tue Feb 25 12:50:46 2014 +0100

    rhbz#1065629: RTF import: re-implement nested tables
    
    The previous fix for this bug only fixed a symptom, this a fix for the
    real problem; with the real problem fixed the nCellEnds is unnecessary.
    
    Given that top-level table properties may be put either before or after the
    table cells, the only way that works to import tables is to buffer a whole
    top-level table row, but currently the buffer is replayed already at the
    end of a nested table row.
    
    Fortunately the RTF spec guarantees that \nesttableprops must occur
    after the nested table cells of the nested row, so it should be
    sufficient to remember the cell properties for the current nested table
    row only, in addition to the cell properties for the top-level table row.
    
    With this change, skipping a \nesttableprops destination when there is
    a table style turns out to mangle ooo98040-1.rtf badly, so stop doing
    that workaround.
    
    RTFDocumentImpl::popState() was copying various buffers up the state
    stack which is a clear indication that these shouldn't be members of
    RTFParserState in the first place, move them to RTFDocumentImpl.
    
    (cherry picked from commit c8f83ce1dbf5544f6aaa91775db6820a69c3c061)
    
    Conflicts:
    	writerfilter/source/rtftok/rtfdocumentimpl.cxx
    
    Change-Id: Ic2d8f7b3e00844b224d61605b405ca651239e5f7
    Reviewed-on: https://gerrit.libreoffice.org/8221
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Miklos Vajna <vmiklos at collabora.co.uk>
    (cherry picked from commit c1bbe64bead02e4f525f0fcfe169ab4a54a89fe4)
    Reviewed-on: https://gerrit.libreoffice.org/8227
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    Reviewed-by: Björn Michaelsen <bjoern.michaelsen at canonical.com>
    Reviewed-by: Eike Rathke <erack at redhat.com>

diff --git a/sw/qa/extras/rtfimport/data/rhbz1065629.rtf b/sw/qa/extras/rtfimport/data/rhbz1065629.rtf
index b22ec50..7f37594 100644
--- a/sw/qa/extras/rtfimport/data/rhbz1065629.rtf
+++ b/sw/qa/extras/rtfimport/data/rhbz1065629.rtf
@@ -6,6 +6,26 @@
 \f3\ftech\fcharset2 Symbol;
 \f4\fswiss\fcharset0 Helvetica;
 }
+{\colortbl
+;
+\red127\green255\blue212;
+\red0\green0\blue0;
+\red0\green0\blue255;
+\red255\green0\blue255;
+\red190\green190\blue190;
+\red0\green255\blue0;
+\red50\green205\blue50;
+\red176\green48\blue96;
+\red0\green0\blue128;
+\red85\green107\blue47;
+\red160\green32\blue240;
+\red255\green0\blue0;
+\red192\green192\blue192;
+\red0\green128\blue128;
+\red255\green255\blue255;
+\red255\green255\blue0;
+\red204\green0\blue0;
+}
 {\info
 {\*\userprops
 {\propname creator}\proptype30
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx
index b389af6..099bb0b 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -1381,6 +1381,38 @@ DECLARE_RTFIMPORT_TEST(testNestedTable, "rhbz1065629.rtf")
     xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
     xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
     CPPUNIT_ASSERT_EQUAL(OUString("Nom: John Doe"), xPara->getString());
+
+    // outer table: background color, borders for B1/B2 cell
+    xTable.set(xTables->getByIndex(2), uno::UNO_QUERY);
+    xCell.set(xTable->getCellByName("A1"), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xCell.is());
+    table::BorderLine2 fullPtSolid(
+            1, 0, 35, 0, table::BorderLineStyle::SOLID, 35);
+    CPPUNIT_ASSERT_BORDER_EQUAL(fullPtSolid,
+        getProperty<table::BorderLine2>(xCell, "LeftBorder"));
+    CPPUNIT_ASSERT_BORDER_EQUAL(fullPtSolid,
+        getProperty<table::BorderLine2>(xCell, "RightBorder"));
+    CPPUNIT_ASSERT_BORDER_EQUAL(fullPtSolid,
+        getProperty<table::BorderLine2>(xCell, "TopBorder"));
+    CPPUNIT_ASSERT_BORDER_EQUAL(fullPtSolid,
+        getProperty<table::BorderLine2>(xCell, "BottomBorder"));
+    CPPUNIT_ASSERT_EQUAL(0xCC0000, getProperty<sal_Int32>(xCell, "BackColor"));
+    xCell.set(xTable->getCellByName("A2"), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xCell.is());
+    table::BorderLine2 halfPtSolid(
+            /*0*/1, 0, 18, 0, table::BorderLineStyle::SOLID, 18);
+    CPPUNIT_ASSERT_BORDER_EQUAL(halfPtSolid,
+        getProperty<table::BorderLine2>(xCell, "LeftBorder"));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xffffffff),
+            getProperty<sal_Int32>(xCell, "BackColor"));
+    xCell.set(xTable->getCellByName("B2"), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xCell.is());
+    CPPUNIT_ASSERT_BORDER_EQUAL(halfPtSolid,
+        getProperty<table::BorderLine2>(xCell, "LeftBorder"));
+    CPPUNIT_ASSERT_BORDER_EQUAL(halfPtSolid,
+        getProperty<table::BorderLine2>(xCell, "RightBorder"));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xffffffff),
+            getProperty<sal_Int32>(xCell, "BackColor"));
 }
 
 DECLARE_RTFIMPORT_TEST(testCp1000016, "hello.rtf")
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index ef7117e..32df23e 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -127,7 +127,8 @@ static RTFSprms& lcl_getLastAttributes(RTFSprms& rSprms, Id nId)
     }
 }
 
-static void lcl_putBorderProperty(std::stack<RTFParserState>& aStates, Id nId, RTFValue::Pointer_t pValue)
+static void
+lcl_putBorderProperty(RTFStack& aStates, Id nId, RTFValue::Pointer_t pValue)
 {
     RTFSprms* pAttributes = 0;
     if (aStates.top().nBorderState == BORDER_PARAGRAPH_BOX)
@@ -248,7 +249,12 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x
     m_aSettingsTableAttributes(),
     m_aSettingsTableSprms(),
     m_xStorage(),
-    m_aTableBuffer(),
+    m_nNestedCells(0),
+    m_nTopLevelCells(0),
+    m_nInheritingCells(0),
+    m_nNestedCurrentCellX(0),
+    m_nTopLevelCurrentCellX(0),
+    m_aTableBufferStack(1), // create top-level buffer already
     m_aSuperBuffer(),
     m_bHasFootnote(false),
     m_pSuperstream(0),
@@ -462,7 +468,8 @@ void RTFDocumentImpl::checkNeedPap()
         else
         {
             RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms));
-            m_aStates.top().pCurrentBuffer->push_back(make_pair(BUFFER_PROPS, pValue));
+            m_aStates.top().pCurrentBuffer->push_back(
+                    Buf_t(BUFFER_PROPS, pValue));
         }
     }
 }
@@ -477,7 +484,7 @@ void RTFDocumentImpl::runProps()
     else
     {
         RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aCharacterAttributes, m_aStates.top().aCharacterSprms));
-        m_aStates.top().pCurrentBuffer->push_back(make_pair(BUFFER_PROPS, pValue));
+        m_aStates.top().pCurrentBuffer->push_back(Buf_t(BUFFER_PROPS, pValue));
     }
 
     // Delete the sprm, so the trackchange range will be started only once.
@@ -878,7 +885,7 @@ int RTFDocumentImpl::resolvePict(bool bInline)
     else
     {
         RTFValue::Pointer_t pValue(new RTFValue(aAttributes, aSprms));
-        m_aStates.top().pCurrentBuffer->push_back(make_pair(BUFFER_PROPS, pValue));
+        m_aStates.top().pCurrentBuffer->push_back(Buf_t(BUFFER_PROPS, pValue));
     }
 
     return 0;
@@ -992,10 +999,10 @@ void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
     }
     else
     {
-        pCurrentBuffer->push_back(make_pair(BUFFER_STARTRUN, RTFValue::Pointer_t()));
+        pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN));
         RTFValue::Pointer_t pValue(new RTFValue(*sValue));
-        pCurrentBuffer->push_back(make_pair(BUFFER_TEXT, pValue));
-        pCurrentBuffer->push_back(make_pair(BUFFER_ENDRUN, RTFValue::Pointer_t()));
+        pCurrentBuffer->push_back(Buf_t(BUFFER_TEXT, pValue));
+        pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN));
     }
 }
 
@@ -1131,9 +1138,10 @@ void RTFDocumentImpl::text(OUString& rString)
 
     // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
     if (m_aStates.top().aTableCellSprms.find(NS_ooxml::LN_CT_TcPrBase_vAlign).get() &&
-        m_aStates.top().nCells == 0)
+        m_nTopLevelCells == 0)
     {
-        m_aTableBuffer.push_back(make_pair(BUFFER_UTEXT, RTFValue::Pointer_t(new RTFValue(rString))));
+        m_aTableBufferStack.back().push_back(
+            Buf_t(BUFFER_UTEXT, RTFValue::Pointer_t(new RTFValue(rString))));
         return;
     }
 
@@ -1154,7 +1162,7 @@ void RTFDocumentImpl::text(OUString& rString)
     else if (pCurrentBuffer)
     {
         RTFValue::Pointer_t pValue;
-        pCurrentBuffer->push_back(make_pair(BUFFER_STARTRUN, pValue));
+        pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, pValue));
     }
 
     if (m_aStates.top().nDestinationState == DESTINATION_NORMAL
@@ -1167,7 +1175,7 @@ void RTFDocumentImpl::text(OUString& rString)
     else
     {
         RTFValue::Pointer_t pValue(new RTFValue(rString));
-        pCurrentBuffer->push_back(make_pair(BUFFER_UTEXT, pValue));
+        pCurrentBuffer->push_back(Buf_t(BUFFER_UTEXT, pValue));
     }
 
     m_bNeedCr = true;
@@ -1177,56 +1185,160 @@ void RTFDocumentImpl::text(OUString& rString)
     else if(pCurrentBuffer)
     {
         RTFValue::Pointer_t pValue;
-        pCurrentBuffer->push_back(make_pair(BUFFER_ENDRUN, pValue));
+        pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, pValue));
     }
 }
 
-void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer)
+void RTFDocumentImpl::prepareProperties(
+    RTFParserState & rState,
+    writerfilter::Reference<Properties>::Pointer_t & o_rpParagraphProperties,
+    writerfilter::Reference<Properties>::Pointer_t & o_rpFrameProperties,
+    writerfilter::Reference<Properties>::Pointer_t & o_rpTableRowProperties,
+    int const nCells, int const nCurrentCellX)
+{
+    o_rpParagraphProperties = getProperties(
+        rState.aParagraphAttributes, rState.aParagraphSprms);
+
+    if (rState.aFrame.hasProperties())
+    {
+        o_rpFrameProperties.reset(new RTFReferenceProperties(
+                RTFSprms(), rState.aFrame.getSprms()));
+    }
+
+    // Table width.
+    RTFValue::Pointer_t const pUnitValue(new RTFValue(3));
+    lcl_putNestedAttribute(rState.aTableRowSprms,
+        NS_ooxml::LN_CT_TblPrBase_tblW, NS_ooxml::LN_CT_TblWidth_type,
+        pUnitValue);
+    RTFValue::Pointer_t const pWValue(new RTFValue(nCurrentCellX));
+    lcl_putNestedAttribute(rState.aTableRowSprms,
+        NS_ooxml::LN_CT_TblPrBase_tblW, NS_ooxml::LN_CT_TblWidth_w, pWValue);
+
+    RTFValue::Pointer_t const pRowValue(new RTFValue(1));
+    if (nCells > 0)
+        rState.aTableRowSprms.set(NS_sprm::LN_PRow, pRowValue);
+
+    RTFValue::Pointer_t const pCellMar =
+        rState.aTableRowSprms.find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
+    if (!pCellMar.get())
+    {
+        // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
+        RTFSprms aAttributes;
+        aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, RTFValue::Pointer_t(
+                    new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)));
+        aAttributes.set(NS_ooxml::LN_CT_TblWidth_w,
+                RTFValue::Pointer_t(new RTFValue(0)));
+        lcl_putNestedSprm(rState.aTableRowSprms,
+                NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+                NS_ooxml::LN_CT_TblCellMar_left,
+                RTFValue::Pointer_t(new RTFValue(aAttributes)));
+        lcl_putNestedSprm(rState.aTableRowSprms,
+                NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+                NS_ooxml::LN_CT_TblCellMar_right,
+                RTFValue::Pointer_t(new RTFValue(aAttributes)));
+    }
+
+    o_rpTableRowProperties.reset(new RTFReferenceProperties(
+            rState.aTableRowAttributes, rState.aTableRowSprms));
+}
+
+void RTFDocumentImpl::pushProperties(
+    writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
+    writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
+    writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties)
+{
+    Mapper().props(pParagraphProperties);
+
+    if (pFrameProperties)
+    {
+        Mapper().props(pFrameProperties);
+    }
+
+    Mapper().props(pTableRowProperties);
+
+    tableBreak();
+}
+
+void RTFDocumentImpl::replayRowBuffer(
+        RTFBuffer_t & rBuffer,
+        ::std::deque<RTFSprms> & rCellsSrpms,
+        ::std::deque<RTFSprms> & rCellsAttributes,
+        int const nCells)
+{
+    for (int i = 0; i < nCells; ++i)
+    {
+        replayBuffer(rBuffer, &rCellsSrpms.front(), &rCellsAttributes.front());
+        rCellsSrpms.pop_front();
+        rCellsAttributes.pop_front();
+    }
+    for (size_t i = 0; i < rBuffer.size(); ++i)
+    {
+        SAL_WARN_IF( BUFFER_CELLEND == boost::get<0>(rBuffer[i]),
+            "writerfilter.rtf", "dropping table cell!");
+    }
+    assert(0 == rCellsSrpms.size());
+    assert(0 == rCellsAttributes.size());
+}
+
+void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer,
+        RTFSprms *const pSprms, RTFSprms const*const pAttributes)
 {
     while (rBuffer.size())
     {
-        std::pair<RTFBufferTypes, RTFValue::Pointer_t> aPair = rBuffer.front();
+        Buf_t aTuple(rBuffer.front());
         rBuffer.pop_front();
-        if (aPair.first == BUFFER_PROPS)
+        if (boost::get<0>(aTuple) == BUFFER_PROPS)
         {
             writerfilter::Reference<Properties>::Pointer_t const pProp(
-                    new RTFReferenceProperties(aPair.second->getAttributes(), aPair.second->getSprms())
+                    new RTFReferenceProperties(
+                        boost::get<1>(aTuple)->getAttributes(),
+                        boost::get<1>(aTuple)->getSprms())
                     );
             Mapper().props(pProp);
         }
-        else if (aPair.first == BUFFER_CELLEND)
+        else if (boost::get<0>(aTuple) == BUFFER_NESTROW)
+        {
+            TableRowBuffer & rRowBuffer(*boost::get<2>(aTuple));
+
+            replayRowBuffer(rRowBuffer.buffer, rRowBuffer.cellsSprms,
+                    rRowBuffer.cellsAttributes, rRowBuffer.nCells);
+
+            pushProperties(rRowBuffer.pParaProperties,
+                    rRowBuffer.pFrameProperties, rRowBuffer.pRowProperties);
+        }
+        else if (boost::get<0>(aTuple) == BUFFER_CELLEND)
         {
+            assert(pSprms && pAttributes);
             RTFValue::Pointer_t pValue(new RTFValue(1));
-            m_aStates.top().aTableCellSprms.set(NS_sprm::LN_PCell, pValue);
+            pSprms->set(NS_sprm::LN_PCell, pValue);
             writerfilter::Reference<Properties>::Pointer_t const pTableCellProperties(
-                    new RTFReferenceProperties(m_aStates.top().aTableCellAttributes, m_aStates.top().aTableCellSprms)
-                    );
+                    new RTFReferenceProperties(*pAttributes, *pSprms));
             Mapper().props(pTableCellProperties);
             tableBreak();
             break;
         }
-        else if (aPair.first == BUFFER_STARTRUN)
+        else if (boost::get<0>(aTuple) == BUFFER_STARTRUN)
             Mapper().startCharacterGroup();
-        else if (aPair.first == BUFFER_TEXT)
+        else if (boost::get<0>(aTuple) == BUFFER_TEXT)
         {
-            sal_uInt8 nValue = aPair.second->getInt();
+            sal_uInt8 const nValue = boost::get<1>(aTuple)->getInt();
             Mapper().text(&nValue, 1);
         }
-        else if (aPair.first == BUFFER_UTEXT)
+        else if (boost::get<0>(aTuple) == BUFFER_UTEXT)
         {
-            OUString aString(aPair.second->getString());
+            OUString const aString(boost::get<1>(aTuple)->getString());
             Mapper().utext(reinterpret_cast<sal_uInt8 const*>(aString.getStr()), aString.getLength());
         }
-        else if (aPair.first == BUFFER_ENDRUN)
+        else if (boost::get<0>(aTuple) == BUFFER_ENDRUN)
             Mapper().endCharacterGroup();
-        else if (aPair.first == BUFFER_PAR)
+        else if (boost::get<0>(aTuple) == BUFFER_PAR)
             parBreak();
-        else if (aPair.first == BUFFER_STARTSHAPE)
-            m_pSdrImport->resolve(aPair.second->getShape(), false);
-        else if (aPair.first == BUFFER_ENDSHAPE)
+        else if (boost::get<0>(aTuple) == BUFFER_STARTSHAPE)
+            m_pSdrImport->resolve(boost::get<1>(aTuple)->getShape(), false);
+        else if (boost::get<0>(aTuple) == BUFFER_ENDSHAPE)
             m_pSdrImport->close();
         else
-            SAL_WARN("writerfilter", "should not happen");
+            assert(false);
     }
 
 }
@@ -1345,11 +1457,14 @@ int RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
             m_aStates.top().nDestinationState = DESTINATION_SHAPEINSTRUCTION;
             break;
         case RTF_NESTTABLEPROPS:
-            // Don't try to support nested tables having table styles for now.
-            if (!m_aStates.top().bHasTableStyle)
-                m_aStates.top().nDestinationState = DESTINATION_NESTEDTABLEPROPERTIES;
-            else
-                m_aStates.top().nDestinationState = DESTINATION_SKIP;
+            // do not set any properties of outer table at nested table!
+            m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms;
+            m_aStates.top().aTableCellAttributes =
+                m_aDefaultState.aTableCellAttributes;
+            m_aNestedTableCellsSprms.clear();
+            m_aNestedTableCellsAttributes.clear();
+            m_nNestedCells = 0;
+            m_aStates.top().nDestinationState = DESTINATION_NESTEDTABLEPROPERTIES;
             break;
         case RTF_HEADER:
         case RTF_FOOTER:
@@ -1403,11 +1518,11 @@ int RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
                 OUString aCustomMark;
                 while (m_aSuperBuffer.size())
                 {
-                    std::pair<RTFBufferTypes, RTFValue::Pointer_t> aPair = m_aSuperBuffer.front();
+                    Buf_t aTuple = m_aSuperBuffer.front();
                     m_aSuperBuffer.pop_front();
-                    if (aPair.first == BUFFER_UTEXT)
+                    if (boost::get<0>(aTuple) == BUFFER_UTEXT)
                     {
-                        aCustomMark = aPair.second->getString();
+                        aCustomMark = boost::get<1>(aTuple)->getString();
                         bCustomMark = true;
                     }
                 }
@@ -1492,7 +1607,8 @@ int RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
                         else
                         {
                             RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aShape));
-                            m_aStates.top().pCurrentBuffer->push_back(make_pair(BUFFER_STARTSHAPE, pValue));
+                            m_aStates.top().pCurrentBuffer->push_back(
+                                    Buf_t(BUFFER_STARTSHAPE, pValue));
                         }
                     }
                 }
@@ -1812,7 +1928,8 @@ int RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
                 else if (m_aStates.top().nDestinationState != DESTINATION_SHAPETEXT)
                 {
                     RTFValue::Pointer_t pValue;
-                    m_aStates.top().pCurrentBuffer->push_back(make_pair(BUFFER_PAR, pValue));
+                    m_aStates.top().pCurrentBuffer->push_back(
+                            Buf_t(BUFFER_PAR, pValue));
                 }
                 // but don't emit properties yet, since they may change till the first text token arrives
                 m_bNeedPap = true;
@@ -1859,113 +1976,114 @@ int RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
                 {
                     // There were no runs in the cell, so we need to send paragraph and character properties here.
                     RTFValue::Pointer_t pPValue(new RTFValue(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms));
-                    m_aTableBuffer.push_back(make_pair(BUFFER_PROPS, pPValue));
+                    m_aTableBufferStack.back().push_back(
+                            Buf_t(BUFFER_PROPS, pPValue));
                     RTFValue::Pointer_t pCValue(new RTFValue(m_aStates.top().aCharacterAttributes, m_aStates.top().aCharacterSprms));
-                    m_aTableBuffer.push_back(make_pair(BUFFER_PROPS, pCValue));
+                    m_aTableBufferStack.back().push_back(
+                            Buf_t(BUFFER_PROPS, pCValue));
                 }
 
                 RTFValue::Pointer_t pValue;
-                m_aTableBuffer.push_back(make_pair(BUFFER_CELLEND, pValue));
+                m_aTableBufferStack.back().push_back(
+                        Buf_t(BUFFER_CELLEND, pValue));
                 m_bNeedPap = true;
-                m_aStates.top().nCellEnds++;
             }
             break;
-        case RTF_ROW:
         case RTF_NESTROW:
             {
+                boost::shared_ptr<TableRowBuffer> const pBuffer(
+                    new TableRowBuffer(
+                        m_aTableBufferStack.back(),
+                        m_aNestedTableCellsSprms,
+                        m_aNestedTableCellsAttributes,
+                        m_nNestedCells));
+                prepareProperties(m_aStates.top(),
+                        pBuffer->pParaProperties,
+                        pBuffer->pFrameProperties,
+                        pBuffer->pRowProperties,
+                        m_nNestedCells, m_nNestedCurrentCellX);
+
+                assert(m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back());
+                if (m_aTableBufferStack.size() == 1)
+                {
+                    throw io::WrongFormatException(
+                        "mismatch between \\itap and number of \\nestrow", 0);
+                }
+                // note: there may be several states pointing to table buffer!
+                for (size_t i = 0; i < m_aStates.size(); ++i)
+                {
+                    if (m_aStates[i].pCurrentBuffer == &m_aTableBufferStack.back())
+                    {
+                        m_aStates[i].pCurrentBuffer =
+                            &m_aTableBufferStack[m_aTableBufferStack.size()-2];
+                    }
+                }
+                m_aTableBufferStack.pop_back();
+                m_aTableBufferStack.back().push_back(
+                        Buf_t(BUFFER_NESTROW, 0, pBuffer));
+
+                m_aNestedTableCellsSprms.clear();
+                m_aNestedTableCellsAttributes.clear();
+                m_nNestedCells = 0;
+                m_bNeedPap = true;
+            }
+            break;
+        case RTF_ROW:
+            {
                 // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): add a fake cell.
                 const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
-                if (nKeyword == RTF_ROW && (m_nCellxMax - m_aStates.top().nCellX) >= MINLAY)
+                if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY)
                     dispatchValue(RTF_CELLX, m_nCellxMax);
 
-                if (m_aStates.top().nCells)
+                if (m_nTopLevelCells)
                 {
                     // Make a backup before we start popping elements
-                    m_aStates.top().aTableInheritingCellsSprms = m_aStates.top().aTableCellsSprms;
-                    m_aStates.top().aTableInheritingCellsAttributes = m_aStates.top().aTableCellsAttributes;
-                    m_aStates.top().nInheritingCells = m_aStates.top().nCells;
+                    m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms;
+                    m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes;
+                    m_nInheritingCells = m_nTopLevelCells;
                 }
                 else
                 {
                     // No table definition? Then inherit from the previous row
-                    m_aStates.top().aTableCellsSprms = m_aStates.top().aTableInheritingCellsSprms;
-                    m_aStates.top().aTableCellsAttributes = m_aStates.top().aTableInheritingCellsAttributes;
-                    m_aStates.top().nCells = m_aStates.top().nInheritingCells;
-                }
-                for (int i = 0; i < m_aStates.top().nCells; ++i)
-                {
-                    m_aStates.top().aTableCellSprms = m_aStates.top().aTableCellsSprms.front();
-                    m_aStates.top().aTableCellsSprms.pop_front();
-                    m_aStates.top().aTableCellAttributes = m_aStates.top().aTableCellsAttributes.front();
-                    m_aStates.top().aTableCellsAttributes.pop_front();
-                    replayBuffer(m_aTableBuffer);
-                }
-                for (int i = 0; i < m_aStates.top().nCellEnds - m_aStates.top().nCells; ++i)
-                {
-                    replayBuffer(m_aTableBuffer);
+                    m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms;
+                    m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes;
+                    m_nTopLevelCells = m_nInheritingCells;
                 }
-                for (size_t i = 0; i < m_aTableBuffer.size(); ++i)
-                {
-                    SAL_WARN_IF(BUFFER_CELLEND == m_aTableBuffer[i].first,
-                        "writerfilter.rtf", "dropping table cell!");
-                }
-                assert(0 == m_aStates.top().aTableCellsSprms.size());
-                assert(0 == m_aStates.top().aTableCellsAttributes.size());
-                m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms;
-                m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes;
-
-                writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties(
-                        getProperties(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms)
-                        );
-                Mapper().props(pParagraphProperties);
 
-                if (m_aStates.top().aFrame.hasProperties())
+                while (m_aTableBufferStack.size() > 1)
                 {
-                    writerfilter::Reference<Properties>::Pointer_t const pFrameProperties(
-                            new RTFReferenceProperties(RTFSprms(), m_aStates.top().aFrame.getSprms()));
-                    Mapper().props(pFrameProperties);
+                    SAL_WARN("writerfilter.rtf", "dropping extra table buffer");
+                    // note: there may be several states pointing to table buffer!
+                    for (size_t i = 0; i < m_aStates.size(); ++i)
+                    {
+                        if (m_aStates[i].pCurrentBuffer == &m_aTableBufferStack.back())
+                        {
+                            m_aStates[i].pCurrentBuffer =
+                                &m_aTableBufferStack.front();
+                        }
+                    }
+                    m_aTableBufferStack.pop_back();
                 }
 
-                // Table width.
-                RTFValue::Pointer_t pUnitValue(new RTFValue(3));
-                lcl_putNestedAttribute(m_aStates.top().aTableRowSprms,
-                        NS_ooxml::LN_CT_TblPrBase_tblW, NS_ooxml::LN_CT_TblWidth_type, pUnitValue);
-                RTFValue::Pointer_t pWValue(new RTFValue(m_aStates.top().nCellX));
-                lcl_putNestedAttribute(m_aStates.top().aTableRowSprms,
-                        NS_ooxml::LN_CT_TblPrBase_tblW, NS_ooxml::LN_CT_TblWidth_w, pWValue);
-
-                RTFValue::Pointer_t pRowValue(new RTFValue(1));
-                if (m_aStates.top().nCells > 0)
-                    m_aStates.top().aTableRowSprms.set(NS_sprm::LN_PRow, pRowValue);
+                replayRowBuffer(m_aTableBufferStack.back(),
+                    m_aTopLevelTableCellsSprms, m_aTopLevelTableCellsAttributes,
+                    m_nTopLevelCells);
 
-                RTFValue::Pointer_t pCellMar = m_aStates.top().aTableRowSprms.find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
-                if (!pCellMar.get())
-                {
-                    // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
-                    RTFSprms aAttributes;
-                    aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, RTFValue::Pointer_t(new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)));
-                    aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, RTFValue::Pointer_t(new RTFValue(0)));
-                    lcl_putNestedSprm(m_aStates.top().aTableRowSprms,
-                            NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left,
-                            RTFValue::Pointer_t(new RTFValue(aAttributes)));
-                    lcl_putNestedSprm(m_aStates.top().aTableRowSprms,
-                            NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_right,
-                            RTFValue::Pointer_t(new RTFValue(aAttributes)));
-                }
+                m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms;
+                m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes;
 
-                writerfilter::Reference<Properties>::Pointer_t const pTableRowProperties(
-                        new RTFReferenceProperties(m_aStates.top().aTableRowAttributes, m_aStates.top().aTableRowSprms)
-                        );
-                Mapper().props(pTableRowProperties);
+                writerfilter::Reference<Properties>::Pointer_t paraProperties;
+                writerfilter::Reference<Properties>::Pointer_t frameProperties;
+                writerfilter::Reference<Properties>::Pointer_t rowProperties;
+                prepareProperties(m_aStates.top(),
+                        paraProperties, frameProperties, rowProperties,
+                        m_nTopLevelCells, m_nTopLevelCurrentCellX);
+                pushProperties(paraProperties, frameProperties, rowProperties);
 
-                tableBreak();
                 m_bNeedPap = true;
                 m_bNeedFinalPar = true;
-                m_aTableBuffer.clear();
-                m_aStates.top().nCells = 0;
-                m_aStates.top().nCellEnds = 0;
-                m_aStates.top().aTableCellsSprms.clear();
-                m_aStates.top().aTableCellsAttributes.clear();
+                m_aTableBufferStack.back().clear();
+                m_nTopLevelCells = 0;
             }
             break;
         case RTF_COLUMN:
@@ -2253,16 +2371,16 @@ int RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
     switch (nKeyword)
     {
         case RTF_KEEP:
-            if (m_aStates.top().pCurrentBuffer != &m_aTableBuffer)
+            if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back())
                 nParam = NS_sprm::LN_PFKeep;
             break;
         case RTF_KEEPN:
-            if (m_aStates.top().pCurrentBuffer != &m_aTableBuffer)
+            if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back())
                 nParam = NS_sprm::LN_PFKeepFollow;
             break;
         case RTF_INTBL:
             {
-                m_aStates.top().pCurrentBuffer = &m_aTableBuffer;
+                m_aStates.top().pCurrentBuffer = &m_aTableBufferStack.back();
                 nParam = NS_sprm::LN_PFInTable;
             }
             break;
@@ -2310,7 +2428,7 @@ int RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
             // \pard is allowed between \cell and \row, but in that case it should not reset the fact that we're inside a table.
             m_aStates.top().aParagraphSprms = m_aDefaultState.aParagraphSprms;
             m_aStates.top().aParagraphAttributes = m_aDefaultState.aParagraphAttributes;
-            if (m_aStates.top().nCells == 0)
+            if (m_nTopLevelCells == 0 && m_nNestedCells == 0)
             {
                 // Reset that we're in a table.
                 m_aStates.top().pCurrentBuffer = 0;
@@ -2333,7 +2451,10 @@ int RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
                 m_aStates.top().aTableRowSprms = m_aDefaultState.aTableRowSprms;
                 m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblGridBase_gridCol, RTFValue::Pointer_t(new RTFValue(-1)), false);
                 m_aStates.top().aTableRowAttributes = m_aDefaultState.aTableRowAttributes;
-                m_aStates.top().nCellX = 0;
+                if (DESTINATION_NESTEDTABLEPROPERTIES == m_aStates.top().nDestinationState)
+                    m_nNestedCurrentCellX = 0;
+                else
+                    m_nTopLevelCurrentCellX = 0;
                 // In case the table definition is in the middle of the row
                 // (invalid), make sure table definition is emitted.
                 m_bNeedPap = true;
@@ -2553,7 +2674,7 @@ int RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
             {
                 if (m_aStates.top().pCurrentBuffer == &m_aSuperBuffer)
                 {
-                    replayBuffer(m_aSuperBuffer);
+                    replayBuffer(m_aSuperBuffer, 0, 0);
                     m_aStates.top().pCurrentBuffer = 0;
                 }
                 m_aStates.top().aCharacterSprms.erase(NS_ooxml::LN_EG_RPrBase_vertAlign);
@@ -2837,8 +2958,15 @@ int RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
     {
         m_aStates.top().aParagraphSprms.set(nSprm, pIntValue);
         if (nKeyword == RTF_ITAP && nParam > 0)
+        {
+            while (m_aTableBufferStack.size() < sal::static_int_cast<size_t>(nParam))
+            {
+                m_aTableBufferStack.push_back(RTFBuffer_t());
+            }
             // Invalid tables may omit INTBL after ITAP
-            dispatchFlag(RTF_INTBL);
+            dispatchFlag(RTF_INTBL); // sets newly pushed buffer as current
+            assert(m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back());
+        }
         return 0;
     }
 
@@ -2924,7 +3052,7 @@ int RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
     {
         m_bNeedPap = true;
         // Don't try to support text frames inside tables for now.
-        if (m_aStates.top().pCurrentBuffer != &m_aTableBuffer)
+        if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back())
             m_aStates.top().aFrame.setSprm(nId, nParam);
 
         return 0;
@@ -3255,25 +3383,43 @@ int RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
             break;
         case RTF_CELLX:
             {
-                int nCellX = nParam - m_aStates.top().nCellX;
+                int & rCurrentCellX((DESTINATION_NESTEDTABLEPROPERTIES ==
+                                        m_aStates.top().nDestinationState)
+                                    ? m_nNestedCurrentCellX
+                                    : m_nTopLevelCurrentCellX);
+                int nCellX = nParam - rCurrentCellX;
 
                 // If there is a negative left margin, then the first cellx is relateve to that.
                 RTFValue::Pointer_t pTblInd = m_aStates.top().aTableRowSprms.find(NS_ooxml::LN_CT_TblPrBase_tblInd);
-                if (m_aStates.top().nCellX == 0 && pTblInd.get())
+                if (rCurrentCellX == 0 && pTblInd.get())
                 {
                     RTFValue::Pointer_t pWidth = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
                     if (pWidth.get() && pWidth->getInt() < 0)
                         nCellX = -1 * (pWidth->getInt() - nParam);
                 }
 
-                m_aStates.top().nCellX = nParam;
+                rCurrentCellX = nParam;
                 RTFValue::Pointer_t pXValue(new RTFValue(nCellX));
                 m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue, false);
-                m_aStates.top().nCells++;
+                if (DESTINATION_NESTEDTABLEPROPERTIES == m_aStates.top().nDestinationState)
+                {
+                    m_nNestedCells++;
+                    // Push cell properties.
+                    m_aNestedTableCellsSprms.push_back(
+                            m_aStates.top().aTableCellSprms);
+                    m_aNestedTableCellsAttributes.push_back(
+                            m_aStates.top().aTableCellAttributes);
+                }
+                else
+                {
+                    m_nTopLevelCells++;
+                    // Push cell properties.
+                    m_aTopLevelTableCellsSprms.push_back(
+                            m_aStates.top().aTableCellSprms);
+                    m_aTopLevelTableCellsAttributes.push_back(
+                            m_aStates.top().aTableCellAttributes);
+                }
 
-                // Push cell properties.
-                m_aStates.top().aTableCellsSprms.push_back(m_aStates.top().aTableCellSprms);
-                m_aStates.top().aTableCellsAttributes.push_back(m_aStates.top().aTableCellAttributes);
                 m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms;
                 m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes;
                 // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token
@@ -4753,7 +4899,8 @@ int RTFDocumentImpl::popState()
                 if (!m_aStates.top().pCurrentBuffer)
                     m_pSdrImport->close();
                 else
-                    m_aStates.top().pCurrentBuffer->push_back(make_pair(BUFFER_ENDSHAPE, RTFValue::Pointer_t()));
+                    m_aStates.top().pCurrentBuffer->push_back(
+                            Buf_t(BUFFER_ENDSHAPE));
             }
             break;
         default:
@@ -4769,23 +4916,11 @@ int RTFDocumentImpl::popState()
         OSL_ASSERT(!m_aStates.empty() && m_aStates.top().pCurrentBuffer == 0);
 
         if (!m_bHasFootnote)
-            replayBuffer(m_aSuperBuffer);
+            replayBuffer(m_aSuperBuffer, 0, 0);
 
         m_bHasFootnote = false;
     }
 
-    if (!m_aStates.empty())
-    {
-        m_aStates.top().nCells = aState.nCells;
-        m_aStates.top().aTableCellsSprms = aState.aTableCellsSprms;
-        m_aStates.top().aTableCellsAttributes = aState.aTableCellsAttributes;
-
-        // Also the inherited properties should be kept accross groups.
-        m_aStates.top().aTableInheritingCellsSprms = aState.aTableInheritingCellsSprms;
-        m_aStates.top().aTableInheritingCellsAttributes = aState.aTableInheritingCellsAttributes;
-        m_aStates.top().nInheritingCells = aState.nInheritingCells;
-    }
-
     return 0;
 }
 
@@ -4872,8 +5007,6 @@ RTFParserState::RTFParserState(RTFDocumentImpl *pDocumentImpl)
     aTableRowAttributes(),
     aTableCellSprms(),
     aTableCellAttributes(),
-    aTableCellsSprms(),
-    aTableCellsAttributes(),
     aTabAttributes(),
     aCurrentColor(),
     nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0)),
@@ -4887,10 +5020,6 @@ RTFParserState::RTFParserState(RTFDocumentImpl *pDocumentImpl)
     aShape(),
     aDrawingObject(),
     aFrame(this),
-    nCellX(0),
-    nCells(0),
-    nInheritingCells(0),
-    nCellEnds(0),
     bIsCjk(false),
     nYear(0),
     nMonth(0),
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index e61b415..932ec46 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -13,6 +13,7 @@
 #include <stack>
 #include <queue>
 #include <boost/optional.hpp>
+#include <boost/tuple/tuple.hpp>
 
 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
@@ -44,6 +45,7 @@ namespace writerfilter {
         enum RTFBufferTypes
         {
             BUFFER_PROPS,
+            BUFFER_NESTROW,
             BUFFER_CELLEND,
             BUFFER_STARTRUN,
             BUFFER_TEXT,
@@ -77,8 +79,33 @@ namespace writerfilter {
             FIELD_RESULT
         };
 
+        struct TableRowBuffer;
+
         /// A buffer storing dmapper calls.
-        typedef std::deque< std::pair<RTFBufferTypes, RTFValue::Pointer_t> > RTFBuffer_t;
+        typedef ::boost::tuple<RTFBufferTypes, RTFValue::Pointer_t,
+                    ::boost::shared_ptr<TableRowBuffer> > Buf_t;
+        typedef std::deque< Buf_t > RTFBuffer_t;
+
+        /// holds one nested table row
+        struct TableRowBuffer
+        {
+            RTFBuffer_t buffer;
+            ::std::deque<RTFSprms> cellsSprms;
+            ::std::deque<RTFSprms> cellsAttributes;
+            int nCells;
+            writerfilter::Reference<Properties>::Pointer_t pParaProperties;
+            writerfilter::Reference<Properties>::Pointer_t pFrameProperties;
+            writerfilter::Reference<Properties>::Pointer_t pRowProperties;
+
+            TableRowBuffer(RTFBuffer_t const& rBuffer,
+                    ::std::deque<RTFSprms> const& rSprms,
+                    ::std::deque<RTFSprms> const& rAttributes,
+                    int const i_nCells)
+                : buffer(rBuffer)
+                , cellsSprms(rSprms), cellsAttributes(rAttributes)
+                , nCells(i_nCells)
+            {}
+        };
 
         /// An entry in the color table.
         class RTFColorTableEntry
@@ -199,12 +226,6 @@ namespace writerfilter {
                 // reset by cellx
                 RTFSprms aTableCellSprms;
                 RTFSprms aTableCellAttributes;
-                // reset by row/nestrow
-                std::deque<RTFSprms> aTableCellsSprms;
-                std::deque<RTFSprms> aTableCellsAttributes;
-                // backup of the above two, to support inheriting cell props
-                std::deque<RTFSprms> aTableInheritingCellsSprms;
-                std::deque<RTFSprms> aTableInheritingCellsAttributes;
                 // reset by tx
                 RTFSprms aTabAttributes;
 
@@ -232,12 +253,6 @@ namespace writerfilter {
                 RTFDrawingObject aDrawingObject;
                 RTFFrame aFrame;
 
-                /// Current cellx value.
-                int nCellX;
-                int nCells;
-                int nInheritingCells;
-                int nCellEnds;
-
                 /// CJK or CTL?
                 bool bIsCjk;
 
@@ -273,6 +288,14 @@ namespace writerfilter {
                 bool bStartedTrackchange; ///< Track change is started, need to end it before popping.
         };
 
+        // if std::stack had an operator[] this would be unnecessary...
+        struct RTFStack : public std::deque<RTFParserState>
+        {
+            RTFParserState & top() { return back(); }
+            void pop() { return pop_back(); }
+            void push(RTFParserState const& rState) {return push_back(rState);}
+        };
+
         class RTFTokenizer;
         class RTFSdrImport;
 
@@ -360,7 +383,23 @@ namespace writerfilter {
                 writerfilter::Reference<Properties>::Pointer_t getProperties(RTFSprms& rAttributes, RTFSprms& rSprms);
                 void checkNeedPap();
                 void sectBreak(bool bFinal);
-                void replayBuffer(RTFBuffer_t& rBuffer);
+                void prepareProperties(
+                    RTFParserState & rState,
+                    writerfilter::Reference<Properties>::Pointer_t &,
+                    writerfilter::Reference<Properties>::Pointer_t &,
+                    writerfilter::Reference<Properties>::Pointer_t &,
+                    int const nCells, int const nCurrentCellX);
+                void pushProperties(
+                    writerfilter::Reference<Properties>::Pointer_t const&,
+                    writerfilter::Reference<Properties>::Pointer_t const&,
+                    writerfilter::Reference<Properties>::Pointer_t const&);
+                void replayRowBuffer(RTFBuffer_t & rBuffer,
+                        ::std::deque<RTFSprms> & rCellsSrpms,
+                        ::std::deque<RTFSprms> & rCellsAttributes,
+                        int const nCells);
+                void replayBuffer(RTFBuffer_t& rBuffer,
+                        RTFSprms      *const pSprms,
+                        RTFSprms const*const pAttributes);
                 /// If we have some unicode or hex characters to send.
                 void checkUnicode(bool bUnicode, bool bHex);
                 /// If we need a final section break at the end of the document.
@@ -377,7 +416,7 @@ namespace writerfilter {
                 Stream* m_pMapperStream;
                 boost::shared_ptr<RTFSdrImport> m_pSdrImport;
                 boost::shared_ptr<RTFTokenizer> m_pTokenizer;
-                std::stack<RTFParserState> m_aStates;
+                RTFStack m_aStates;
                 /// Read by RTF_PARD.
                 RTFParserState m_aDefaultState;
                 bool m_bSkipUnknown;
@@ -407,8 +446,30 @@ namespace writerfilter {
                 oox::StorageRef m_xStorage;
                 boost::shared_ptr<oox::GraphicHelper> m_pGraphicHelper;
 
+                /// cell props buffer for nested tables, reset by \nestrow
+                /// the \nesttableprops is a destination and must follow the
+                /// nested cells, so it should be sufficient to store the
+                /// currently active one, no need for a stack of them
+                int m_nNestedCells;
+                std::deque<RTFSprms> m_aNestedTableCellsSprms;
+                std::deque<RTFSprms> m_aNestedTableCellsAttributes;
+                /// cell props buffer for top-level table, reset by \row
+                int m_nTopLevelCells;
+                std::deque<RTFSprms> m_aTopLevelTableCellsSprms;
+                std::deque<RTFSprms> m_aTopLevelTableCellsAttributes;
+                /// backup of top-level props, to support inheriting cell props
+                int m_nInheritingCells;
+                std::deque<RTFSprms> m_aTableInheritingCellsSprms;
+                std::deque<RTFSprms> m_aTableInheritingCellsAttributes;
+
+                /// Current cellx value (nested table)
+                int m_nNestedCurrentCellX;
+                /// Current cellx value (top-level table)
+                int m_nTopLevelCurrentCellX;
+
                 /// Buffered table cells, till cell definitions are not reached.
-                RTFBuffer_t m_aTableBuffer;
+                /// for nested table, one buffer per table level
+                std::deque< RTFBuffer_t > m_aTableBufferStack;
                 /// Buffered superscript, till footnote is reached (or not).
                 RTFBuffer_t m_aSuperBuffer;
 


More information about the Libreoffice-commits mailing list