src/lib/MSPUBCollector.cpp | 173 +++++++++++++++++++++++++++++++++------------ src/lib/MSPUBParser.cpp | 69 ++++++++++++++++- src/lib/TableInfo.h | 23 +++++ 3 files changed, 216 insertions(+), 49 deletions(-)
New commits: commit 3b6efdb66e92c4d3d93daa56930ead86bf4fb96a Author: David Tardon <dtar...@redhat.com> Date: Sun Dec 28 20:22:34 2014 +0100 handle merged cells Change-Id: I32c416d89e18d780d852a900f16a35d14531c209 diff --git a/src/lib/MSPUBCollector.cpp b/src/lib/MSPUBCollector.cpp index 04f5b6c..7f8cc84 100644 --- a/src/lib/MSPUBCollector.cpp +++ b/src/lib/MSPUBCollector.cpp @@ -9,6 +9,8 @@ #include <math.h> +#include <boost/multi_array.hpp> + #include <unicode/ucsdet.h> #include "MSPUBCollector.h" @@ -103,6 +105,79 @@ static void separateSpacesAndInsertText(librevenge::RVNGDrawingInterface *iface, separateTabsAndInsertText(iface, tmpText); } +struct TableLayoutCell +{ + TableLayoutCell() + : m_rowSpan(0) + , m_colSpan(0) + { + } + + unsigned m_rowSpan; + unsigned m_colSpan; +}; + +bool isCovered(const TableLayoutCell &cell) +{ + assert((cell.m_rowSpan == 0) == (cell.m_colSpan == 0)); + return (cell.m_rowSpan == 0) && (cell.m_colSpan == 0); +} + +typedef boost::multi_array<TableLayoutCell, 2> TableLayout; + +void createTableLayout(const std::vector<CellInfo> &cells, TableLayout &tableLayout) +{ + for (std::vector<CellInfo>::const_iterator it = cells.begin(); it != cells.end(); ++it) + { + if ((it->m_endRow >= tableLayout.shape()[0]) || (it->m_endColumn >= tableLayout.shape()[1])) + { + MSPUB_DEBUG_MSG(( + "cell %u (rows %u to %u, columns %u to %u) overflows the table, ignoring\n", + unsigned(int(it - cells.begin())), + it->m_startRow, it->m_endRow, + it->m_startColumn, it->m_endColumn, + )); + continue; + } + if (it->m_startRow > it->m_endRow) + { + MSPUB_DEBUG_MSG(( + "cell %u (rows %u to %u) has got negative row span, ignoring\n", + unsigned(int(it - cells.begin())), + it->m_startRow, it->m_endRow, + )); + continue; + } + if (it->m_startColumn > it->m_endColumn) + { + MSPUB_DEBUG_MSG(( + "cell %u (columns %u to %u) has got negative column span, ignoring\n", + unsigned(int(it - cells.begin())), + it->m_startColumn, it->m_endColumn, + )); + continue; + } + + const unsigned rowSpan = it->m_endRow - it->m_startRow + 1; + const unsigned colSpan = it->m_endColumn - it->m_startColumn + 1; + + if ((rowSpan == 0) != (colSpan == 0)) + { + MSPUB_DEBUG_MSG(( + "cell %u (rows %u to %u, columns %u to %u) has got 0 span in one dimension, ignoring\n", + unsigned(int(it - cells.begin())), + it->m_startRow, it->m_endRow, + it->m_startColumn, it->m_endColumn, + )); + continue; + } + + TableLayoutCell &layoutCell = tableLayout[it->m_startRow][it->m_startColumn]; + layoutCell.m_rowSpan = rowSpan; + layoutCell.m_colSpan = colSpan; + } +} + } // anonymous namespace void MSPUBCollector::addEOTFont(const librevenge::RVNGString &name, const librevenge::RVNGBinaryData &data) @@ -874,62 +949,72 @@ boost::function<void(void)> MSPUBCollector::paintShape(const ShapeInfo &info, co std::vector<unsigned> tableCellTextEnds; if (bool(info.m_tableCellTextEnds)) tableCellTextEnds = get(info.m_tableCellTextEnds); - unsigned row = 0; - unsigned column = 0; + TableLayout tableLayout(boost::extents[get(info.m_tableInfo).m_numRows][get(info.m_tableInfo).m_numColumns]); + createTableLayout(get(info.m_tableInfo).m_cells, tableLayout); + + unsigned cell = 0; unsigned para = 0; unsigned offset = 1; - for (unsigned cell = 0; cell != get(info.m_tableInfo).m_numColumns * get(info.m_tableInfo).m_numRows; ++cell) + for (unsigned row = 0; row != tableLayout.shape()[0]; ++row) { - assert(row < get(info.m_tableInfo).m_numRows); - assert(column < get(info.m_tableInfo).m_numColumns); - - if (column == 0) - m_painter->openTableRow(librevenge::RVNGPropertyList()); + m_painter->openTableRow(librevenge::RVNGPropertyList()); - librevenge::RVNGPropertyList cellProps; - cellProps.insert("librevenge:column", int(column)); - cellProps.insert("librevenge:row", int(row)); - m_painter->openTableCell(cellProps); - - if (cell < tableCellTextEnds.size()) + for (unsigned col = 0; col != tableLayout.shape()[1]; ++col) { - const unsigned cellEnd = tableCellTextEnds[cell]; - while ((para < text.size()) && (offset < cellEnd)) + librevenge::RVNGPropertyList cellProps; + cellProps.insert("librevenge:column", int(col)); + cellProps.insert("librevenge:row", int(row)); + + if (isCovered(tableLayout[row][col])) { - librevenge::RVNGPropertyList paraProps = getParaStyleProps(text[para].style, text[para].style.m_defaultCharStyleIndex); - m_painter->openParagraph(paraProps); - for (unsigned i_spans = 0; (i_spans < text[para].spans.size()) && (offset < cellEnd); ++i_spans) - { - librevenge::RVNGString textString; - appendCharacters(textString, text[para].spans[i_spans].chars, - getCalculatedEncoding()); - offset += textString.len(); - // TODO: why do we not drop these during parse already? - if ((i_spans == text[para].spans.size() - 1) && (textString == "\r")) - continue; - librevenge::RVNGPropertyList charProps = getCharStyleProps(text[para].spans[i_spans].style, text[para].style.m_defaultCharStyleIndex); - m_painter->openSpan(charProps); - separateSpacesAndInsertText(m_painter, textString); - m_painter->closeSpan(); - } + m_painter->insertCoveredTableCell(cellProps); + } + else + { + if (tableLayout[row][col].m_colSpan > 1) + cellProps.insert("table:number-columns-spanned", int(tableLayout[row][col].m_colSpan)); + if (tableLayout[row][col].m_rowSpan > 1) + cellProps.insert("table:number-rows-spanned", int(tableLayout[row][col].m_rowSpan)); + + m_painter->openTableCell(cellProps); - if (offset > cellEnd) + if (cell < tableCellTextEnds.size()) { - MSPUB_DEBUG_MSG(("cell text ends in the middle of a span!\n")); + const unsigned cellEnd = tableCellTextEnds[cell]; + while ((para < text.size()) && (offset < cellEnd)) + { + librevenge::RVNGPropertyList paraProps = getParaStyleProps(text[para].style, text[para].style.m_defaultCharStyleIndex); + m_painter->openParagraph(paraProps); + for (unsigned i_spans = 0; (i_spans < text[para].spans.size()) && (offset < cellEnd); ++i_spans) + { + librevenge::RVNGString textString; + appendCharacters(textString, text[para].spans[i_spans].chars, + getCalculatedEncoding()); + offset += textString.len(); + // TODO: why do we not drop these during parse already? + if ((i_spans == text[para].spans.size() - 1) && (textString == "\r")) + continue; + librevenge::RVNGPropertyList charProps = getCharStyleProps(text[para].spans[i_spans].style, text[para].style.m_defaultCharStyleIndex); + m_painter->openSpan(charProps); + separateSpacesAndInsertText(m_painter, textString); + m_painter->closeSpan(); + } + + if (offset > cellEnd) + { + MSPUB_DEBUG_MSG(("cell text ends in the middle of a span!\n")); + } + m_painter->closeParagraph(); + ++para; + } } - m_painter->closeParagraph(); - ++para; + + ++cell; + m_painter->closeTableCell(); } } - m_painter->closeTableCell(); - ++column; - if (column == get(info.m_tableInfo).m_numColumns) - { - m_painter->closeTableRow(); - ++row; - column = 0; - } + m_painter->closeTableRow(); } m_painter->endTableObject(); diff --git a/src/lib/MSPUBParser.cpp b/src/lib/MSPUBParser.cpp index 9b56db8..d2f3baa 100644 --- a/src/lib/MSPUBParser.cpp +++ b/src/lib/MSPUBParser.cpp @@ -751,6 +751,11 @@ bool MSPUBParser::parseShape(librevenge::RVNGInputStream *input, break; } } + + TableInfo ti(nr, nc); + ti.m_rowOffsetsInEmu = rowOffsetsInEmu; + ti.m_columnOffsetsInEmu = columnOffsetsInEmu; + if (!index) { MSPUB_DEBUG_MSG(("WARNING: Couldn't find cells of seqnum %u corresponding to table of seqnum %u.\n", @@ -759,11 +764,67 @@ bool MSPUBParser::parseShape(librevenge::RVNGInputStream *input, } else { - // Currently do nothing with the cells chunk. + const ContentChunkReference &cellsChunk = m_contentChunks[m_cellsChunkIndices[get(index)]]; + input->seek(cellsChunk.offset, librevenge::RVNG_SEEK_SET); + const unsigned cellsLength = readU32(input); + boost::optional<unsigned> cellCount; + while (stillReading(input, cellsChunk.offset + cellsLength)) + { + MSPUBBlockInfo info = parseBlock(input, true); + switch (info.id) + { + case 0x01: + cellCount = info.data; + break; + case 0x02: + { + input->seek(info.dataOffset + 4, librevenge::RVNG_SEEK_SET); + while (stillReading(input, info.dataOffset + info.dataLength)) + { + const MSPUBBlockInfo itemInfo = parseBlock(input, true); + if (itemInfo.id == 0) + { + input->seek(itemInfo.dataOffset + 4, librevenge::RVNG_SEEK_SET); + CellInfo currentCell; + while (stillReading(input, itemInfo.dataOffset + itemInfo.dataLength)) + { + const MSPUBBlockInfo subInfo = parseBlock(input, true); + switch (subInfo.id) + { + case 0x01: + currentCell.m_startRow = subInfo.data; + break; + case 0x02: + currentCell.m_endRow = subInfo.data; + break; + case 0x03: + currentCell.m_startColumn = subInfo.data; + break; + case 0x04: + currentCell.m_endColumn = subInfo.data; + break; + // TODO: 0x09 - 0x0e: width/height of content + margins? + default: + break; + } + } + ti.m_cells.push_back(currentCell); + } + } + + break; + } + default: + break; + } + } + + if (bool(cellCount) && (get(cellCount) != ti.m_cells.size())) + { + MSPUB_DEBUG_MSG(("%u cell records expected, but read %u\n", get(cellCount), ti.m_cells.size())); + } } - TableInfo ti(nr, nc); - ti.m_rowOffsetsInEmu = rowOffsetsInEmu; - ti.m_columnOffsetsInEmu = columnOffsetsInEmu; + m_collector->setShapeTableInfo(chunk.seqNum, ti); if (bool(textId)) m_collector->addTextShape(get(textId), chunk.seqNum); diff --git a/src/lib/TableInfo.h b/src/lib/TableInfo.h index f2e9688..7869c7c 100644 --- a/src/lib/TableInfo.h +++ b/src/lib/TableInfo.h @@ -10,16 +10,37 @@ #ifndef __TABLEINFO_H__ #define __TABLEINFO_H__ +#include <vector> + namespace libmspub { + +struct CellInfo +{ + CellInfo() + : m_startRow() + , m_endRow() + , m_startColumn() + , m_endColumn() + { + } + + unsigned m_startRow; + unsigned m_endRow; + unsigned m_startColumn; + unsigned m_endColumn; +}; + struct TableInfo { std::vector<unsigned> m_rowOffsetsInEmu; std::vector<unsigned> m_columnOffsetsInEmu; unsigned m_numRows; unsigned m_numColumns; + std::vector<CellInfo> m_cells; TableInfo(unsigned numRows, unsigned numColumns) : m_rowOffsetsInEmu(), - m_columnOffsetsInEmu(), m_numRows(numRows), m_numColumns(numColumns) + m_columnOffsetsInEmu(), m_numRows(numRows), m_numColumns(numColumns), + m_cells() { } }; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits