Kaydet (Commit) c8f83ce1 authored tarafından Michael Stahl's avatar Michael Stahl

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.

Change-Id: Ic2d8f7b3e00844b224d61605b405ca651239e5f7
üst 8dcb56fd
...@@ -6,6 +6,26 @@ ...@@ -6,6 +6,26 @@
\f3\ftech\fcharset2 Symbol; \f3\ftech\fcharset2 Symbol;
\f4\fswiss\fcharset0 Helvetica; \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 {\info
{\*\userprops {\*\userprops
{\propname creator}\proptype30 {\propname creator}\proptype30
......
...@@ -1383,6 +1383,38 @@ DECLARE_RTFIMPORT_TEST(testNestedTable, "rhbz1065629.rtf") ...@@ -1383,6 +1383,38 @@ DECLARE_RTFIMPORT_TEST(testNestedTable, "rhbz1065629.rtf")
xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(OUString("Nom: John Doe"), xPara->getString()); 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") DECLARE_RTFIMPORT_TEST(testCp1000016, "hello.rtf")
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <stack> #include <stack>
#include <queue> #include <queue>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/tuple/tuple.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/beans/XPropertySet.hpp>
...@@ -44,6 +45,7 @@ namespace writerfilter { ...@@ -44,6 +45,7 @@ namespace writerfilter {
enum RTFBufferTypes enum RTFBufferTypes
{ {
BUFFER_PROPS, BUFFER_PROPS,
BUFFER_NESTROW,
BUFFER_CELLEND, BUFFER_CELLEND,
BUFFER_STARTRUN, BUFFER_STARTRUN,
BUFFER_TEXT, BUFFER_TEXT,
...@@ -77,8 +79,33 @@ namespace writerfilter { ...@@ -77,8 +79,33 @@ namespace writerfilter {
FIELD_RESULT FIELD_RESULT
}; };
struct TableRowBuffer;
/// A buffer storing dmapper calls. /// 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. /// An entry in the color table.
class RTFColorTableEntry class RTFColorTableEntry
...@@ -199,12 +226,6 @@ namespace writerfilter { ...@@ -199,12 +226,6 @@ namespace writerfilter {
// reset by cellx // reset by cellx
RTFSprms aTableCellSprms; RTFSprms aTableCellSprms;
RTFSprms aTableCellAttributes; 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 // reset by tx
RTFSprms aTabAttributes; RTFSprms aTabAttributes;
...@@ -232,12 +253,6 @@ namespace writerfilter { ...@@ -232,12 +253,6 @@ namespace writerfilter {
RTFDrawingObject aDrawingObject; RTFDrawingObject aDrawingObject;
RTFFrame aFrame; RTFFrame aFrame;
/// Current cellx value.
int nCellX;
int nCells;
int nInheritingCells;
int nCellEnds;
/// CJK or CTL? /// CJK or CTL?
bool bIsCjk; bool bIsCjk;
...@@ -273,6 +288,14 @@ namespace writerfilter { ...@@ -273,6 +288,14 @@ namespace writerfilter {
bool bStartedTrackchange; ///< Track change is started, need to end it before popping. 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 RTFTokenizer;
class RTFSdrImport; class RTFSdrImport;
...@@ -362,7 +385,23 @@ namespace writerfilter { ...@@ -362,7 +385,23 @@ namespace writerfilter {
writerfilter::Reference<Properties>::Pointer_t getProperties(RTFSprms& rAttributes, RTFSprms& rSprms); writerfilter::Reference<Properties>::Pointer_t getProperties(RTFSprms& rAttributes, RTFSprms& rSprms);
void checkNeedPap(); void checkNeedPap();
void sectBreak(bool bFinal); 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. /// If we have some unicode or hex characters to send.
void checkUnicode(bool bUnicode, bool bHex); void checkUnicode(bool bUnicode, bool bHex);
/// If we need a final section break at the end of the document. /// If we need a final section break at the end of the document.
...@@ -379,7 +418,7 @@ namespace writerfilter { ...@@ -379,7 +418,7 @@ namespace writerfilter {
Stream* m_pMapperStream; Stream* m_pMapperStream;
boost::shared_ptr<RTFSdrImport> m_pSdrImport; boost::shared_ptr<RTFSdrImport> m_pSdrImport;
boost::shared_ptr<RTFTokenizer> m_pTokenizer; boost::shared_ptr<RTFTokenizer> m_pTokenizer;
std::stack<RTFParserState> m_aStates; RTFStack m_aStates;
/// Read by RTF_PARD. /// Read by RTF_PARD.
RTFParserState m_aDefaultState; RTFParserState m_aDefaultState;
bool m_bSkipUnknown; bool m_bSkipUnknown;
...@@ -411,8 +450,30 @@ namespace writerfilter { ...@@ -411,8 +450,30 @@ namespace writerfilter {
oox::StorageRef m_xStorage; oox::StorageRef m_xStorage;
boost::shared_ptr<oox::GraphicHelper> m_pGraphicHelper; 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. /// 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). /// Buffered superscript, till footnote is reached (or not).
RTFBuffer_t m_aSuperBuffer; RTFBuffer_t m_aSuperBuffer;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment