1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <iostream>
21 #include <stdio.h>
22 #include "WW8TableInfo.hxx"
23 #include <fmtfsize.hxx>
24 #include "attributeoutputbase.hxx"
25 #include <swtable.hxx>
26 #include <frmfmt.hxx>
27 #include <pam.hxx>
28 #include <dbgoutsw.hxx>
29 #include <sal/log.hxx>
30 #include <osl/diagnose.h>
31 
32 namespace ww8
33 {
34 
WW8TableNodeInfoInner(WW8TableNodeInfo * pParent)35 WW8TableNodeInfoInner::WW8TableNodeInfoInner(WW8TableNodeInfo * pParent)
36 : mpParent(pParent)
37 , mnDepth(0)
38 , mnCell(0)
39 , mnRow(0)
40 , mnShadowsBefore(0)
41 , mnShadowsAfter(0)
42 , mbEndOfLine(false)
43 , mbFinalEndOfLine(false)
44 , mbEndOfCell(false)
45 , mbFirstInTable(false)
46 , mbVertMerge(false)
47 , mpTableBox(nullptr)
48 , mpTable(nullptr)
49 {
50 }
51 
~WW8TableNodeInfoInner()52 WW8TableNodeInfoInner::~WW8TableNodeInfoInner()
53 {
54 }
55 
setDepth(sal_uInt32 nDepth)56 void WW8TableNodeInfoInner::setDepth(sal_uInt32 nDepth)
57 {
58     mnDepth = nDepth;
59 }
60 
setCell(sal_uInt32 nCell)61 void WW8TableNodeInfoInner::setCell(sal_uInt32 nCell)
62 {
63     mnCell = nCell;
64 }
65 
setRow(sal_uInt32 nRow)66 void WW8TableNodeInfoInner::setRow(sal_uInt32 nRow)
67 {
68     mnRow = nRow;
69 }
70 
setShadowsBefore(sal_uInt32 nShadowsBefore)71 void WW8TableNodeInfoInner::setShadowsBefore(sal_uInt32 nShadowsBefore)
72 {
73     mnShadowsBefore = nShadowsBefore;
74 }
75 
setShadowsAfter(sal_uInt32 nShadowsAfter)76 void WW8TableNodeInfoInner::setShadowsAfter(sal_uInt32 nShadowsAfter)
77 {
78     mnShadowsAfter = nShadowsAfter;
79 }
80 
setEndOfLine(bool bEndOfLine)81 void WW8TableNodeInfoInner::setEndOfLine(bool bEndOfLine)
82 {
83     mbEndOfLine = bEndOfLine;
84 }
85 
setFinalEndOfLine(bool bFinalEndOfLine)86 void WW8TableNodeInfoInner::setFinalEndOfLine(bool bFinalEndOfLine)
87 {
88     mbFinalEndOfLine = bFinalEndOfLine;
89 }
90 
setEndOfCell(bool bEndOfCell)91 void WW8TableNodeInfoInner::setEndOfCell(bool bEndOfCell)
92 {
93     mbEndOfCell = bEndOfCell;
94 }
95 
setFirstInTable(bool bFirstInTable)96 void WW8TableNodeInfoInner::setFirstInTable(bool bFirstInTable)
97 {
98     mbFirstInTable = bFirstInTable;
99 }
100 
setVertMerge(bool bVertMerge)101 void WW8TableNodeInfoInner::setVertMerge(bool bVertMerge)
102 
103 {
104     mbVertMerge = bVertMerge;
105 }
106 
setTableBox(const SwTableBox * pTableBox)107 void WW8TableNodeInfoInner::setTableBox(const SwTableBox * pTableBox)
108 {
109     mpTableBox = pTableBox;
110 }
111 
setTable(const SwTable * pTable)112 void WW8TableNodeInfoInner::setTable(const SwTable * pTable)
113 {
114     mpTable = pTable;
115 }
116 
setRect(const SwRect & rRect)117 void WW8TableNodeInfoInner::setRect(const SwRect & rRect)
118 {
119     maRect = rRect;
120 }
121 
getNode() const122 const SwNode * WW8TableNodeInfoInner::getNode() const
123 {
124     const SwNode * pResult = nullptr;
125 
126     if (mpParent != nullptr)
127         pResult = mpParent->getNode();
128 
129     return pResult;
130 }
131 
getTableBoxesOfRow() const132 TableBoxVectorPtr WW8TableNodeInfoInner::getTableBoxesOfRow() const
133 {
134     TableBoxVectorPtr pResult = std::make_shared<TableBoxVector>();
135 
136     WW8TableCellGrid::Pointer_t pCellGrid =
137         mpParent->getParent()->getCellGridForTable(getTable(), false);
138 
139     if (!pCellGrid)
140     {
141         const SwTableLine * pTabLine = getTableBox()->GetUpper();
142         const SwTableBoxes & rTableBoxes = pTabLine->GetTabBoxes();
143 
144         sal_uInt8 nBoxes = rTableBoxes.size();
145         if (nBoxes > MAXTABLECELLS)
146             nBoxes = MAXTABLECELLS;
147         for ( sal_uInt8 n = 0; n < nBoxes; n++ )
148         {
149             pResult->push_back(rTableBoxes[n]);
150         }
151     }
152     else
153         pResult = pCellGrid->getTableBoxesOfRow(this);
154 
155     return pResult;
156 }
157 
getGridColsOfRow(AttributeOutputBase & rBase,bool calculateColumnsFromAllRows)158 GridColsPtr WW8TableNodeInfoInner::getGridColsOfRow(AttributeOutputBase & rBase, bool calculateColumnsFromAllRows)
159 {
160     GridColsPtr pResult = std::make_shared<GridCols>();
161     WidthsPtr pWidths;
162 
163     // Check which columns should be checked - only the current row,
164     // or all the rows together
165     if (calculateColumnsFromAllRows)
166     {
167                 // Calculate the width of all the columns based on ALL the rows.
168         // The difference is that this kind of draws vertical lines,
169         // so that if the rows look like this:
170         //
171         //  ------------------------
172         //  |                   |  |
173         //  ------------------------
174         //  |   |                  |
175         //  ------------------------
176         //  |       |              |
177         //  ------------------------
178 
179         // then the actual column widths will be broken down like this:
180         //
181         //  ------------------------
182         //  |   |   |           |  |
183         //  ------------------------
184 
185         // See the example at
186         // http://officeopenxml.com/WPtableGrid.php
187         // Under "Word 2007 Example"
188         pWidths = getColumnWidthsBasedOnAllRows();
189     }
190     else
191     {
192         // Calculate the width of all the columns based on the current row
193         pWidths = getWidthsOfRow();
194     }
195 
196     const SwFrameFormat *pFormat = getTable()->GetFrameFormat();
197     OSL_ENSURE(pFormat,"Impossible");
198     if (!pFormat)
199         return pResult;
200 
201     const SwFormatFrameSize &rSize = pFormat->GetFrameSize();
202     tools::ULong nTableSz = static_cast<tools::ULong>(rSize.GetWidth());
203 
204     tools::Long nPageSize = 0;
205     bool bRelBoxSize = false;
206 
207     rBase.GetTablePageSize( this, nPageSize, bRelBoxSize );
208 
209     SwTwips nSz = 0;
210     for (const auto& rWidth : *pWidths)
211     {
212         nSz += rWidth;
213         SwTwips nCalc = nSz;
214         if ( bRelBoxSize )
215             nCalc = ( nCalc * nPageSize ) / nTableSz;
216 
217         pResult->push_back( nCalc );
218     }
219 
220     return pResult;
221 }
222 
getColumnWidthsBasedOnAllRows() const223 WidthsPtr WW8TableNodeInfoInner::getColumnWidthsBasedOnAllRows() const
224 {
225     WidthsPtr pWidths;
226 
227     WW8TableCellGrid::Pointer_t pCellGrid =
228         mpParent->getParent()->getCellGridForTable(getTable(), false);
229 
230     if (!pCellGrid)
231     {
232         const SwTable * pTable = getTable();
233         const SwTableLines& rTableLines = pTable->GetTabLines();
234         const size_t nNumOfLines = rTableLines.size();
235 
236         // Go over all the rows - and for each row - calculate where
237         // there is a separator between columns
238         WidthsPtr pSeparators = std::make_shared<Widths>();
239         for ( size_t nLineIndex = 0; nLineIndex < nNumOfLines; ++nLineIndex )
240         {
241             const SwTableLine *pCurrentLine = rTableLines[nLineIndex];
242             const SwTableBoxes & rTabBoxes = pCurrentLine->GetTabBoxes();
243             size_t nBoxes = rTabBoxes.size();
244             if (nBoxes > MAXTABLECELLS)
245                 nBoxes = MAXTABLECELLS;
246 
247             sal_uInt32 nSeparatorPosition = 0;
248             for (size_t nBoxIndex = 0; nBoxIndex < nBoxes; ++nBoxIndex)
249             {
250                 const SwFrameFormat* pBoxFormat = rTabBoxes[ nBoxIndex ]->GetFrameFormat();
251                 const SwFormatFrameSize& rLSz = pBoxFormat->GetFrameSize();
252                 nSeparatorPosition += rLSz.GetWidth();
253                 pSeparators->push_back(nSeparatorPosition);
254             }
255         }
256 
257         // Sort the separator positions and remove any duplicates
258         std::sort(pSeparators->begin(), pSeparators->end());
259         std::vector<sal_uInt32>::iterator it = std::unique(pSeparators->begin(), pSeparators->end());
260         pSeparators->erase(it, pSeparators->end());
261 
262         // Calculate the widths based on the position of the unique & sorted
263         // column separators
264         pWidths = std::make_shared<Widths>();
265         sal_uInt32 nPreviousWidth = 0;
266         for (const sal_uInt32 nCurrentWidth : *pSeparators)
267         {
268             pWidths->push_back(nCurrentWidth - nPreviousWidth);
269             nPreviousWidth = nCurrentWidth;
270         }
271     }
272     else
273     {
274         pWidths = pCellGrid->getWidthsOfRow(this);
275     }
276 
277     return pWidths;
278 }
279 
getWidthsOfRow() const280 WidthsPtr WW8TableNodeInfoInner::getWidthsOfRow() const
281 {
282     WidthsPtr pWidths;
283 
284     WW8TableCellGrid::Pointer_t pCellGrid =
285         mpParent->getParent()->getCellGridForTable(getTable(), false);
286 
287     if (!pCellGrid)
288     {
289         const SwTableBox * pTabBox = getTableBox();
290         const SwTableLine * pTabLine = pTabBox->GetUpper();
291         const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
292 
293         pWidths = std::make_shared<Widths>();
294         // number of cell written
295         sal_uInt32 nBoxes = rTabBoxes.size();
296         if (nBoxes > MAXTABLECELLS)
297             nBoxes = MAXTABLECELLS;
298 
299         for (sal_uInt32 n = 0; n < nBoxes; n++)
300         {
301             const SwFrameFormat* pBoxFormat = rTabBoxes[ n ]->GetFrameFormat();
302             const SwFormatFrameSize& rLSz = pBoxFormat->GetFrameSize();
303 
304             pWidths->push_back(rLSz.GetWidth());
305         }
306     }
307     else
308         pWidths = pCellGrid->getWidthsOfRow(this);
309 
310     return pWidths;
311 }
312 
getRowSpansOfRow() const313 RowSpansPtr WW8TableNodeInfoInner::getRowSpansOfRow() const
314 {
315     RowSpansPtr pResult = std::make_shared<RowSpans>();
316 
317     WW8TableCellGrid::Pointer_t pCellGrid =
318         mpParent->getParent()->getCellGridForTable(getTable(), false);
319 
320     if (!pCellGrid)
321     {
322         const SwTableBox * pTabBox = getTableBox();
323         const SwTableLine * pTabLine = pTabBox->GetUpper();
324         const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
325 
326         sal_uInt32 nBoxes = rTabBoxes.size();
327         if (nBoxes > MAXTABLECELLS)
328             nBoxes = MAXTABLECELLS;
329 
330         for (sal_uInt32 n = 0; n < nBoxes; ++n)
331         {
332             pResult->push_back(rTabBoxes[n]->getRowSpan());
333         }
334     }
335     else
336         pResult = pCellGrid->getRowSpansOfRow(this);
337 
338     return pResult;
339  }
340 
341 
342 #ifdef DBG_UTIL
toString() const343 std::string WW8TableNodeInfoInner::toString() const
344 {
345     static char buffer[256];
346     snprintf(buffer, sizeof(buffer),
347              "<tableinner depth=\"%" SAL_PRIuUINT32 "\""
348              " cell=\"%" SAL_PRIuUINT32 "\""
349              " row=\"%" SAL_PRIuUINT32 "\""
350              " endOfCell=\"%s\""
351              " endOfLine=\"%s\""
352              " shadowsBefore=\"%" SAL_PRIuUINT32 "\""
353              " shadowsAfter=\"%" SAL_PRIuUINT32 "\""
354              " vertMerge=\"%s\"/>",
355              mnDepth, mnCell, mnRow,
356              mbEndOfCell ? "yes" : "no",
357              mbEndOfLine ? "yes" : "no",
358              mnShadowsBefore,
359              mnShadowsAfter,
360              mbVertMerge ? "yes" : "no");
361 
362     return std::string(buffer);
363 }
364 #endif
365 
WW8TableNodeInfo(WW8TableInfo * pParent,const SwNode * pNode)366 WW8TableNodeInfo::WW8TableNodeInfo(WW8TableInfo * pParent,
367                                    const SwNode * pNode)
368 : mpParent(pParent),
369   mnDepth(0),
370   mpNode(pNode),
371   mpNext(nullptr),
372   mpNextNode(nullptr)
373 {
374 }
375 
~WW8TableNodeInfo()376 WW8TableNodeInfo::~WW8TableNodeInfo()
377 {
378 }
379 
380 #ifdef DBG_UTIL
toString() const381 std::string WW8TableNodeInfo::toString() const
382 {
383     static char buffer[1024];
384     snprintf(buffer, sizeof(buffer),
385              "<tableNodeInfo p=\"%p\" depth=\"%" SAL_PRIuUINT32 "\">"
386              ,this, getDepth());
387 
388     std::string sResult(buffer);
389 
390     for (const auto& rInner : mInners)
391     {
392         WW8TableNodeInfoInner::Pointer_t pInner = rInner.second;
393         sResult += pInner->toString();
394     }
395     sResult += dbg_out(*mpNode);
396     sResult += "</tableNodeInfo>";
397 
398     return sResult;
399 }
400 #endif
401 
setDepth(sal_uInt32 nDepth)402 void WW8TableNodeInfo::setDepth(sal_uInt32 nDepth)
403 {
404     mnDepth = nDepth;
405 
406     Inners_t::iterator aIt = mInners.find(mnDepth);
407 
408     if (aIt == mInners.end())
409         mInners[mnDepth] = std::make_shared<ww8::WW8TableNodeInfoInner>(this);
410 
411     mInners[mnDepth]->setDepth(mnDepth);
412 }
413 
setEndOfLine(bool bEndOfLine)414 void WW8TableNodeInfo::setEndOfLine(bool bEndOfLine)
415 {
416     WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
417     pInner->setEndOfLine(bEndOfLine);
418 
419 #ifdef DBG_UTIL
420     SAL_INFO( "sw.ww8", "<endOfLine depth=\"" << mnDepth << "\">" << toString() << "</endOfLine>" );
421 #endif
422 }
423 
setEndOfCell(bool bEndOfCell)424 void WW8TableNodeInfo::setEndOfCell(bool bEndOfCell)
425 {
426     WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
427     pInner->setEndOfCell(bEndOfCell);
428 
429 #ifdef DBG_UTIL
430     SAL_INFO( "sw.ww8", "<endOfCell depth=\"" << mnDepth << "\">" << toString() << "</endOfCell>" );
431 #endif
432 }
433 
setFirstInTable(bool bFirstInTable)434 void WW8TableNodeInfo::setFirstInTable(bool bFirstInTable)
435 {
436     WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
437 
438     pInner->setFirstInTable(bFirstInTable);
439 
440 #ifdef DBG_UTIL
441     SAL_INFO( "sw.ww8", "<firstInTable depth=\"" << mnDepth << "\">" << toString() << "</firstInTable>" );
442 #endif
443 }
444 
setVertMerge(bool bVertMerge)445 void WW8TableNodeInfo::setVertMerge(bool bVertMerge)
446 {
447     WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
448 
449     pInner->setVertMerge(bVertMerge);
450 
451 #ifdef DBG_UTIL
452     SAL_INFO( "sw.ww8", "<vertMerge depth=\"" << mnDepth << "\">" << toString() << "</vertMerge>" );
453 #endif
454 }
455 
setTableBox(const SwTableBox * pTableBox)456 void WW8TableNodeInfo::setTableBox(const SwTableBox * pTableBox)
457 {
458     getInnerForDepth(mnDepth)->setTableBox(pTableBox);
459 }
460 
setTable(const SwTable * pTable)461 void WW8TableNodeInfo::setTable(const SwTable * pTable)
462 {
463     getInnerForDepth(mnDepth)->setTable(pTable);
464 }
465 
setNext(WW8TableNodeInfo * pNext)466 void WW8TableNodeInfo::setNext(WW8TableNodeInfo * pNext)
467 {
468     mpNext = pNext;
469 
470 #ifdef DBG_UTIL
471     SAL_INFO( "sw.ww8", "<setnext><from>" << toString() << "</from><to>" << pNext->toString() << "</to></setnext>" );
472 #endif
473 }
474 
setNextNode(const SwNode * pNode)475 void WW8TableNodeInfo::setNextNode(const SwNode * pNode)
476 {
477     mpNextNode = pNode;
478 }
479 
setRect(const SwRect & rRect)480 void WW8TableNodeInfo::setRect(const SwRect & rRect)
481 {
482     getInnerForDepth(mnDepth)->setRect(rRect);
483 }
484 
setCell(sal_uInt32 nCell)485 void WW8TableNodeInfo::setCell(sal_uInt32 nCell)
486 {
487     getInnerForDepth(mnDepth)->setCell(nCell);
488 }
489 
setRow(sal_uInt32 nRow)490 void WW8TableNodeInfo::setRow(sal_uInt32 nRow)
491 {
492     getInnerForDepth(mnDepth)->setRow(nRow);
493 }
494 
setShadowsBefore(sal_uInt32 nShadowsBefore)495 void WW8TableNodeInfo::setShadowsBefore(sal_uInt32 nShadowsBefore)
496 {
497     getInnerForDepth(mnDepth)->setShadowsBefore(nShadowsBefore);
498 }
499 
setShadowsAfter(sal_uInt32 nShadowsAfter)500 void WW8TableNodeInfo::setShadowsAfter(sal_uInt32 nShadowsAfter)
501 {
502     getInnerForDepth(mnDepth)->setShadowsAfter(nShadowsAfter);
503 }
504 
505 
getDepth() const506 sal_uInt32 WW8TableNodeInfo::getDepth() const
507 {
508     if (!mInners.empty())
509         return mInners.begin()->second->getDepth();
510 
511     return mnDepth;
512 }
513 
514 
getTableBox() const515 const SwTableBox * WW8TableNodeInfo::getTableBox() const
516 {
517     return getInnerForDepth(mnDepth)->getTableBox();
518 }
519 
getCell() const520 sal_uInt32 WW8TableNodeInfo::getCell() const
521 {
522     return getInnerForDepth(mnDepth)->getCell();
523 }
524 
getRow() const525 sal_uInt32 WW8TableNodeInfo::getRow() const
526 {
527     return getInnerForDepth(mnDepth)->getRow();
528 }
529 
getFirstInner() const530 WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getFirstInner() const
531 {
532     WW8TableNodeInfoInner::Pointer_t pResult;
533 
534     if (!mInners.empty())
535         pResult = mInners.begin()->second;
536 
537     return pResult;
538 }
539 
getInnerForDepth(sal_uInt32 nDepth) const540 WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getInnerForDepth(sal_uInt32 nDepth) const
541 {
542     WW8TableNodeInfoInner::Pointer_t pResult;
543 
544     Inners_t::const_iterator aIt = mInners.find(nDepth);
545     if (aIt != mInners.end())
546     {
547         pResult = aIt->second;
548     }
549 
550     return pResult;
551 }
552 
WW8TableInfo()553 WW8TableInfo::WW8TableInfo()
554 {
555 }
556 
~WW8TableInfo()557 WW8TableInfo::~WW8TableInfo()
558 {
559 }
560 
561 WW8TableNodeInfo *
processSwTableByLayout(const SwTable * pTable,RowEndInners_t & rLastRowEnds)562 WW8TableInfo::processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
563 {
564     SwTableCellInfo aTableCellInfo(pTable);
565 
566     while (aTableCellInfo.getNext())
567     {
568         SwRect aRect = aTableCellInfo.getRect();
569 
570         SAL_INFO( "sw.ww8", "<CellFrame>" );
571         SAL_INFO( "sw.ww8", "<rect top=\"" << aRect.Top() << "\" bottom=\"" << aRect.Bottom()
572             << "\" left=\"" << aRect.Left() << "\" right=\"" << aRect.Right() << "\"/>" );
573         const SwTableBox * pTableBox = aTableCellInfo.getTableBox();
574         const SwStartNode * pSttNd = pTableBox->GetSttNd();
575 
576         if (pSttNd != nullptr)
577         {
578             SwPaM aPam(*pSttNd, 0);
579 
580             bool bDone = false;
581             do
582             {
583                 SwNode & rNode = aPam.GetPoint()->nNode.GetNode();
584 
585                 insertTableNodeInfo(&rNode, pTable, pTableBox, 0, 0, 1, & aRect);
586 
587                 if (rNode.IsEndNode())
588                 {
589                     SwEndNode * pEndNode = rNode.GetEndNode();
590                     SwStartNode * pTmpSttNd = pEndNode->StartOfSectionNode();
591 
592                     if (pTmpSttNd == pSttNd)
593                         bDone = true;
594                 }
595 
596                 aPam.GetPoint()->nNode++;
597             }
598             while (!bDone);
599         }
600 
601         SAL_INFO( "sw.ww8", "</CellFrame>" );
602     }
603 
604     return reorderByLayout(pTable, rLastRowEnds);
605 }
606 
processSwTable(const SwTable * pTable)607 void WW8TableInfo::processSwTable(const SwTable * pTable)
608 {
609     SAL_INFO( "sw.ww8", "<processSwTable>" );
610 
611     WW8TableNodeInfo * pPrev = nullptr;
612     RowEndInners_t aLastRowEnds;
613 
614     if (pTable->IsTableComplex() && pTable->HasLayout())
615     {
616         pPrev = processSwTableByLayout(pTable, aLastRowEnds);
617 #ifdef DBG_UTIL
618         SAL_INFO( "sw.ww8", getCellGridForTable(pTable)->toString());
619 #endif
620     }
621     else
622     {
623         const SwTableLines & rLines = pTable->GetTabLines();
624 
625         for (size_t n = 0; n < rLines.size(); ++n)
626         {
627             const SwTableLine * pLine = rLines[n];
628 
629             pPrev = processTableLine(pTable, pLine, static_cast<sal_uInt32>(n), 1, pPrev, aLastRowEnds);
630         }
631 
632     }
633 
634     if (pPrev)
635     {
636         SwTableNode * pTableNode = pTable->GetTableNode();
637         SwEndNode * pEndNode = pTableNode->EndOfSectionNode();
638         pPrev->setNextNode(pEndNode);
639         assert(!aLastRowEnds.empty());
640         for (auto &a : aLastRowEnds)
641         {
642             assert(a.second->isEndOfLine());
643             a.second->setFinalEndOfLine(true);
644         }
645     }
646     SAL_INFO( "sw.ww8", "</processSwTable>" );
647 }
648 
649 WW8TableNodeInfo *
processTableLine(const SwTable * pTable,const SwTableLine * pTableLine,sal_uInt32 nRow,sal_uInt32 nDepth,WW8TableNodeInfo * pPrev,RowEndInners_t & rLastRowEnds)650 WW8TableInfo::processTableLine(const SwTable * pTable,
651                                const SwTableLine * pTableLine,
652                                sal_uInt32 nRow,
653                                sal_uInt32 nDepth,
654                                WW8TableNodeInfo * pPrev,
655                                RowEndInners_t &rLastRowEnds)
656 {
657     SAL_INFO( "sw.ww8", "<processTableLine row=\"" << nRow << "\" depth=\"" << nDepth << "\">" );
658 
659     const SwTableBoxes & rBoxes = pTableLine->GetTabBoxes();
660 
661     for (size_t n = 0; n < rBoxes.size(); ++n)
662     {
663         const SwTableBox * pBox = rBoxes[n];
664 
665         pPrev = processTableBox(pTable, pBox, nRow, static_cast<sal_uInt32>(n), nDepth, n == rBoxes.size() - 1, pPrev, rLastRowEnds);
666     }
667 
668     SAL_INFO( "sw.ww8", "</processTableLine>" );
669 
670     return pPrev;
671 }
672 
673 WW8TableNodeInfo::Pointer_t
processTableBoxLines(const SwTableBox * pBox,const SwTable * pTable,const SwTableBox * pBoxToSet,sal_uInt32 nRow,sal_uInt32 nCell,sal_uInt32 nDepth)674 WW8TableInfo::processTableBoxLines(const SwTableBox * pBox,
675                                    const SwTable * pTable,
676                                    const SwTableBox * pBoxToSet,
677                                    sal_uInt32 nRow,
678                                    sal_uInt32 nCell,
679                                    sal_uInt32 nDepth)
680 {
681     SAL_INFO( "sw.ww8", "<processTableBoxLines depth=\"" << nDepth << "\" row=\"" << nRow
682         << "\" cell=\"" << nCell << "\">" );
683 
684     const SwTableLines & rLines = pBox->GetTabLines();
685     WW8TableNodeInfo::Pointer_t pNodeInfo;
686 
687     if (!rLines.empty())
688     {
689         for (size_t n = 0; n < rLines.size(); ++n)
690         {
691             const SwTableLine * pLine = rLines[n];
692             const SwTableBoxes & rBoxes = pLine->GetTabBoxes();
693 
694             for (size_t nBox = 0; nBox < rBoxes.size(); ++nBox)
695                 pNodeInfo = processTableBoxLines(rBoxes[nBox], pTable, pBoxToSet, nRow, nCell, nDepth);
696         }
697     }
698     else
699     {
700         const SwStartNode * pSttNd = pBox->GetSttNd();
701         const SwEndNode * pEndNd = pSttNd->EndOfSectionNode();
702         SwPaM aPaM(*pSttNd, 0);
703         SwPaM aEndPaM(*pEndNd, 0);
704 
705         bool bDone = false;
706         while (!bDone)
707         {
708             SwNode & rNode = aPaM.GetPoint()->nNode.GetNode();
709 
710             pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBoxToSet, nRow, nCell, nDepth);
711 
712             if (aPaM.GetPoint()->nNode == aEndPaM.GetPoint()->nNode)
713                 bDone = true;
714             else
715                 aPaM.GetPoint()->nNode++;
716         }
717     }
718 
719     SAL_INFO( "sw.ww8", "</processTableBoxLines>" );
720 
721     return pNodeInfo;
722 }
723 
updateFinalEndOfLine(RowEndInners_t & rLastRowEnds,WW8TableNodeInfo const * pEndOfCellInfo)724 static void updateFinalEndOfLine(RowEndInners_t &rLastRowEnds, WW8TableNodeInfo const * pEndOfCellInfo)
725 {
726     sal_Int32 nDepth = pEndOfCellInfo->getDepth();
727     WW8TableNodeInfoInner::Pointer_t pInner = pEndOfCellInfo->getInnerForDepth(nDepth);
728 
729     auto aIt = rLastRowEnds.find(nDepth);
730     if (aIt == rLastRowEnds.end() || (pInner->getRow() > aIt->second->getRow()))
731         rLastRowEnds[nDepth] = pInner.get();
732 }
733 
734 WW8TableNodeInfo *
processTableBox(const SwTable * pTable,const SwTableBox * pBox,sal_uInt32 nRow,sal_uInt32 nCell,sal_uInt32 nDepth,bool bEndOfLine,WW8TableNodeInfo * pPrev,RowEndInners_t & rLastRowEnds)735 WW8TableInfo::processTableBox(const SwTable * pTable,
736                               const SwTableBox * pBox,
737                               sal_uInt32 nRow,
738                               sal_uInt32 nCell,
739                               sal_uInt32 nDepth,
740                               bool bEndOfLine,
741                               WW8TableNodeInfo * pPrev,
742                               RowEndInners_t &rLastRowEnds)
743 {
744     SAL_INFO( "sw.ww8", "<processTableBox row=\"" << nRow << "\" cell=\"" << nCell
745         << "\" depth=\"" << nDepth << "\">" );
746 
747     WW8TableNodeInfo::Pointer_t pNodeInfo;
748     const SwTableLines & rLines = pBox->GetTabLines();
749     const SwStartNode * pSttNd = pBox->GetSttNd();
750     WW8TableNodeInfo::Pointer_t pEndOfCellInfo;
751 
752     if (!rLines.empty())
753     {
754         pNodeInfo = processTableBoxLines(pBox, pTable, pBox, nRow, nCell, nDepth);
755         pNodeInfo->setEndOfCell(true);
756         if (bEndOfLine)
757         {
758             pNodeInfo->setEndOfLine(true);
759             updateFinalEndOfLine(rLastRowEnds, pNodeInfo.get());
760         }
761 
762         for (size_t n = 0; n < rLines.size(); n++)
763         {
764             const SwTableLine * pLine = rLines[n];
765 
766             pPrev = processTableLine(pTable, pLine, n, 1, pPrev, rLastRowEnds);
767         }
768     }
769     else
770     {
771         SwPaM aPaM(*pSttNd, 0);
772 
773         bool bDone = false;
774         sal_uInt32 nDepthInsideCell = 0;
775 
776         do
777         {
778             SwNode & rNode = aPaM.GetPoint()->nNode.GetNode();
779 
780             if (rNode.IsStartNode())
781             {
782                 if (nDepthInsideCell > 0)
783                     pEndOfCellInfo.reset();
784 
785                 nDepthInsideCell++;
786             }
787 
788             pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBox, nRow, nCell, nDepth);
789 
790             if (pPrev)
791                 pPrev->setNext(pNodeInfo.get());
792 
793             pPrev = pNodeInfo.get();
794 
795             if (nDepthInsideCell == 1 && rNode.IsTextNode())
796                 pEndOfCellInfo = pNodeInfo;
797 
798             if (rNode.IsEndNode())
799             {
800                 nDepthInsideCell--;
801 
802                 if (nDepthInsideCell == 0 && !pEndOfCellInfo)
803                     pEndOfCellInfo = pNodeInfo;
804 
805                 SwEndNode * pEndNode = rNode.GetEndNode( );
806                 SwStartNode * pTmpSttNd = pEndNode->StartOfSectionNode();
807                 if (pTmpSttNd == pSttNd)
808                     bDone = true;
809             }
810 
811             aPaM.GetPoint()->nNode++;
812         }
813         while (!bDone);
814 
815         if (pEndOfCellInfo)
816         {
817             pEndOfCellInfo->setEndOfCell(true);
818 
819             if (bEndOfLine)
820             {
821                 pEndOfCellInfo->setEndOfLine(true);
822                 updateFinalEndOfLine(rLastRowEnds, pEndOfCellInfo.get());
823             }
824         }
825     }
826 
827     SAL_INFO( "sw.ww8", "</processTableBox>" );
828 
829     return pPrev;
830 }
831 
insertTableNodeInfo(const SwNode * pNode,const SwTable * pTable,const SwTableBox * pTableBox,sal_uInt32 nRow,sal_uInt32 nCell,sal_uInt32 nDepth,SwRect const * pRect)832 WW8TableNodeInfo::Pointer_t WW8TableInfo::insertTableNodeInfo
833 (const SwNode * pNode,
834  const SwTable * pTable,
835  const SwTableBox * pTableBox,
836  sal_uInt32 nRow,
837  sal_uInt32 nCell,
838  sal_uInt32 nDepth,
839  SwRect const * pRect)
840 {
841     WW8TableNodeInfo::Pointer_t pNodeInfo = getTableNodeInfo(pNode);
842 
843     if (!pNodeInfo)
844     {
845         pNodeInfo =
846             std::make_shared<ww8::WW8TableNodeInfo>(this, pNode);
847         mMap.emplace(pNode, pNodeInfo);
848     }
849 
850     pNodeInfo->setDepth(nDepth + pNodeInfo->getDepth());
851 
852     pNodeInfo->setTable(pTable);
853     pNodeInfo->setTableBox(pTableBox);
854 
855     pNodeInfo->setCell(nCell);
856     pNodeInfo->setRow(nRow);
857 
858     if (pNode->IsTextNode())
859     {
860         FirstInTableMap_t::const_iterator aIt = mFirstInTableMap.find(pTable);
861         if (aIt == mFirstInTableMap.end())
862         {
863             mFirstInTableMap[pTable] = pNode;
864             pNodeInfo->setFirstInTable(true);
865         }
866     }
867 
868     if (pRect)
869     {
870         WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
871 
872         pCellGrid->insert(*pRect, pNodeInfo.get());
873         pNodeInfo->setRect(*pRect);
874     }
875 
876 #ifdef DBG_UTIL
877     SAL_INFO( "sw.ww8", pNodeInfo->toString());
878 #endif
879     return pNodeInfo;
880 }
881 
getCellGridForTable(const SwTable * pTable,bool bCreate)882 WW8TableCellGrid::Pointer_t WW8TableInfo::getCellGridForTable
883 (const SwTable * pTable, bool bCreate)
884 {
885     WW8TableCellGrid::Pointer_t pResult;
886     CellGridMap_t::iterator aIt = mCellGridMap.find(pTable);
887 
888     if (aIt == mCellGridMap.end())
889     {
890         if (bCreate)
891         {
892             pResult = std::make_shared<ww8::WW8TableCellGrid>();
893             mCellGridMap[pTable] = pResult;
894         }
895     }
896     else
897         pResult = mCellGridMap[pTable];
898 
899     return pResult;
900 }
901 
getTableNodeInfo(const SwNode * pNode)902 WW8TableNodeInfo::Pointer_t WW8TableInfo::getTableNodeInfo
903 (const SwNode * pNode)
904 {
905     WW8TableNodeInfo::Pointer_t pResult;
906     Map_t::iterator aIt = mMap.find(pNode);
907 
908     if (aIt != mMap.end())
909         pResult = (*aIt).second;
910 
911     return pResult;
912 }
913 
getNextNode(const SwNode * pNode)914 const SwNode * WW8TableInfo::getNextNode(const SwNode * pNode)
915 {
916     const SwNode * pResult = nullptr;
917 
918     WW8TableNodeInfo::Pointer_t pNodeInfo = getTableNodeInfo(pNode);
919 
920     if (pNodeInfo)
921     {
922         WW8TableNodeInfo * pNextInfo = pNodeInfo->getNext();
923 
924         if (pNextInfo != nullptr)
925             pResult = pNextInfo->getNode();
926         else
927         {
928             const SwNode * pNextNode = pNodeInfo->getNextNode();
929 
930             if (pNextNode != nullptr)
931                 pResult = pNextNode;
932         }
933     }
934 
935     return pResult;
936 }
937 
operator <(const WW8TableNodeInfo & rInfo) const938 bool WW8TableNodeInfo::operator < (const WW8TableNodeInfo & rInfo) const
939 {
940     bool bRet = false;
941 
942     if (rInfo.mpNode != nullptr)
943     {
944         if (mpNode == nullptr)
945         {
946             bRet = true;
947         }
948         else
949         {
950             if (mpNode->GetIndex() < rInfo.mpNode->GetIndex())
951                 bRet = true;
952         }
953     }
954 
955     return bRet;
956 }
957 
operator <(const CellInfo & aCellInfo) const958 bool CellInfo::operator < (const CellInfo & aCellInfo) const
959 {
960     bool aRet = false;
961 
962     if (top() < aCellInfo.top())
963         aRet = true;
964     else if (top() == aCellInfo.top())
965     {
966         if (left() < aCellInfo.left())
967             aRet = true;
968         else if (left() == aCellInfo.left())
969         {
970             if (width() < aCellInfo.width())
971                 aRet = true;
972             else if (width() == aCellInfo.width())
973             {
974                 if (height() < aCellInfo.height())
975                     aRet = true;
976                 else if (height() == aCellInfo.height())
977                 {
978                     if (aCellInfo.getTableNodeInfo())
979                     {
980                         if (m_pNodeInfo == nullptr)
981                             aRet = true;
982                         else
983                         {
984                             aRet = *m_pNodeInfo < *aCellInfo.getTableNodeInfo();
985                         }
986                     }
987                 }
988             }
989         }
990     }
991 
992     return aRet;
993 }
994 
995 #ifdef DBG_UTIL
toString() const996 std::string CellInfo::toString() const
997 {
998     static char sBuffer[256];
999 
1000     snprintf(sBuffer, sizeof(sBuffer),
1001              "<cellinfo left=\"%" SAL_PRIdINT64 "\""
1002              " right=\"%" SAL_PRIdINT64 "\""
1003              " top=\"%" SAL_PRIdINT64 "\""
1004              " bottom=\"%" SAL_PRIdINT64 "\""
1005              " node=\"%p\"/>",
1006              sal_Int64(left()),
1007              sal_Int64(right()),
1008              sal_Int64(top()),
1009              sal_Int64(bottom()),
1010              m_pNodeInfo);
1011 
1012     return sBuffer;
1013 }
1014 #endif
1015 
reorderByLayout(const SwTable * pTable,RowEndInners_t & rLastRowEnds)1016 WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
1017 {
1018     WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
1019 
1020 #ifdef DBG_UTIL
1021     SAL_INFO( "sw.ww8", pCellGrid->toString());
1022 #endif
1023 
1024     pCellGrid->addShadowCells();
1025     return pCellGrid->connectCells(rLastRowEnds);
1026 }
1027 
WW8TableCellGrid()1028 WW8TableCellGrid::WW8TableCellGrid()
1029 {
1030 }
1031 
~WW8TableCellGrid()1032 WW8TableCellGrid::~WW8TableCellGrid()
1033 {
1034 }
1035 
getRow(tools::Long nTop,bool bCreate)1036 WW8TableCellGridRow::Pointer_t WW8TableCellGrid::getRow(tools::Long nTop, bool bCreate)
1037 {
1038     WW8TableCellGridRow::Pointer_t pResult;
1039 
1040     RowTops_t::iterator aIt = m_aRowTops.find(nTop);
1041 
1042     if (aIt == m_aRowTops.end())
1043     {
1044         if (bCreate)
1045         {
1046             pResult = std::make_shared<ww8::WW8TableCellGridRow>();
1047             m_aRows[nTop] = pResult;
1048             m_aRowTops.insert(nTop);
1049         }
1050     }
1051     else
1052         pResult = m_aRows[nTop];
1053 
1054     return pResult;
1055 }
1056 
getRowTopsBegin() const1057 WW8TableCellGrid::RowTops_t::const_iterator WW8TableCellGrid::getRowTopsBegin() const
1058 {
1059     return m_aRowTops.begin();
1060 }
1061 
getRowTopsEnd() const1062 WW8TableCellGrid::RowTops_t::const_iterator WW8TableCellGrid::getRowTopsEnd() const
1063 {
1064     return m_aRowTops.end();
1065 }
1066 
getCellsBegin(tools::Long nTop)1067 CellInfoMultiSet::const_iterator WW8TableCellGrid::getCellsBegin(tools::Long nTop)
1068 {
1069     return getRow(nTop)->begin();
1070 }
1071 
getCellsEnd(tools::Long nTop)1072 CellInfoMultiSet::const_iterator WW8TableCellGrid::getCellsEnd(tools::Long nTop)
1073 {
1074     return getRow(nTop)->end();
1075 }
1076 
insert(const SwRect & rRect,WW8TableNodeInfo * pNodeInfo,const tools::ULong * pFormatFrameWidth)1077 void WW8TableCellGrid::insert(const SwRect & rRect,
1078                               WW8TableNodeInfo * pNodeInfo,
1079                               const tools::ULong * pFormatFrameWidth)
1080 {
1081     CellInfo aCellInfo(rRect, pNodeInfo);
1082 
1083     if (pFormatFrameWidth != nullptr)
1084         aCellInfo.setFormatFrameWidth(*pFormatFrameWidth);
1085 
1086     WW8TableCellGridRow::Pointer_t pRow = getRow(rRect.Top());
1087     pRow->insert(aCellInfo);
1088 }
1089 
addShadowCells()1090 void WW8TableCellGrid::addShadowCells()
1091 {
1092     SAL_INFO( "sw.ww8", "<addShadowCells>" );
1093 
1094     RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
1095 
1096     while (aTopsIt != getRowTopsEnd())
1097     {
1098         CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
1099         CellInfoMultiSet::const_iterator aCellEndIt = getCellsEnd(*aTopsIt);
1100 
1101         RowSpansPtr pRowSpans = std::make_shared<RowSpans>();
1102 
1103         bool bBeginningOfCell = true;
1104         bool bVertMerge = false;
1105         SwRect aRect = aCellIt->getRect();
1106         sal_Int32 nRowSpan = 1;
1107         while (aCellIt != aCellEndIt)
1108         {
1109             WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
1110 
1111             if (bBeginningOfCell)
1112             {
1113                 RowTops_t::const_iterator aRowSpanIt(aTopsIt);
1114                 ++aRowSpanIt;
1115 
1116                 if (aRowSpanIt != getRowTopsEnd() &&
1117                     *aRowSpanIt < aCellIt->bottom())
1118                 {
1119                     aRect.Top(*aRowSpanIt);
1120                     tools::ULong nFormatFrameWidth = aCellIt->getFormatFrameWidth();
1121                     insert(aRect, nullptr, &nFormatFrameWidth);
1122 
1123                     bVertMerge = true;
1124                 }
1125                 else
1126                     bVertMerge = false;
1127 
1128                 nRowSpan = 1;
1129                 while (aRowSpanIt != getRowTopsEnd() &&
1130                        *aRowSpanIt < aCellIt->bottom())
1131                 {
1132                     ++aRowSpanIt;
1133                     nRowSpan++;
1134                 }
1135 
1136                 if (pNodeInfo)
1137                     pRowSpans->push_back(nRowSpan);
1138                 else
1139                     pRowSpans->push_back(-nRowSpan);
1140             }
1141 
1142             if (pNodeInfo)
1143             {
1144                 pNodeInfo->setVertMerge(bVertMerge);
1145             }
1146 
1147             ++aCellIt;
1148             if (aCellIt != aCellEndIt)
1149             {
1150                 bBeginningOfCell = (aRect.Left() != aCellIt->left());
1151                 aRect = aCellIt->getRect();
1152             }
1153         }
1154 
1155         WW8TableCellGridRow::Pointer_t pRow = getRow(*aTopsIt);
1156         if (pRow)
1157             pRow->setRowSpans(pRowSpans);
1158 
1159         ++aTopsIt;
1160     }
1161     SAL_INFO( "sw.ww8", "</addShadowCells>" );
1162 }
1163 
connectCells(RowEndInners_t & rLastRowEnds)1164 WW8TableNodeInfo * WW8TableCellGrid::connectCells(RowEndInners_t &rLastRowEnds)
1165 {
1166     RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
1167     sal_uInt32 nRow = 0;
1168     WW8TableNodeInfo * pLastNodeInfo = nullptr;
1169 
1170     while (aTopsIt != getRowTopsEnd())
1171     {
1172         CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
1173         CellInfoMultiSet::const_iterator aCellEndIt = getCellsEnd(*aTopsIt);
1174         GridColsPtr pWidths = std::make_shared<Widths>();
1175         TableBoxVectorPtr pTableBoxes = std::make_shared<TableBoxVector>();
1176 
1177         sal_uInt32 nShadows = 0;
1178         sal_uInt32 nCell = 0;
1179         bool bBeginningOfCell = true;
1180         WW8TableNodeInfo * pEndOfCellInfo = nullptr;
1181         sal_uInt32 nDepthInCell = 0;
1182         while (aCellIt != aCellEndIt)
1183         {
1184             tools::Long nCellX = aCellIt->left();
1185             WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
1186             if (pNodeInfo)
1187             {
1188                 const SwNode * pNode = pNodeInfo->getNode();
1189 
1190                 if (pNode->IsStartNode())
1191                 {
1192                     nDepthInCell++;
1193                     pEndOfCellInfo = nullptr;
1194                 }
1195 
1196                 if (nDepthInCell == 1 && pNode->IsTextNode())
1197                     pEndOfCellInfo = pNodeInfo;
1198 
1199                 pNodeInfo->setShadowsBefore(nShadows);
1200                 pNodeInfo->setCell(nCell);
1201                 pNodeInfo->setRow(nRow);
1202                 if (pLastNodeInfo)
1203                 {
1204                     pLastNodeInfo->setNext(pNodeInfo);
1205                     pLastNodeInfo->setNextNode(pNode);
1206                 }
1207                 pLastNodeInfo = pNodeInfo;
1208                 nShadows = 0;
1209 
1210                 if (pNode->IsEndNode())
1211                 {
1212                     nDepthInCell--;
1213 
1214                     if (nDepthInCell == 0 && !pEndOfCellInfo)
1215                         pEndOfCellInfo = pNodeInfo;
1216                 }
1217             }
1218             else
1219             {
1220                 nShadows++;
1221             }
1222 
1223             if (bBeginningOfCell)
1224             {
1225                 pWidths->push_back(aCellIt->getFormatFrameWidth());
1226 
1227                 if (pNodeInfo)
1228                     pTableBoxes->push_back(pNodeInfo->getTableBox());
1229                 else
1230                     pTableBoxes->push_back(nullptr);
1231             }
1232 
1233             ++aCellIt;
1234             bBeginningOfCell = false;
1235 
1236             if (aCellIt != aCellEndIt && aCellIt->left() != nCellX)
1237             {
1238                 nCell++;
1239                 bBeginningOfCell = true;
1240 
1241                 if (pEndOfCellInfo)
1242                 {
1243                     pEndOfCellInfo->setEndOfCell(true);
1244                 }
1245 
1246                 pEndOfCellInfo = nullptr;
1247             }
1248         }
1249 
1250         pLastNodeInfo->setShadowsAfter(nShadows);
1251 
1252         if (!pEndOfCellInfo)
1253         {
1254             pEndOfCellInfo = pLastNodeInfo;
1255         }
1256 
1257         pEndOfCellInfo->setEndOfCell(true);
1258         pLastNodeInfo->setEndOfLine(true);
1259         updateFinalEndOfLine(rLastRowEnds, pLastNodeInfo);
1260 
1261         WW8TableCellGridRow::Pointer_t pRow(getRow(*aTopsIt));
1262         pRow->setTableBoxVector(pTableBoxes);
1263         pRow->setWidths(pWidths);
1264 
1265         ++aTopsIt;
1266         nRow++;
1267     }
1268 
1269     return pLastNodeInfo;
1270 }
1271 
1272 #ifdef DBG_UTIL
toString()1273 std::string WW8TableCellGrid::toString()
1274 {
1275     std::string sResult = "<WW8TableCellGrid>";
1276 
1277     RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
1278     static char sBuffer[1024];
1279     while (aTopsIt != getRowTopsEnd())
1280     {
1281         sprintf(sBuffer, "<row y=\"%" SAL_PRIdINT64 "\">", sal_Int64(*aTopsIt));
1282         sResult += sBuffer;
1283 
1284         CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
1285         CellInfoMultiSet::const_iterator aCellsEnd = getCellsEnd(*aTopsIt);
1286 
1287         while (aCellIt != aCellsEnd)
1288         {
1289             snprintf(sBuffer, sizeof(sBuffer), "<cellInfo top=\"%" SAL_PRIdINT64 "\" bottom=\"%" SAL_PRIdINT64 "\" left=\"%" SAL_PRIdINT64 "\" right=\"%" SAL_PRIdINT64 "\">",
1290                      sal_Int64(aCellIt->top()), sal_Int64(aCellIt->bottom()), sal_Int64(aCellIt->left()), sal_Int64(aCellIt->right()));
1291             sResult += sBuffer;
1292 
1293             WW8TableNodeInfo * pInfo = aCellIt->getTableNodeInfo();
1294             if (pInfo)
1295                 sResult += pInfo->toString();
1296             else
1297                 sResult += "<shadow/>\n";
1298 
1299             sResult += "</cellInfo>\n";
1300             ++aCellIt;
1301         }
1302 
1303         WW8TableCellGridRow::Pointer_t pRow = getRow(*aTopsIt);
1304         WidthsPtr pWidths = pRow->getWidths();
1305         if (pWidths != nullptr)
1306         {
1307             sResult += "<widths>";
1308 
1309             Widths::const_iterator aItEnd = pWidths->end();
1310             for (Widths::const_iterator aIt = pWidths->begin();
1311                  aIt != aItEnd;
1312                  ++aIt)
1313             {
1314                 if (aIt != pWidths->begin())
1315                     sResult += ", ";
1316 
1317                 snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32 "", *aIt);
1318                 sResult += sBuffer;
1319             }
1320 
1321             sResult += "</widths>";
1322         }
1323 
1324         RowSpansPtr pRowSpans = pRow->getRowSpans();
1325         if (pRowSpans)
1326         {
1327             sResult += "<rowspans>";
1328 
1329             RowSpans::const_iterator aItEnd = pRowSpans->end();
1330             for (RowSpans::const_iterator aIt = pRowSpans->begin();
1331                  aIt != aItEnd;
1332                  ++aIt)
1333             {
1334                 if (aIt != pRowSpans->begin())
1335                     sResult += ", ";
1336 
1337                 snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32 "", *aIt);
1338                 sResult += sBuffer;
1339             }
1340 
1341             sResult += "</rowspans>";
1342         }
1343 
1344         sResult += "</row>\n";
1345         ++aTopsIt;
1346     }
1347 
1348     sResult += "</WW8TableCellGrid>\n";
1349 
1350     return sResult;
1351 }
1352 #endif
1353 
getTableBoxesOfRow(WW8TableNodeInfoInner const * pNodeInfoInner)1354 TableBoxVectorPtr WW8TableCellGrid::getTableBoxesOfRow
1355 (WW8TableNodeInfoInner const * pNodeInfoInner)
1356 {
1357     TableBoxVectorPtr pResult;
1358     WW8TableCellGridRow::Pointer_t pRow =
1359         getRow(pNodeInfoInner->getRect().Top(), false);
1360 
1361     if (pRow)
1362     {
1363         pResult = pRow->getTableBoxVector();
1364     }
1365 
1366     return pResult;
1367 }
1368 
getWidthsOfRow(WW8TableNodeInfoInner const * pNodeInfoInner)1369 WidthsPtr WW8TableCellGrid::getWidthsOfRow
1370 (WW8TableNodeInfoInner const * pNodeInfoInner)
1371 {
1372     GridColsPtr pResult;
1373 
1374     WW8TableCellGridRow::Pointer_t pRow =
1375         getRow(pNodeInfoInner->getRect().Top(), false);
1376 
1377     if (pRow)
1378     {
1379         pResult = pRow->getWidths();
1380     }
1381 
1382     return pResult;
1383 }
1384 
getRowSpansOfRow(WW8TableNodeInfoInner const * pNodeInfoInner)1385 RowSpansPtr WW8TableCellGrid::getRowSpansOfRow
1386 (WW8TableNodeInfoInner const * pNodeInfoInner)
1387 {
1388     RowSpansPtr pResult;
1389 
1390     WW8TableCellGridRow::Pointer_t pRow =
1391         getRow(pNodeInfoInner->getRect().Top(), false);
1392 
1393     if (pRow)
1394     {
1395         pResult = pRow->getRowSpans();
1396     }
1397 
1398     return pResult;
1399 }
1400 
WW8TableCellGridRow()1401 WW8TableCellGridRow::WW8TableCellGridRow()
1402 : m_pCellInfos(std::make_shared<CellInfoMultiSet>())
1403 {
1404 }
1405 
~WW8TableCellGridRow()1406 WW8TableCellGridRow::~WW8TableCellGridRow()
1407 {
1408 }
1409 
insert(const CellInfo & rCellInfo)1410 void WW8TableCellGridRow::insert(const CellInfo & rCellInfo)
1411 {
1412     m_pCellInfos->insert(rCellInfo);
1413 
1414 #ifdef DBG_UTIL
1415     SAL_INFO( "sw.ww8", "<gridRowInsert>" << rCellInfo.toString() << "</gridRowInsert>" );
1416 #endif
1417 }
1418 
begin() const1419 CellInfoMultiSet::const_iterator WW8TableCellGridRow::begin() const
1420 {
1421     return m_pCellInfos->begin();
1422 }
1423 
end() const1424 CellInfoMultiSet::const_iterator WW8TableCellGridRow::end() const
1425 {
1426     return m_pCellInfos->end();
1427 }
1428 
setTableBoxVector(TableBoxVectorPtr const & pTableBoxVector)1429 void WW8TableCellGridRow::setTableBoxVector(TableBoxVectorPtr const & pTableBoxVector)
1430 {
1431     if (pTableBoxVector->size() > MAXTABLECELLS)
1432         pTableBoxVector->resize(MAXTABLECELLS);
1433     m_pTableBoxVector = pTableBoxVector;
1434 }
1435 
setWidths(WidthsPtr const & pWidths)1436 void WW8TableCellGridRow::setWidths(WidthsPtr const & pWidths)
1437 {
1438     m_pWidths = pWidths;
1439 }
1440 
setRowSpans(RowSpansPtr const & pRowSpans)1441 void WW8TableCellGridRow::setRowSpans(RowSpansPtr const & pRowSpans)
1442 {
1443     m_pRowSpans = pRowSpans;
1444 }
1445 
1446 
CellInfo(const SwRect & aRect,WW8TableNodeInfo * pNodeInfo)1447 CellInfo::CellInfo(const SwRect & aRect, WW8TableNodeInfo * pNodeInfo)
1448 : m_aRect(aRect), m_pNodeInfo(pNodeInfo), m_nFormatFrameWidth(0)
1449 {
1450     if (pNodeInfo != nullptr)
1451     {
1452         const SwTableBox * pBox = pNodeInfo->getTableBox();
1453         const SwFrameFormat * pFrameFormat = pBox->GetFrameFormat();
1454         const SwFormatFrameSize & rSize = pFrameFormat->GetFrameSize();
1455 
1456         m_nFormatFrameWidth = rSize.GetWidth();
1457     }
1458 }
1459 
1460 }
1461 
1462 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1463