summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2017-03-02 18:55:50 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2017-03-03 13:40:23 +0000
commitbb2a3df2d5b5a01aa58fb3567686e50762186036 (patch)
tree97a87c1008d200e4e3b2312313e7cb5f419dc96c
parenta51b7a1c3a7e7cf7b0c733e1dec40288278c1884 (diff)
tdf#106291: WW8 import: Properly treat column spans
Previous code unconditionally treated all cells in merge groups as rows span, thus in some conditions it merged incorrectly when there were cells from same row. The fix is inspired by SwTable::PrepareMerge(). Also, fixed improper adjustment of too narrow cells in WW8TabDesc::CalcDefaults(), which also happens in files where column spans are represented by spanned 1-twip-wide cells. Unit test included. Change-Id: I6c3803635f006dd396805d6847daa4d80c97cad4 Reviewed-on: https://gerrit.libreoffice.org/34820 Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com> Tested-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r--sw/qa/extras/ww8import/data/tdf106291.docbin0 -> 24064 bytes
-rw-r--r--sw/qa/extras/ww8import/ww8import.cxx9
-rw-r--r--sw/source/filter/ww8/ww8par2.cxx88
3 files changed, 82 insertions, 15 deletions
diff --git a/sw/qa/extras/ww8import/data/tdf106291.doc b/sw/qa/extras/ww8import/data/tdf106291.doc
new file mode 100644
index 000000000000..893004d46118
--- /dev/null
+++ b/sw/qa/extras/ww8import/data/tdf106291.doc
Binary files differ
diff --git a/sw/qa/extras/ww8import/ww8import.cxx b/sw/qa/extras/ww8import/ww8import.cxx
index c7f488fc2346..79c323f2ccde 100644
--- a/sw/qa/extras/ww8import/ww8import.cxx
+++ b/sw/qa/extras/ww8import/ww8import.cxx
@@ -65,6 +65,15 @@ DECLARE_WW8IMPORT_TEST(testTdf99120, "tdf99120.doc")
CPPUNIT_ASSERT_EQUAL(OUString("Section 2, even."), parseDump("/root/page[4]/header/txt/text()"));
}
+DECLARE_WW8IMPORT_TEST(testTdf106291, "tdf106291.doc")
+{
+ // Table cell was merged vertically instead of horizontally -> had incorrect dimensions
+ OUString cellWidth = parseDump("/root/page[1]/body/tab/row/cell[1]/infos/bounds", "width");
+ OUString cellHeight = parseDump("/root/page[1]/body/tab/row/cell[1]/infos/bounds", "height");
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(8660), cellWidth.toInt32());
+ CPPUNIT_ASSERT(cellHeight.toInt32() > 200); // height might depend on font size
+}
+
// tests should only be added to ww8IMPORT *if* they fail round-tripping in ww8EXPORT
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index f7ee7d273023..6b424a4d0594 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -75,10 +75,12 @@
using namespace ::com::sun::star;
+// Gets filled in WW8TabDesc::MergeCells().
+// Algorithm must ensure proper row and column order in WW8SelBoxInfo!
class WW8SelBoxInfo
{
private:
- std::vector<SwTableBox*> m_vBoxes;
+ std::vector<std::vector<SwTableBox*> > m_vRows;
WW8SelBoxInfo(WW8SelBoxInfo const&) = delete;
WW8SelBoxInfo& operator=(WW8SelBoxInfo const&) = delete;
@@ -92,11 +94,35 @@ public:
: nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
{}
- size_t size() const { return m_vBoxes.size(); }
+ size_t size() const
+ {
+ size_t nResult = 0;
+ for (auto& it : m_vRows)
+ nResult += it.size();
+ return nResult;
+ }
+
+ size_t rowsCount() const { return m_vRows.size(); }
- SwTableBox* operator[]( size_t nIndex ) { return m_vBoxes[nIndex]; }
+ const std::vector<SwTableBox*>& row( size_t nIndex ) { return m_vRows[nIndex]; }
- void push_back( SwTableBox* pBox ) { m_vBoxes.push_back(pBox); }
+ void push_back( SwTableBox* pBox )
+ {
+ bool bDone = false;
+ for (auto& iRow : m_vRows)
+ if (iRow[0]->GetUpper() == pBox->GetUpper())
+ {
+ iRow.push_back(pBox);
+ bDone = true;
+ break;
+ }
+ if (!bDone)
+ {
+ const size_t sz = m_vRows.size();
+ m_vRows.resize(sz+1);
+ m_vRows[sz].push_back(pBox);
+ }
+ }
};
WW8TabBandDesc::WW8TabBandDesc()
@@ -2118,6 +2144,15 @@ void WW8TabDesc::CalcDefaults()
if( pR->nCenter[0] < m_nMinLeft )
m_nMinLeft = pR->nCenter[0];
+ // Following adjustment moves a border and then uses it to find width
+ // of next cell, so collect current widths, to avoid situation when width
+ // adjustment to too narrow cell makes next cell have negative width
+ short nOrigWidth[MAX_COL + 1];
+ for( short i = 0; i < pR->nWwCols; i++ )
+ {
+ nOrigWidth[i] = pR->nCenter[i+1] - pR->nCenter[i];
+ }
+
for( short i = 0; i < pR->nWwCols; i++ )
{
/*
@@ -2130,10 +2165,20 @@ void WW8TabDesc::CalcDefaults()
#i28333# If the nGapHalf is greater than the cell width best to ignore it
*/
int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
+ if (nCellWidth != nOrigWidth[i])
+ {
+ if (nOrigWidth[i] == 0)
+ nCellWidth = 0; // restore zero-width "cell"
+ else if ((pR->nGapHalf >= nCellWidth) && (pR->nGapHalf < nOrigWidth[i]))
+ nCellWidth = pR->nGapHalf + 1; // avoid false ignore
+ else if ((nCellWidth <= 0) && (nOrigWidth[i] > 0))
+ nCellWidth = 1; // minimal non-zero width to minimize distortion
+ }
if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
{
- pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
+ nCellWidth = MINLAY + pR->nGapHalf * 2;
}
+ pR->nCenter[i + 1] = pR->nCenter[i] + nCellWidth;
}
if( pR->nCenter[pR->nWwCols] > m_nMaxRight )
@@ -2529,7 +2574,8 @@ void WW8TabDesc::MergeCells()
for (m_pActBand=m_pFirstBand, nRow=0; m_pActBand; m_pActBand=m_pActBand->pNextBand)
{
- // insert current box into merge group if appropriate
+ // insert current box into merge group if appropriate.
+ // The algorithm must ensure proper row and column order in WW8SelBoxInfo!
if( m_pActBand->pTCs )
{
for( short j = 0; j < m_pActBand->nRows; j++, nRow++ )
@@ -2729,18 +2775,30 @@ void WW8TabDesc::FinishSwTable()
// process all merge groups one by one
for (auto const& groupIt : m_MergeGroups)
{
- sal_uInt16 nActBoxCount = groupIt->size();
-
- if( ( 1 < nActBoxCount ) && (*groupIt)[0] )
+ if((1 < groupIt->size()) && groupIt->row(0)[0])
{
- const sal_uInt16 nRowSpan = groupIt->size();
+ SwFrameFormat* pNewFormat = groupIt->row(0)[0]->ClaimFrameFormat();
+ pNewFormat->SetFormatAttr(SwFormatFrameSize(ATT_VAR_SIZE, groupIt->nGroupWidth, 0));
+ const sal_uInt16 nRowSpan = groupIt->rowsCount();
for (sal_uInt16 n = 0; n < nRowSpan; ++n)
{
- SwTableBox* pCurrentBox = (*groupIt)[n];
- const long nRowSpanSet = n == 0 ?
- nRowSpan :
- ((-1) * (nRowSpan - n));
- pCurrentBox->setRowSpan( nRowSpanSet );
+ auto& rRow = groupIt->row(n);
+ for (size_t i = 0; i<rRow.size(); ++i)
+ {
+ const long nRowSpanSet = (n == 0) && (i == 0) ?
+ nRowSpan :
+ ((-1) * (nRowSpan - n));
+ SwTableBox* pCurrentBox = rRow[i];
+ pCurrentBox->setRowSpan(nRowSpanSet);
+
+ if (i == 0)
+ pCurrentBox->ChgFrameFormat(static_cast<SwTableBoxFormat*>(pNewFormat));
+ else
+ {
+ SwFrameFormat* pFormat = pCurrentBox->ClaimFrameFormat();
+ pFormat->SetFormatAttr(SwFormatFrameSize(ATT_VAR_SIZE, 0, 0));
+ }
+ }
}
}
}