From 6f9b3532ee81850500d9e87ad329c00ea9c83bba Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Tue, 9 Jun 2015 17:26:14 +0100 Subject: fix crash on export of ooo67471-2.sxw to docx This old-school table has three rows in it, but the second row is of 0 height so is indistinguisable from the third row by layout positioning, so the WW8TableNodeInfo view of the table is that it has two rows, and the comparison of being on the last row is done with the m_xTableWrt->GetRows view which considers it to have 3, so the table end marks are never output. add a new finalEndOfLine property that the WW8TableNodeInfo sets on the last end of row of the table as it sees it, which should resolve this. old style tables are a cess pit, which is why they were replaced Change-Id: I996aa59a338a594487f49ec0f228af3fb3032d15 --- sw/qa/extras/ooxmlexport/data/ooo67471-2.odt | Bin 0 -> 9511 bytes sw/qa/extras/ooxmlexport/ooxmlexport5.cxx | 6 ++ sw/source/filter/ww8/WW8TableInfo.cxx | 95 +++++++++++++++++---------- sw/source/filter/ww8/WW8TableInfo.hxx | 21 ++++-- sw/source/filter/ww8/docxattributeoutput.cxx | 4 +- 5 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 sw/qa/extras/ooxmlexport/data/ooo67471-2.odt (limited to 'sw') diff --git a/sw/qa/extras/ooxmlexport/data/ooo67471-2.odt b/sw/qa/extras/ooxmlexport/data/ooo67471-2.odt new file mode 100644 index 000000000000..82daa57763a7 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo67471-2.odt differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx index 5fe36fde8aa1..b63d7559f3a9 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx @@ -825,6 +825,12 @@ DECLARE_OOXMLEXPORT_TEST(testOO47778_2, "ooo47778-4.odt") assertXPathContent(pXmlDoc, "(//w:t)[4]", "c"); } +DECLARE_OOXMLEXPORT_TEST(testOO67471, "ooo67471-2.odt") +{ + if (xmlDocPtr pXmlDoc = parseExport("word/document.xml")) + assertXPathContent(pXmlDoc, "(//w:t)[2]", "B"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/WW8TableInfo.cxx b/sw/source/filter/ww8/WW8TableInfo.cxx index 4ccb45eb5bc5..91244f3a216b 100644 --- a/sw/source/filter/ww8/WW8TableInfo.cxx +++ b/sw/source/filter/ww8/WW8TableInfo.cxx @@ -40,6 +40,7 @@ WW8TableNodeInfoInner::WW8TableNodeInfoInner(WW8TableNodeInfo * pParent) , mnShadowsBefore(0) , mnShadowsAfter(0) , mbEndOfLine(false) +, mbFinalEndOfLine(false) , mbEndOfCell(false) , mbFirstInTable(false) , mbVertMerge(false) @@ -82,6 +83,11 @@ void WW8TableNodeInfoInner::setEndOfLine(bool bEndOfLine) mbEndOfLine = bEndOfLine; } +void WW8TableNodeInfoInner::setFinalEndOfLine(bool bFinalEndOfLine) +{ + mbFinalEndOfLine = bFinalEndOfLine; +} + void WW8TableNodeInfoInner::setEndOfCell(bool bEndOfCell) { mbEndOfCell = bEndOfCell; @@ -531,8 +537,6 @@ const SwTableBox * WW8TableNodeInfo::getTableBox() const return getInnerForDepth(mnDepth)->getTableBox(); } - - sal_uInt32 WW8TableNodeInfo::getCell() const { return getInnerForDepth(mnDepth)->getCell(); @@ -543,6 +547,10 @@ sal_uInt32 WW8TableNodeInfo::getRow() const return getInnerForDepth(mnDepth)->getRow(); } +bool WW8TableNodeInfo::isEndOfLine() const +{ + return getInnerForDepth(mnDepth)->isEndOfLine(); +} const WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getFirstInner() const { @@ -576,10 +584,9 @@ WW8TableInfo::~WW8TableInfo() } WW8TableNodeInfo * -WW8TableInfo::processSwTableByLayout(const SwTable * pTable) +WW8TableInfo::processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds) { SwTableCellInfo aTableCellInfo(pTable); - WW8TableNodeInfo * pPrev = NULL; while (aTableCellInfo.getNext()) { @@ -619,9 +626,7 @@ WW8TableInfo::processSwTableByLayout(const SwTable * pTable) SAL_INFO( "sw.ww8", "" ); } - pPrev = reorderByLayout(pTable); - - return pPrev; + return reorderByLayout(pTable, rLastRowEnds); } void WW8TableInfo::processSwTable(const SwTable * pTable) @@ -629,11 +634,11 @@ void WW8TableInfo::processSwTable(const SwTable * pTable) SAL_INFO( "sw.ww8", "" ); WW8TableNodeInfo * pPrev = NULL; + RowEndInners_t aLastRowEnds; if (pTable->IsTableComplex() && pTable->HasLayout()) { - pPrev = processSwTableByLayout(pTable); - + pPrev = processSwTableByLayout(pTable, aLastRowEnds); #ifdef DBG_UTIL SAL_INFO( "sw.ww8", getCellGridForTable(pTable)->toString()); #endif @@ -646,17 +651,22 @@ void WW8TableInfo::processSwTable(const SwTable * pTable) { const SwTableLine * pLine = rLines[n]; - pPrev = processTableLine(pTable, pLine, static_cast(n), 1, pPrev); + pPrev = processTableLine(pTable, pLine, static_cast(n), 1, pPrev, aLastRowEnds); } } - if (pPrev != NULL) + if (pPrev) { SwTableNode * pTableNode = pTable->GetTableNode(); SwEndNode * pEndNode = pTableNode->EndOfSectionNode(); - pPrev->setNextNode(pEndNode); + assert(!aLastRowEnds.empty()); + for (auto &a : aLastRowEnds) + { + assert(a.second->isEndOfLine()); + a.second->setFinalEndOfLine(true); + } } SAL_INFO( "sw.ww8", "" ); } @@ -665,7 +675,9 @@ WW8TableNodeInfo * WW8TableInfo::processTableLine(const SwTable * pTable, const SwTableLine * pTableLine, sal_uInt32 nRow, - sal_uInt32 nDepth, WW8TableNodeInfo * pPrev) + sal_uInt32 nDepth, + WW8TableNodeInfo * pPrev, + RowEndInners_t &rLastRowEnds) { SAL_INFO( "sw.ww8", "" ); @@ -677,7 +689,7 @@ WW8TableInfo::processTableLine(const SwTable * pTable, { const SwTableBox * pBox = rBoxes[n]; - pPrev = processTableBox(pTable, pBox, nRow, static_cast(n), nDepth, n == rBoxes.size() - 1, pPrev); + pPrev = processTableBox(pTable, pBox, nRow, static_cast(n), nDepth, n == rBoxes.size() - 1, pPrev, rLastRowEnds); } SAL_INFO( "sw.ww8", "" ); @@ -736,6 +748,16 @@ WW8TableInfo::processTableBoxLines(const SwTableBox * pBox, return pNodeInfo; } +void updateFinalEndOfLine(RowEndInners_t &rLastRowEnds, WW8TableNodeInfo* pEndOfCellInfo) +{ + sal_Int32 nDepth = pEndOfCellInfo->getDepth(); + WW8TableNodeInfoInner::Pointer_t pInner = pEndOfCellInfo->getInnerForDepth(nDepth); + + auto aIt = rLastRowEnds.find(nDepth); + if (aIt == rLastRowEnds.end() || (pInner->getRow() > aIt->second->getRow())) + rLastRowEnds[nDepth] = pInner.get(); +} + WW8TableNodeInfo * WW8TableInfo::processTableBox(const SwTable * pTable, const SwTableBox * pBox, @@ -743,7 +765,8 @@ WW8TableInfo::processTableBox(const SwTable * pTable, sal_uInt32 nCell, sal_uInt32 nDepth, bool bEndOfLine, - WW8TableNodeInfo * pPrev) + WW8TableNodeInfo * pPrev, + RowEndInners_t &rLastRowEnds) { SAL_INFO( "sw.ww8", "" ); @@ -758,13 +781,16 @@ WW8TableInfo::processTableBox(const SwTable * pTable, pNodeInfo = processTableBoxLines(pBox, pTable, pBox, nRow, nCell, nDepth); pNodeInfo->setEndOfCell(true); if (bEndOfLine) + { pNodeInfo->setEndOfLine(true); + updateFinalEndOfLine(rLastRowEnds, pNodeInfo.get()); + } for (size_t n = 0; n < rLines.size(); n++) { const SwTableLine * pLine = rLines[n]; - pPrev = processTableLine(pTable, pLine, n, 1, pPrev); + pPrev = processTableLine(pTable, pLine, n, 1, pPrev, rLastRowEnds); } } else @@ -788,7 +814,7 @@ WW8TableInfo::processTableBox(const SwTable * pTable, pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBox, nRow, nCell, nDepth); - if (pPrev != NULL) + if (pPrev) pPrev->setNext(pNodeInfo.get()); pPrev = pNodeInfo.get(); @@ -800,7 +826,7 @@ WW8TableInfo::processTableBox(const SwTable * pTable, { nDepthInsideCell--; - if (nDepthInsideCell == 0 && pEndOfCellInfo.get() == NULL) + if (nDepthInsideCell == 0 && !pEndOfCellInfo) pEndOfCellInfo = pNodeInfo; SwEndNode * pEndNode = rNode.GetEndNode( ); @@ -818,7 +844,10 @@ WW8TableInfo::processTableBox(const SwTable * pTable, pEndOfCellInfo->setEndOfCell(true); if (bEndOfLine) + { pEndOfCellInfo->setEndOfLine(true); + updateFinalEndOfLine(rLastRowEnds, pEndOfCellInfo.get()); + } } } @@ -973,7 +1002,7 @@ bool CellInfo::operator < (const CellInfo & aCellInfo) const aRet = true; else if (height() == aCellInfo.height()) { - if (aCellInfo.getTableNodeInfo() != NULL) + if (aCellInfo.getTableNodeInfo()) { if (m_pNodeInfo == NULL) aRet = true; @@ -1011,9 +1040,8 @@ bool CellInfo::operator < (const CellInfo & aCellInfo) const } #endif -WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable) +WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds) { - WW8TableNodeInfo * pPrev = NULL; WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable); #ifdef DBG_UTIL @@ -1021,9 +1049,7 @@ WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable) #endif pCellGrid->addShadowCells(); - pPrev = pCellGrid->connectCells(); - - return pPrev; + return pCellGrid->connectCells(rLastRowEnds); } WW8TableCellGrid::WW8TableCellGrid() @@ -1138,13 +1164,13 @@ void WW8TableCellGrid::addShadowCells() nRowSpan++; } - if (pNodeInfo != NULL) + if (pNodeInfo) pRowSpans->push_back(nRowSpan); else pRowSpans->push_back(-nRowSpan); } - if (pNodeInfo != NULL) + if (pNodeInfo) { pNodeInfo->setVertMerge(bVertMerge); } @@ -1166,7 +1192,7 @@ void WW8TableCellGrid::addShadowCells() SAL_INFO( "sw.ww8", "" ); } -WW8TableNodeInfo * WW8TableCellGrid::connectCells() +WW8TableNodeInfo * WW8TableCellGrid::connectCells(RowEndInners_t &rLastRowEnds) { RowTops_t::const_iterator aTopsIt = getRowTopsBegin(); sal_uInt32 nRow = 0; @@ -1188,7 +1214,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() { long nCellX = aCellIt->left(); WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo(); - if (pNodeInfo != NULL) + if (pNodeInfo) { const SwNode * pNode = pNodeInfo->getNode(); @@ -1204,7 +1230,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() pNodeInfo->setShadowsBefore(nShadows); pNodeInfo->setCell(nCell); pNodeInfo->setRow(nRow); - if (pLastNodeInfo != NULL) + if (pLastNodeInfo) { pLastNodeInfo->setNext(pNodeInfo); pLastNodeInfo->setNextNode(pNode); @@ -1216,7 +1242,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() { nDepthInCell--; - if (nDepthInCell == 0 && pEndOfCellInfo == NULL) + if (nDepthInCell == 0 && !pEndOfCellInfo) pEndOfCellInfo = pNodeInfo; } } @@ -1229,7 +1255,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() { pWidths->push_back(aCellIt->getFormatFrmWidth()); - if (pNodeInfo != NULL) + if (pNodeInfo) pTableBoxes->push_back(pNodeInfo->getTableBox()); else pTableBoxes->push_back(NULL); @@ -1243,7 +1269,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() nCell++; bBeginningOfCell = true; - if (pEndOfCellInfo != NULL) + if (pEndOfCellInfo) { pEndOfCellInfo->setEndOfCell(true); } @@ -1254,13 +1280,14 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() pLastNodeInfo->setShadowsAfter(nShadows); - if (pEndOfCellInfo == NULL) + if (!pEndOfCellInfo) { pEndOfCellInfo = pLastNodeInfo; } pEndOfCellInfo->setEndOfCell(true); pLastNodeInfo->setEndOfLine(true); + updateFinalEndOfLine(rLastRowEnds, pLastNodeInfo); WW8TableCellGridRow::Pointer_t pRow(getRow(*aTopsIt)); pRow->setTableBoxVector(pTableBoxes); @@ -1297,7 +1324,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells() sResult += sBuffer; WW8TableNodeInfo * pInfo = aCellIt->getTableNodeInfo(); - if (pInfo != NULL) + if (pInfo) sResult += pInfo->toString(); else sResult += "\n"; diff --git a/sw/source/filter/ww8/WW8TableInfo.hxx b/sw/source/filter/ww8/WW8TableInfo.hxx index 38e55b579eae..442f11d724b3 100644 --- a/sw/source/filter/ww8/WW8TableInfo.hxx +++ b/sw/source/filter/ww8/WW8TableInfo.hxx @@ -58,6 +58,7 @@ class WW8TableNodeInfoInner sal_uInt32 mnShadowsBefore; sal_uInt32 mnShadowsAfter; bool mbEndOfLine; + bool mbFinalEndOfLine; bool mbEndOfCell; bool mbFirstInTable; bool mbVertMerge; @@ -77,10 +78,11 @@ public: void setShadowsBefore(sal_uInt32 nShadowsBefore); void setShadowsAfter(sal_uInt32 nShadowsAfter); void setEndOfLine(bool bEndOfLine); + void setFinalEndOfLine(bool bEndOfLine); void setEndOfCell(bool bEndOfCell); void setFirstInTable(bool bFirstInTable); - void setVertMerge(bool bVertMErge); - void setTableBox(const SwTableBox * pTableBox); + void setVertMerge(bool bVertMerge); + void setTableBox(const SwTableBox *pTableBox); void setTable(const SwTable * pTable); void setRect(const SwRect & rRect); @@ -91,6 +93,7 @@ public: sal_uInt32 getShadowsAfter() const { return mnShadowsAfter;} bool isEndOfCell() const { return mbEndOfCell;} bool isEndOfLine() const { return mbEndOfLine;} + bool isFinalEndOfLine() const { return mbFinalEndOfLine;} bool isFirstInTable() const { return mbFirstInTable;} bool isVertMerge() const; const SwTableBox * getTableBox() const { return mpTableBox;} @@ -156,6 +159,9 @@ public: typedef ::std::multiset > CellInfoMultiSet; typedef boost::shared_ptr CellInfoMultiSetPtr; +typedef ::std::map > RowEndInners_t; + class WW8TableInfo; class WW8TableNodeInfo @@ -278,7 +284,7 @@ public: void insert(const SwRect & rRect, WW8TableNodeInfo * pNodeInfo, unsigned long * pFormatFrmWidth = NULL); void addShadowCells(); - WW8TableNodeInfo * connectCells(); + WW8TableNodeInfo *connectCells(RowEndInners_t &rLastRowEnds); #ifdef DBG_UTIL ::std::string toString(); @@ -305,14 +311,15 @@ class WW8TableInfo processTableLine(const SwTable * pTable, const SwTableLine * pTableLine, sal_uInt32 nRow, - sal_uInt32 nDepth, WW8TableNodeInfo * pPrev); + sal_uInt32 nDepth, WW8TableNodeInfo * pPrev, RowEndInners_t &rLastRowEnds); WW8TableNodeInfo * processTableBox(const SwTable * pTable, const SwTableBox * pTableBox, sal_uInt32 nRow, sal_uInt32 nCell, - sal_uInt32 nDepth, bool bEndOfLine, WW8TableNodeInfo * pPrev); + sal_uInt32 nDepth, bool bEndOfLine, + WW8TableNodeInfo * pPrev, RowEndInners_t &rLastRowEnds); WW8TableNodeInfo::Pointer_t processTableBoxLines(const SwTableBox * pBox, @@ -341,12 +348,12 @@ public: virtual ~WW8TableInfo(); void processSwTable(const SwTable * pTable); - WW8TableNodeInfo * processSwTableByLayout(const SwTable * pTable); + WW8TableNodeInfo * processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds); WW8TableNodeInfo::Pointer_t getTableNodeInfo(const SwNode * pNode); const SwNode * getNextNode(const SwNode * pNode); const WW8TableNodeInfo * getFirstTableNodeInfo() const; - WW8TableNodeInfo * reorderByLayout(const SwTable * pTable); + WW8TableNodeInfo * reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds); }; } diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index aecd1d1adac7..a0276c454627 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -718,8 +718,6 @@ void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointe InitTableHelper( pInner ); - const size_t nLinesCount = m_xTableWrt->GetRows().size(); - // HACK // msoffice seems to have an internal limitation of 63 columns for tables // and refuses to load .docx with more, even though the spec seems to allow that; @@ -763,7 +761,7 @@ void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointe EndTableRow(); // This is the end of the table - if ( pInner->isEndOfLine( ) && ( nRow + 1 ) == nLinesCount ) + if (pInner->isFinalEndOfLine()) EndTable(); } } -- cgit v1.2.3