diff options
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf129452_excessBorder.docx | bin | 0 -> 11115 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport15.cxx | 11 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapperTableHandler.cxx | 22 | ||||
-rw-r--r-- | writerfilter/source/dmapper/TableManager.cxx | 34 | ||||
-rw-r--r-- | writerfilter/source/dmapper/TableManager.hxx | 4 |
5 files changed, 67 insertions, 4 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf129452_excessBorder.docx b/sw/qa/extras/ooxmlexport/data/tdf129452_excessBorder.docx Binary files differnew file mode 100644 index 000000000000..2bce3ff883bc --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf129452_excessBorder.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx index 27e2f22c2dbc..1e13de385fa4 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -45,6 +45,17 @@ DECLARE_OOXMLEXPORT_TEST(testTdf133370_columnBreak, "tdf133370_columnBreak.odt") CPPUNIT_ASSERT_EQUAL(1, getPages()); } +DECLARE_OOXMLEXPORT_TEST(testTdf129452_excessBorder, "tdf129452_excessBorder.docx") +{ + uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY); + uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY_THROW); + + // The outside border should not be applied on inside cells. The merge doesn't extend to the table bottom. + // [Note: as humans, we would call this cell D3, but since row 4 hasn't been analyzed yet, it is considered column C.] + table::BorderLine2 aBorder = getProperty<table::BorderLine2>(xTable->getCellByName("C3"), "BottomBorder"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("No bottom border on merged cell", sal_uInt32(0), aBorder.LineWidth); +} DECLARE_OOXMLEXPORT_TEST(testTdf134063, "tdf134063.docx") { diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx index 7da44a475efd..901fdfc0c115 100644 --- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx @@ -758,6 +758,9 @@ CellPropertyValuesSeq_t DomainMapperTableHandler::endTableGetCellProperties(Tabl } } + // Note that this is intentionally called "cell" and not "column". + // Don't make the mistake that all cell x's will be in the same column. + // Merged cells (grid span) in a row will affect the actual column. (fake cells were added to handle gridBefore) sal_Int32 nCell = 0; pCellProperties[nRow].realloc( aRowOfCellsIterator->size() ); beans::PropertyValues* pSingleCellProperties = pCellProperties[nRow].getArray(); @@ -905,10 +908,20 @@ CellPropertyValuesSeq_t DomainMapperTableHandler::endTableGetCellProperties(Tabl // tdf#129452 Checking if current cell is vertically merged with all the other cells below to the bottom. // This must be done in order to apply the bottom border of the table to the first cell in a vertical merge. bool bMergedVertically = bool(m_aCellProperties[nRow][nCell]->getProperty(PROP_VERTICAL_MERGE)); - - for (size_t i = nRow + 1; bMergedVertically && i < m_aCellProperties.size(); i++) - if ( m_aCellProperties[i].size() > sal::static_int_cast<std::size_t>(nCell) ) - bMergedVertically = bool(m_aCellProperties[i][nCell]->getProperty(PROP_VERTICAL_MERGE)); + if ( bMergedVertically ) + { + const sal_uInt32 nColumn = m_rDMapper_Impl.getTableManager().findColumn(nRow, nCell); + for (size_t i = nRow + 1; bMergedVertically && i < m_aCellProperties.size(); i++) + { + const sal_uInt32 nColumnCell = m_rDMapper_Impl.getTableManager().findColumnCell(i, nColumn); + if ( m_aCellProperties[i].size() > sal::static_int_cast<std::size_t>(nColumnCell) ) + { + bMergedVertically = bool(m_aCellProperties[i][nColumnCell]->getProperty(PROP_VERTICAL_MERGE)); + } + else + bMergedVertically = false; + } + } lcl_computeCellBorders( rInfo.pTableBorders, *aCellIterator, nCell, nRow, bIsEndCol, bIsEndRow, bMergedVertically ); @@ -1231,6 +1244,7 @@ void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTab TableParagraphVectorPtr pTableParagraphs = m_rDMapper_Impl.getTableManager().getCurrentParagraphs(); for (size_t nRow = 0; nRow < m_aTableRanges.size(); ++nRow) { + // Note that this is "cell" since you must not treat it as "column". for (size_t nCell = 0; nCell < m_aTableRanges[nRow].size(); ++nCell) { auto rStartPara = m_aTableRanges[nRow][nCell][0]; diff --git a/writerfilter/source/dmapper/TableManager.cxx b/writerfilter/source/dmapper/TableManager.cxx index 582b4d4705a6..2649ee1120e2 100644 --- a/writerfilter/source/dmapper/TableManager.cxx +++ b/writerfilter/source/dmapper/TableManager.cxx @@ -69,6 +69,40 @@ void TableManager::setCurrentGridSpan(sal_uInt32 nGridSpan) mTableDataStack.top()->getCurrentRow()->setCurrentGridSpan(nGridSpan); } +sal_uInt32 TableManager::findColumn(const sal_uInt32 nRow, const sal_uInt32 nCell) +{ + RowData::Pointer_t pRow = mTableDataStack.top()->getRow(nRow); + if (!pRow || nCell < pRow->getGridBefore() || nCell >= pRow->getCellCount()) + return SAL_MAX_UINT32; + + // The gridSpans provide a one-based index, so add up all the spans of the PREVIOUS columns, + // and that result will provide the first possible zero-based number for the desired column. + sal_uInt32 nColumn = 0; + for (sal_uInt32 n = 0; n < nCell; ++n) + nColumn += pRow->getGridSpan(n); + return nColumn; +} + +sal_uInt32 TableManager::findColumnCell(const sal_uInt32 nRow, const sal_uInt32 nCol) +{ + RowData::Pointer_t pRow = mTableDataStack.top()->getRow(nRow); + if (!pRow || nCol < pRow->getGridBefore()) + return SAL_MAX_UINT32; + + sal_uInt32 nCell = 0; + sal_uInt32 nGrids = 0; + // The gridSpans give us a one-based index, but requested column is zero-based - so keep that in mind. + for (const auto& rSpan : pRow->getGridSpans()) + { + nGrids += rSpan; + if (nCol < nGrids) + return nCell; + + ++nCell; + } + return SAL_MAX_UINT32; // must be in gridAfter or invalid column request +} + void TableManager::endOfRowAction() {} void TableManager::endOfCellAction() {} diff --git a/writerfilter/source/dmapper/TableManager.hxx b/writerfilter/source/dmapper/TableManager.hxx index d1c6ee431bc8..1cc7caaf958e 100644 --- a/writerfilter/source/dmapper/TableManager.hxx +++ b/writerfilter/source/dmapper/TableManager.hxx @@ -504,6 +504,10 @@ public: void setCurrentGridBefore( sal_uInt32 nSkipGrids ); std::vector<sal_uInt32> getCurrentGridSpans(); void setCurrentGridSpan( sal_uInt32 nGridSpan ); + /// Given a zero-based row/cell, return the zero-based grid it belongs to, or SAL_MAX_UINT16 for invalid. + sal_uInt32 findColumn( const sal_uInt32 nRow, const sal_uInt32 nCell ); + /// Given a zero-based row/col, return the zero-based cell describing that grid, or SAL_MAX_UINT16 for invalid. + sal_uInt32 findColumnCell( const sal_uInt32 nRow, const sal_uInt32 nCol ); void setTableStartsAtCellStart(bool bTableStartsAtCellStart); void setCellLastParaAfterAutospacing(bool bIsAfterAutospacing); |