sw/qa/extras/ww8import/data/tdf106291.doc |binary
 sw/qa/extras/ww8import/ww8import.cxx      |    9 ++
 sw/source/filter/ww8/ww8par2.cxx          |  103 ++++++++++++++++++++++++------
 3 files changed, 92 insertions(+), 20 deletions(-)

New commits:
commit 7d265e093bc8078471e87da85c625ef2365a1637
Author: Mike Kaganski <[email protected]>
Date:   Thu Mar 2 18:55:50 2017 +0300

    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: If043cfc466879d45141c655f7be1588792f898d3
    Reviewed-on: https://gerrit.libreoffice.org/34820
    Reviewed-by: Mike Kaganski <[email protected]>
    Tested-by: Mike Kaganski <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/34884
    Reviewed-by: Miklos Vajna <[email protected]>
    Tested-by: Miklos Vajna <[email protected]>

diff --git a/sw/qa/extras/ww8import/data/tdf106291.doc 
b/sw/qa/extras/ww8import/data/tdf106291.doc
new file mode 100644
index 0000000..893004d
Binary files /dev/null and b/sw/qa/extras/ww8import/data/tdf106291.doc differ
diff --git a/sw/qa/extras/ww8import/ww8import.cxx 
b/sw/qa/extras/ww8import/ww8import.cxx
index 1df4a6c..3220a52 100644
--- a/sw/qa/extras/ww8import/ww8import.cxx
+++ b/sw/qa/extras/ww8import/ww8import.cxx
@@ -553,6 +553,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
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index 80d5ca7c..f7693b0 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -75,9 +75,16 @@
 
 using namespace ::com::sun::star;
 
+// Gets filled in WW8TabDesc::MergeCells().
+// Algorithm must ensure proper row and column order in WW8SelBoxInfo!
 class WW8SelBoxInfo
-    : public std::vector<SwTableBox*>, private boost::noncopyable
 {
+private:
+    std::vector<std::vector<SwTableBox*> > m_vRows;
+
+    WW8SelBoxInfo(WW8SelBoxInfo const&) = delete;
+    WW8SelBoxInfo& operator=(WW8SelBoxInfo const&) = delete;
+
 public:
     short nGroupXStart;
     short nGroupWidth;
@@ -86,6 +93,36 @@ public:
     WW8SelBoxInfo(short nXCenter, short nWidth)
         : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
     {}
+
+    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(); }
+
+    const std::vector<SwTableBox*>& row( size_t nIndex ) { return 
m_vRows[nIndex]; }
+
+    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()
@@ -162,7 +199,7 @@ class WW8TabDesc: private boost::noncopyable
 
     // single box - maybe used in a merge group
     // (the merge groups are processed later at once)
-    SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
+    void UpdateTableMergeGroup(WW8_TCell& rCell,
         WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, sal_uInt16 nCol  );
     void StartMiserableHackForUnsupportedDirection(short nWwCol);
     void EndMiserableHackForUnsupportedDirection(short nWwCol);
@@ -2104,6 +2141,15 @@ void WW8TabDesc::CalcDefaults()
         if( pR->nCenter[0] < nMinLeft )
             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++ )
         {
            /*
@@ -2116,10 +2162,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] > nMaxRight )
@@ -2518,7 +2574,8 @@ void WW8TabDesc::MergeCells()
 
     for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=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( pActBand->pTCs )
         {
             for( short j = 0; j < pActBand->nRows; j++, nRow++ )
@@ -2703,18 +2760,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));
+                        }
+                    }
                 }
             }
         }
@@ -3257,14 +3326,11 @@ void WW8TabDesc::TableCellEnd()
 }
 
 // if necessary register the box for the merge group for this column
-SwTableBox* WW8TabDesc::UpdateTableMergeGroup(  WW8_TCell&     rCell,
+void WW8TabDesc::UpdateTableMergeGroup(  WW8_TCell&     rCell,
                                                 WW8SelBoxInfo* pActGroup,
                                                 SwTableBox*    pActBox,
                                                 sal_uInt16         nCol )
 {
-    // set default for return
-    SwTableBox* pResult = nullptr;
-
     // check if the box has to be merged
     // If cell is the first one to be merged, a new merge group has to be 
provided.
     // E.g., it could be that a cell is the first one to be merged, but no
@@ -3291,11 +3357,8 @@ SwTableBox* WW8TabDesc::UpdateTableMergeGroup(  
WW8_TCell&     rCell,
         {
             // add current box to merge group
             pTheMergeGroup->push_back(pActBox);
-            // return target box
-            pResult = (*pTheMergeGroup)[ 0 ];
         }
     }
-    return pResult;
 }
 
 sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as 
INDICATED within WW6 UI status line -1
_______________________________________________
Libreoffice-commits mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to