[Libreoffice-commits] libmspub.git: src/lib

David Tardon dtardon at redhat.com
Sun Dec 28 11:45:44 PST 2014


 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 <dtardon at 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()
   {
   }
 };


More information about the Libreoffice-commits mailing list