1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3  *
4  *  The Contents of this file are made available subject to the terms of
5  *  either of the following licenses
6  *
7  *         - GNU Lesser General Public License Version 2.1
8  *         - Sun Industry Standards Source License Version 1.1
9  *
10  *  Sun Microsystems Inc., October, 2000
11  *
12  *  GNU Lesser General Public License Version 2.1
13  *  =============================================
14  *  Copyright 2000 by Sun Microsystems, Inc.
15  *  901 San Antonio Road, Palo Alto, CA 94303, USA
16  *
17  *  This library is free software; you can redistribute it and/or
18  *  modify it under the terms of the GNU Lesser General Public
19  *  License version 2.1, as published by the Free Software Foundation.
20  *
21  *  This library is distributed in the hope that it will be useful,
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  *  Lesser General Public License for more details.
25  *
26  *  You should have received a copy of the GNU Lesser General Public
27  *  License along with this library; if not, write to the Free Software
28  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29  *  MA  02111-1307  USA
30  *
31  *
32  *  Sun Industry Standards Source License Version 1.1
33  *  =================================================
34  *  The contents of this file are subject to the Sun Industry Standards
35  *  Source License Version 1.1 (the "License"); You may not use this file
36  *  except in compliance with the License. You may obtain a copy of the
37  *  License at http://www.openoffice.org/license.html.
38  *
39  *  Software provided under this License is provided on an "AS IS" basis,
40  *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
41  *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
42  *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
43  *  See the License for the specific provisions governing your rights and
44  *  obligations concerning the Software.
45  *
46  *  The Initial Developer of the Original Code is: IBM Corporation
47  *
48  *  Copyright: 2008 by IBM Corporation
49  *
50  *  All Rights Reserved.
51  *
52  *  Contributor(s): _______________________________________
53  *
54  *
55  ************************************************************************/
56 /**
57  * @file
58  *  For LWP filter architecture prototype - table layouts
59  */
60 
61 #include <lwpglobalmgr.hxx>
62 #include "lwptablelayout.hxx"
63 #include <lwpfoundry.hxx>
64 #include "lwpholder.hxx"
65 #include "lwptable.hxx"
66 #include "lwptblcell.hxx"
67 #include "lwprowlayout.hxx"
68 #include <lwpfilehdr.hxx>
69 
70 #include <xfilter/xfstylemanager.hxx>
71 #include <xfilter/xftablestyle.hxx>
72 #include <xfilter/xfrow.hxx>
73 #include <xfilter/xfrowstyle.hxx>
74 #include <xfilter/xfcell.hxx>
75 #include <xfilter/xfcolstyle.hxx>
76 #include <xfilter/xfframestyle.hxx>
77 #include <xfilter/xfframe.hxx>
78 #include <xfilter/xffloatframe.hxx>
79 #include "lwpframelayout.hxx"
80 #include <xfilter/xfnumberstyle.hxx>
81 #include <xfilter/xfparastyle.hxx>
82 #include <o3tl/sorted_vector.hxx>
83 #include <sal/log.hxx>
84 
85 #include <algorithm>
86 #include <memory>
87 
LwpSuperTableLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)88 LwpSuperTableLayout::LwpSuperTableLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
89     : LwpPlacableLayout(objHdr, pStrm)
90 {
91     m_pFrame.reset(new LwpFrame(this) );
92 }
93 
~LwpSuperTableLayout()94 LwpSuperTableLayout::~LwpSuperTableLayout()
95 {
96 }
97 /**
98  * @short    Read super table layout record
99  */
Read()100 void LwpSuperTableLayout::Read()
101 {
102     LwpPlacableLayout::Read();
103     m_pObjStrm->SkipExtra();
104 
105 }
106 /**
107  * @short   Get child table layout
108  * @return pointer to table layout
109  */
GetTableLayout()110 LwpTableLayout* LwpSuperTableLayout::GetTableLayout()
111 {
112     LwpObjectID *pID = &GetChildTail();
113 
114     while(pID && !pID->IsNull())
115     {
116         LwpLayout* pLayout = dynamic_cast<LwpLayout*>(pID->obj().get());
117         if (!pLayout)
118         {
119             break;
120         }
121         if (pLayout->GetLayoutType() == LWP_TABLE_LAYOUT)
122         {
123             return dynamic_cast<LwpTableLayout *>(pLayout);
124         }
125         pID = &pLayout->GetPrevious();
126     }
127 
128     return nullptr;
129 }
130 /**
131  * @short   Get effective heading table layout, the one just before table layout is the only one which is effective
132  * @return LwpTableHeadingLayout* - pointer to table heading layout
133  */
GetTableHeadingLayout()134 LwpTableHeadingLayout* LwpSuperTableLayout::GetTableHeadingLayout()
135 {
136     LwpObjectID *pID = &GetChildTail();
137 
138     while(pID && !pID->IsNull())
139     {
140         LwpLayout * pLayout = dynamic_cast<LwpLayout *>(pID->obj().get());
141         if (!pLayout)
142         {
143             break;
144         }
145 
146         if (pLayout->GetLayoutType() == LWP_TABLE_HEADING_LAYOUT)
147         {
148             return dynamic_cast<LwpTableHeadingLayout *>(pLayout);
149         }
150         pID = &pLayout->GetPrevious();
151     }
152 
153     return nullptr;
154 }
155 /**
156  * @short   Register super table layout style
157  */
RegisterNewStyle()158 void LwpSuperTableLayout::RegisterNewStyle()
159 {
160     // if this layout is style of real table entry
161     LwpTableLayout* pTableLayout = GetTableLayout();
162     if (pTableLayout != nullptr)
163     {
164         pTableLayout->SetFoundry(m_pFoundry);
165         pTableLayout->RegisterStyle();
166     }
167 }
168 /**
169  * @short   Judge whether table size is according to content, borrowed from Word Pro code
170  * @param
171  * @return sal_Bool
172  */
IsSizeRightToContent()173 bool LwpSuperTableLayout::IsSizeRightToContent()
174 {
175     /* Only "with paragraph above" tables can size right to content. */
176     if (GetRelativeType() == LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE)
177         return LwpPlacableLayout::IsSizeRightToContent();
178 
179     return false;
180 }
181 /**
182  * @short   Judge whether table is justifiable, borrowed from Word Pro code
183  * @param
184  * @return sal_Bool
185  */
IsJustifiable()186 bool LwpSuperTableLayout::IsJustifiable()
187 {
188     return (GetRelativeType() != LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE || IsSizeRightToContent());
189 }
190 /**
191  * @short   Get width of frame outside table
192  * @param pTableStyle - pointer of XFTableStyle
193  * @return double - table width
194  */
GetWidth()195 double LwpSuperTableLayout::GetWidth()
196 {
197     double dWidth = GetTableWidth();
198     double dLeft    = GetMarginsValue(MARGIN_LEFT);
199     double dRight   = GetMarginsValue(MARGIN_RIGHT);
200 
201     return (dWidth + dLeft + dRight);
202 }
203 /**
204  * @short   Get width of table
205  * @param pTableStyle - pointer of XFTableStyle
206  * @return double - table width
207  */
GetTableWidth()208 double LwpSuperTableLayout::GetTableWidth()
209 {
210     sal_Int32 nWidth = 0;
211     if(!IsJustifiable() || ((nWidth = LwpMiddleLayout::GetMinimumWidth()) <= 0))
212     {
213         LwpTableLayout* pTableLayout = GetTableLayout();
214         if(!pTableLayout)
215         {
216             SAL_WARN("lwp", "missing table layout, early return");
217             return 0;
218         }
219         LwpTable *pTable = pTableLayout->GetTable();
220         if(!pTable)
221         {
222             SAL_WARN("lwp", "missing table, early return");
223             return 0;
224         }
225         double dDefaultWidth = pTable->GetWidth();
226         sal_uInt16 nCol = pTable->GetColumn();
227 
228         double dWidth = 0;
229 
230         for(sal_uInt16 i =0; i< nCol; i++)
231         {
232             LwpObjectID *pColumnID = &pTableLayout->GetColumnLayoutHead();
233             LwpColumnLayout * pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
234             double dColumnWidth = dDefaultWidth;
235             o3tl::sorted_vector<LwpColumnLayout*> aSeen;
236             while (pColumnLayout)
237             {
238                 aSeen.insert(pColumnLayout);
239                 if(pColumnLayout->GetColumnID() == i)
240                 {
241                     dColumnWidth = pColumnLayout->GetWidth();
242                     break;
243                 }
244                 pColumnID = &pColumnLayout->GetNext();
245                 pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
246                 if (aSeen.find(pColumnLayout) != aSeen.end())
247                     throw std::runtime_error("loop in conversion");
248             }
249             dWidth += dColumnWidth;
250         }
251 
252         return dWidth;
253     }
254 
255     double dLeft    = GetMarginsValue(MARGIN_LEFT);
256     double dRight   = GetMarginsValue(MARGIN_RIGHT);
257     return LwpTools::ConvertFromUnitsToMetric(nWidth)-dLeft-dRight;
258 
259 }
260 /**
261  * @short   Apply shadow to table
262  * @param pTableStyle - pointer of XFTableStyle
263  * @return
264  */
ApplyShadow(XFTableStyle * pTableStyle)265 void LwpSuperTableLayout::ApplyShadow(XFTableStyle *pTableStyle)
266 {
267     // use shadow property of supertable
268     std::unique_ptr<XFShadow> pXFShadow(GetXFShadow());
269     if(pXFShadow)
270     {
271         pTableStyle->SetShadow(pXFShadow->GetPosition(), pXFShadow->GetOffset(), pXFShadow->GetColor());
272     }
273 }
274 /**
275  * @short   Apply pattern fill to table style
276  * @param pTableStyle - pointer of XFTableStyle
277  * @return
278  */
ApplyPatternFill(XFTableStyle * pTableStyle)279 void LwpSuperTableLayout::ApplyPatternFill(XFTableStyle* pTableStyle)
280 {
281     std::unique_ptr<XFBGImage> xXFBGImage(GetFillPattern());
282     if (xXFBGImage)
283     {
284         pTableStyle->SetBackImage(xXFBGImage);
285     }
286 }
287 
288 /**
289  * @short   Apply background to table style
290  * @param pTableStyle - pointer of XFTableStyle
291  * @return
292  */
ApplyBackGround(XFTableStyle * pTableStyle)293 void LwpSuperTableLayout::ApplyBackGround(XFTableStyle* pTableStyle)
294 {
295     if (IsPatternFill())
296     {
297         ApplyPatternFill(pTableStyle);
298     }
299     else
300     {
301         ApplyBackColor(pTableStyle);
302     }
303 }
304 /**
305  * @short   Apply back color to table
306  * @param pTableStyle - pointer of XFTableStyle
307  * @return
308  */
ApplyBackColor(XFTableStyle * pTableStyle)309 void LwpSuperTableLayout::ApplyBackColor(XFTableStyle *pTableStyle)
310 {
311     LwpColor* pColor = GetBackColor();
312     if(pColor && pColor->IsValidColor())
313     {
314         XFColor aColor(pColor->To24Color());
315         pTableStyle->SetBackColor(aColor);
316     }
317 }
318 /**
319  * @short   Apply watermark to  table
320  * @param pTableStyle - pointer of XFTableStyle
321  * @return
322  */
ApplyWatermark(XFTableStyle * pTableStyle)323 void LwpSuperTableLayout::ApplyWatermark(XFTableStyle *pTableStyle)
324 {
325     std::unique_ptr<XFBGImage> xBGImage(GetXFBGImage());
326     if (xBGImage)
327     {
328         pTableStyle->SetBackImage(xBGImage);
329     }
330 }
331 /**
332  * @short   Apply alignment  to table
333  * @param pTableStyle - pointer of XFTableStyle
334  * @return
335  */
ApplyAlignment(XFTableStyle * pTableStyle)336 void LwpSuperTableLayout::ApplyAlignment(XFTableStyle * pTableStyle)
337 {
338     LwpPoint aPoint;
339     if (LwpLayoutGeometry* pGeometry = GetGeometry())
340         aPoint = pGeometry->GetOrigin();
341     double dXOffset = LwpTools::ConvertFromUnitsToMetric(aPoint.GetX());
342 
343     // add left padding to alignment distance
344     double dLeft = GetMarginsValue(MARGIN_LEFT);
345 
346     pTableStyle->SetAlign(enumXFAlignStart, dXOffset+ dLeft);
347 }
348 /**
349  * @short   Add table to container
350  * @param pCont - pointer of container
351  * @return pCont
352  */
XFConvert(XFContentContainer * pCont)353 void  LwpSuperTableLayout::XFConvert(XFContentContainer* pCont)
354 {
355     if ( LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE == GetRelativeType()
356             && (!GetContainerLayout().is() || !GetContainerLayout()->IsCell()) )
357     {
358         LwpTableLayout * pTableLayout = GetTableLayout();
359         if (pTableLayout)
360         {
361             pTableLayout->XFConvert(pCont);
362         }
363     }
364     else if(IsRelativeAnchored())
365     {
366         //anchor to paragraph except "with paragraph above"
367         XFConvertFrame(pCont);
368     }
369     else if(m_pFrame)
370     {
371         //anchor to page, frame, cell
372         m_pFrame->XFConvert(pCont);
373     }
374 }
375 /**
376  * @short   convert frame which anchor to page
377  * @param
378  * @return
379  */
XFConvertFrame(XFContentContainer * pCont,sal_Int32 nStart,sal_Int32 nEnd,bool bAll)380 void  LwpSuperTableLayout::XFConvertFrame(XFContentContainer* pCont, sal_Int32 nStart, sal_Int32 nEnd, bool bAll)
381 {
382     if(!m_pFrame)
383         return;
384 
385     rtl::Reference<XFFrame> xXFFrame;
386     if(nEnd < nStart)
387     {
388         xXFFrame.set(new XFFrame);
389     }
390     else
391     {
392         xXFFrame.set(new XFFloatFrame(nStart, nEnd, bAll));
393     }
394 
395     m_pFrame->Parse(xXFFrame.get(), static_cast<sal_uInt16>(nStart));
396     //parse table, and add table to frame
397     LwpTableLayout * pTableLayout = GetTableLayout();
398     if (pTableLayout)
399     {
400         pTableLayout->XFConvert(xXFFrame.get());
401     }
402     //add frame to the container
403     pCont->Add(xXFFrame.get());
404 
405 }
406 /**
407  * @short  register frame style
408  * @param
409  * @return
410  */
RegisterFrameStyle()411 void  LwpSuperTableLayout::RegisterFrameStyle()
412 {
413     std::unique_ptr<XFFrameStyle> xFrameStyle(new XFFrameStyle);
414     m_pFrame->RegisterStyle(xFrameStyle);
415 }
416 
LwpTableLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)417 LwpTableLayout::LwpTableLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
418     : LwpLayout(objHdr, pStrm)
419     , m_nRows(0)
420     , m_nCols(0)
421     , m_pDefaultCellLayout(nullptr)
422     , m_bConverted(false)
423 {
424 }
425 
426 /**
427  * @short   Get neighbour cell by specifying ROW+COL
428  * @param   nRow
429  * @param   nCol
430  * @return   LwpCellLayout *
431  */
GetCellByRowCol(sal_uInt16 nRow,sal_uInt16 nCol)432 LwpCellLayout * LwpTableLayout::GetCellByRowCol(sal_uInt16 nRow, sal_uInt16 nCol)
433 {
434     if (nRow >= m_nRows || nCol >= m_nCols)
435         return nullptr;
436 
437     return m_WordProCellsMap[static_cast<size_t>(nRow)*m_nCols + nCol];
438 }
439 
440 /**
441  * @short   traverse all table cells
442  * @param
443  * @param
444  * @param
445  */
TraverseTable()446 void LwpTableLayout::TraverseTable()
447 {
448     sal_uInt32 nCount = m_nRows*m_nCols;
449 
450     // new cell map nRow*nCOl and initialize
451     m_WordProCellsMap.insert(m_WordProCellsMap.end(), nCount, m_pDefaultCellLayout);
452 
453     // set value
454     LwpObjectID* pRowID = &GetChildHead();
455     LwpRowLayout * pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
456     o3tl::sorted_vector<LwpRowLayout*> aSeen;
457     while (pRowLayout)
458     {
459         aSeen.insert(pRowLayout);
460 
461         pRowLayout->SetRowMap();
462 
463         // for 's analysis job
464         m_RowsMap[pRowLayout->GetRowID()] = pRowLayout;
465         pRowLayout->CollectMergeInfo();
466         // end for 's analysis
467 
468         pRowID = &pRowLayout->GetNext();
469         pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
470         if (aSeen.find(pRowLayout) != aSeen.end())
471             throw std::runtime_error("loop in conversion");
472     }
473 }
474 
475 /**
476  * @short   search the cell map
477  * @param   nRow - row id (0 based)
478  * @param   nRow - row id (0 based)
479  * @return   LwpObjectID * - pointer to cell story object ID
480  */
SearchCellStoryMap(sal_uInt16 nRow,sal_uInt16 nCol)481 LwpObjectID * LwpTableLayout::SearchCellStoryMap(sal_uInt16 nRow, sal_uInt16 nCol)
482 {
483     if (nRow >= m_nRows || nCol >= m_nCols )
484     {
485         return nullptr;
486     }
487 
488     LwpCellLayout * pCell = GetCellByRowCol(nRow, nCol);
489     if (pCell)
490     {
491         // maybe connected cell layout
492         // maybe default cell layout
493         if (nRow != pCell->GetRowID() || nCol != pCell->GetColID())
494         {
495             return nullptr;
496         }
497         return &pCell->GetContent();
498     }
499 
500     return nullptr;
501 }
502 
503 /**
504  * @short   Get parent super table layout of table layout
505  * @return  LwpSuperTableLayout * - pointer of parent super table layout
506  */
GetSuperTableLayout()507 LwpSuperTableLayout * LwpTableLayout::GetSuperTableLayout()
508 {
509     return dynamic_cast<LwpSuperTableLayout *>(GetParent().obj().get());
510 }
511 /**
512  * @short    Get table pointer
513  * @return   LwpTable * - content table pointer
514  */
GetTable()515 LwpTable *  LwpTableLayout::GetTable()
516 {
517     return dynamic_cast<LwpTable *>(m_Content.obj().get());
518 }
519 /**
520  * @short   Get column style name by column ID
521  * @param   sal_uInt16 -- col id(0 based)
522  * @return OUString - name of column style
523  */
GetColumnWidth(sal_uInt16 nCol)524 OUString LwpTableLayout::GetColumnWidth(sal_uInt16 nCol)
525 {
526     if (nCol >= m_nCols)
527     {
528         assert(false);
529         return m_DefaultColumnStyleName;
530     }
531 
532     LwpColumnLayout * pCol = m_aColumns[nCol];
533     if (pCol)
534     {
535         return pCol->GetStyleName();
536     }
537 
538     return m_DefaultColumnStyleName;
539 }
540 /**
541  * @short   analyze all columns to get whole table width and width of all columns
542  * @short   and register all column styles
543  * @param   none
544  */
RegisterColumns()545 void LwpTableLayout::RegisterColumns()
546 {
547     LwpTable* pTable = GetTable();
548     if (!pTable)
549         throw std::range_error("corrupt LwpTableLayout");
550 
551     LwpSuperTableLayout* pSuper = GetSuperTableLayout();
552     if (!pSuper)
553         throw std::range_error("corrupt LwpTableLayout");
554 
555     sal_uInt16 nCols = m_nCols;
556 
557     m_aColumns.resize(nCols);
558     std::unique_ptr<bool[]> pWidthCalculated( new bool[nCols] );
559     for(sal_uInt16 i=0;i<nCols; i++)
560     {
561         pWidthCalculated[i] = false;
562         m_aColumns[i] = nullptr;
563     }
564 
565     double dDefaultColumn = pTable->GetWidth();
566     sal_uInt16 nJustifiableColumn = nCols;
567 
568     double dTableWidth = pSuper->GetTableWidth();
569 
570     // Get total width of justifiable columns
571     // NOTICE: all default columns are regarded as justifiable columns
572     LwpObjectID* pColumnID = &GetColumnLayoutHead();
573     LwpColumnLayout * pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
574     o3tl::sorted_vector<LwpColumnLayout*> aSeen;
575     while (pColumnLayout)
576     {
577         aSeen.insert(pColumnLayout);
578 
579         auto nColId = pColumnLayout->GetColumnID();
580         if (nColId >= nCols)
581         {
582             throw std::range_error("corrupt LwpTableLayout");
583         }
584         m_aColumns[nColId] = pColumnLayout;
585         if (!pColumnLayout->IsJustifiable())
586         {
587             pWidthCalculated[nColId] = true;
588             dTableWidth -= pColumnLayout->GetWidth();
589             nJustifiableColumn --;
590         }
591 
592         pColumnID = &pColumnLayout->GetNext();
593         pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
594 
595         if (aSeen.find(pColumnLayout) != aSeen.end())
596             throw std::runtime_error("loop in conversion");
597     }
598 
599     // if all columns are not justifiable, the rightmost column will be changed to justifiable
600     if (nJustifiableColumn == 0 && nCols != 0)
601     {
602         nJustifiableColumn ++;
603         if (m_aColumns[nCols - 1])
604         {
605             pWidthCalculated[nCols-1] = false;
606             dTableWidth += m_aColumns[nCols-1]->GetWidth();
607         }
608         else
609         {
610             // this can't happen
611             dTableWidth = dDefaultColumn;
612             assert(false);
613         }
614     }
615 
616     // justifiable columns will share the remain width averagely
617     dDefaultColumn = nJustifiableColumn ? dTableWidth/nJustifiableColumn : 0;
618 
619     // register default column style
620     std::unique_ptr<XFColStyle> xColStyle(new XFColStyle);
621     xColStyle->SetWidth(static_cast<float>(dDefaultColumn));
622 
623     XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
624     m_DefaultColumnStyleName =  pXFStyleManager->AddStyle(std::move(xColStyle)).m_pStyle->GetStyleName();
625 
626     // register existed column style
627     sal_uInt16 i=0;
628     for( i=0;i<nCols; i++)
629     {
630         if (m_aColumns[i])
631         {
632             m_aColumns[i]->SetFoundry(m_pFoundry);
633             if(!pWidthCalculated[i])
634             {
635                 // justifiable ----register style with calculated value
636                 m_aColumns[i]->SetStyleName(m_DefaultColumnStyleName);
637             }
638             else
639             {
640                 // not justifiable ---- register style with original value
641                 m_aColumns[i]->RegisterStyle(m_aColumns[i]->GetWidth());
642             }
643         }
644     }
645 }
646 /**
647  * @short    register all row styles
648  * @param   none
649  */
RegisterRows()650 void LwpTableLayout::RegisterRows()
651 {
652     LwpTable * pTable = GetTable();
653     if (pTable == nullptr)
654     {
655         assert(false);
656         return;
657     }
658 
659     // register default row style
660     std::unique_ptr<XFRowStyle> xRowStyle(new XFRowStyle);
661     if (m_nDirection & 0x0030)
662     {
663         xRowStyle->SetMinRowHeight(static_cast<float>(pTable->GetHeight()));
664     }
665     else
666     {
667         xRowStyle->SetRowHeight(static_cast<float>(pTable->GetHeight()));
668     }
669     XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
670     m_DefaultRowStyleName =  pXFStyleManager->AddStyle(std::move(xRowStyle)).m_pStyle->GetStyleName();
671 
672     // register style of rows
673     LwpObjectID * pRowID = &GetChildHead();
674     LwpRowLayout * pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
675     while (pRowLayout)
676     {
677         pRowLayout->SetFoundry(m_pFoundry);
678         pRowLayout->RegisterStyle();
679 
680         pRowID = &pRowLayout->GetNext();
681         pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
682     }
683 }
684 /**
685  * @short   register table style, if needed, including frame style
686  * @param   none
687  */
RegisterStyle()688 void LwpTableLayout::RegisterStyle()
689 {
690     // get super table layout
691     LwpSuperTableLayout * pSuper = GetSuperTableLayout();
692     if (!pSuper)
693         return;
694 
695     // get table
696     LwpTable * pTable = GetTable();
697     if (pTable == nullptr)
698     {
699         SAL_WARN("lwp", "missing table, early return");
700         return;
701     }
702 
703     // get row/column number of this table
704     m_nRows = pTable->GetRow();
705     m_nCols = pTable->GetColumn();
706     //http://www.danielsays.com/ss-gallery-win1x2x3x-lotus-word-pro-96.html
707     //tables with up to 255 rows and 8192 columns
708     //the row limit tallies with the casting of m_nCols to an unsigned char
709     //elsewhere
710     if (m_nRows > MAX_NUM_ROWS)
711         throw std::runtime_error("max legal row exceeded");
712     if (m_nCols > MAX_NUM_COLS)
713         throw std::runtime_error("max legal column exceeded");
714 
715     // get default cell layout of current table
716     LwpObjectID& rID= pTable->GetDefaultCellStyle();
717     m_pDefaultCellLayout = dynamic_cast<LwpCellLayout *>(rID.obj().get());
718 
719     // register columns styles
720     RegisterColumns();
721 
722     // register style of whole table
723     std::unique_ptr<XFTableStyle> xTableStyle(new XFTableStyle);
724 
725     sal_uInt8 nType = pSuper->GetRelativeType();
726     // If the table is not "with paragraph above" placement, create an frame style
727     // by supertable layout
728     if ( LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE == nType
729         && (!pSuper->GetContainerLayout().is() || !pSuper->GetContainerLayout()->IsCell()) )
730     {
731         //with para above
732         pSuper->ApplyBackGround(xTableStyle.get());
733         pSuper->ApplyWatermark(xTableStyle.get());
734         pSuper->ApplyShadow(xTableStyle.get());
735         pSuper->ApplyAlignment(xTableStyle.get());
736         xTableStyle->SetWidth(pSuper->GetTableWidth());
737     }
738     else
739     {
740         pSuper->RegisterFrameStyle();
741         xTableStyle->SetAlign(enumXFAlignCenter);
742         xTableStyle->SetWidth(pSuper->GetTableWidth());
743     }
744     XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
745     m_StyleName = pXFStyleManager->AddStyle(std::move(xTableStyle)).m_pStyle->GetStyleName();
746 
747     //convert to OO table now and register row style traverse
748     TraverseTable();
749 
750     SplitConflictCells();
751 
752     // Register rows layouts, it must be after SplitConflictCells
753     RegisterRows();
754 
755     // Parse table
756     ParseTable();
757 
758     // the old code doesn't check if the LwpFoundry pointer is NULL,
759     // so the NULL pointer cause sodc freeze. Add code to check the pointer.
760     if (GetFoundry())
761         PutCellVals(GetFoundry(), pTable->GetObjectID());
762 }
763 /**
764  * @short   read table layout
765  * @param   none
766  */
ParseTable()767 void LwpTableLayout::ParseTable()
768 {
769     // get super table layout
770     LwpSuperTableLayout* pSuper = GetSuperTableLayout();
771     if (!pSuper)
772     {
773         throw std::runtime_error("missing super table");
774     }
775 
776     if (m_pXFTable)
777     {
778         throw std::runtime_error("this table is already parsed");
779     }
780 
781     // set name of object
782     m_pXFTable.set(new XFTable);
783 
784     m_pXFTable->SetTableName(pSuper->GetName().str());
785     // set table style
786     m_pXFTable->SetStyleName(m_StyleName);
787 
788     sal_uInt16 nRow = m_nRows;
789     sal_uInt8 nCol = static_cast<sal_uInt8>(m_nCols);
790 
791     //process header rows
792     LwpTableHeadingLayout* pTableHeading;
793     pTableHeading = pSuper->GetTableHeadingLayout();
794     if (pTableHeading)
795     {
796         sal_uInt16 nStartHeadRow;
797         sal_uInt16 nEndHeadRow;
798         pTableHeading->GetStartEndRow(nStartHeadRow,nEndHeadRow);
799         if (nStartHeadRow != 0)
800             ConvertTable(m_pXFTable,0,nRow,0,nCol);
801         else
802         {
803             sal_uInt16 nContentRow = ConvertHeadingRow(m_pXFTable,nStartHeadRow,nEndHeadRow+1);
804             ConvertTable(m_pXFTable,nContentRow,nRow,0,nCol);
805         }
806     }
807     else
808         ConvertTable(m_pXFTable,0,nRow,0,nCol);
809 }
810 
811 /**
812  * @short   read table layout
813  * @param   none
814  */
Read()815 void LwpTableLayout::Read()
816 {
817     LwpLayout::Read();
818 
819     // before layout hierarchy rework!
820     if(LwpFileHeader::m_nFileRevision < 0x000b)
821     {
822         assert(false);
823     }
824     m_ColumnLayout.ReadIndexed(m_pObjStrm.get());
825 
826     m_pObjStrm->SkipExtra();
827 }
828 
829 /**
830  * @short    Convert table
831  * @param
832  * @return   pCont - container which will contain table
833  */
XFConvert(XFContentContainer * pCont)834 void LwpTableLayout::XFConvert(XFContentContainer* pCont)
835 {
836     if (!m_pXFTable)
837         return;
838     if (m_bConverted)
839         throw std::runtime_error("already added to a container");
840     pCont->Add(m_pXFTable.get());
841     m_bConverted = true;
842 }
843 
844 /**
845  * @short   convert heading row
846  * @param  pXFTable - pointer of table
847  * @param  nStartRow - start heading row ID
848  * @param  nEndRow - end heading row ID
849  */
ConvertHeadingRow(rtl::Reference<XFTable> const & pXFTable,sal_uInt16 nStartHeadRow,sal_uInt16 nEndHeadRow)850 sal_uInt16 LwpTableLayout::ConvertHeadingRow(
851         rtl::Reference<XFTable> const & pXFTable, sal_uInt16 nStartHeadRow, sal_uInt16 nEndHeadRow)
852 {
853     sal_uInt16 nContentRow;
854     LwpTable* pTable = GetTable();
855     assert(pTable);
856     sal_uInt8 nCol = static_cast<sal_uInt8>(pTable->GetColumn());
857     rtl::Reference<XFTable> pTmpTable( new XFTable );
858 
859     ConvertTable(pTmpTable,nStartHeadRow,nEndHeadRow,0,nCol);
860 
861     sal_uInt16 nRowNum = pTmpTable->GetRowCount();
862     std::vector<sal_uInt8> CellMark(nRowNum);
863 
864     if (nRowNum == 1)
865     {
866         XFRow* pXFRow = pTmpTable->GetRow(1);
867         pXFTable->AddHeaderRow(pXFRow);
868         pTmpTable->RemoveRow(1);
869         nContentRow = nEndHeadRow;
870     }
871     else
872     {
873         sal_uInt8 nFirstColSpann = 1;
874         const bool bFindFlag = FindSplitColMark(pTmpTable.get(), CellMark, nFirstColSpann);
875 
876         if (bFindFlag)//split to 2 cells
877         {
878             SplitRowToCells(pTmpTable.get(), pXFTable, nFirstColSpann, CellMark.data());
879             nContentRow = nEndHeadRow;
880         }
881         else//can not split,the first row will be the heading row,the rest will be content row
882         {
883             XFRow* pXFRow = pTmpTable->GetRow(1);
884             pXFTable->AddHeaderRow(pXFRow);
885             pTmpTable->RemoveRow(1);
886             auto iter = m_RowsMap.find(0);
887             if (iter == m_RowsMap.end())
888             {
889                 SAL_WARN("lwp", "row 0 is unknown");
890                 nContentRow = 0;
891             }
892             else
893                 nContentRow = iter->second->GetCurMaxSpannedRows(0,nCol);
894         }
895     }
896     return nContentRow;
897 }
898 
SplitRowToCells(XFTable * pTmpTable,rtl::Reference<XFTable> const & pXFTable,sal_uInt8 nFirstColSpann,const sal_uInt8 * pCellMark)899 void LwpTableLayout::SplitRowToCells(XFTable* pTmpTable, rtl::Reference<XFTable> const & pXFTable,
900         sal_uInt8 nFirstColSpann,const sal_uInt8* pCellMark)
901 {
902     sal_uInt16 i;
903     sal_uInt16 nRowNum = pTmpTable->GetRowCount();
904     LwpTable* pTable = GetTable();
905     assert(pTable);
906     sal_uInt8 nCol = static_cast<sal_uInt8>(pTable->GetColumn());
907 
908     rtl::Reference<XFRow> xXFRow(new XFRow);
909 
910     //register style for heading row
911     double fHeight = 0;
912     OUString styleName;
913     std::unique_ptr<XFRowStyle> xRowStyle(new XFRowStyle);
914     XFRow* pRow = pTmpTable->GetRow(1);
915     if (!pRow)
916         throw std::runtime_error("missing row");
917     styleName = pRow->GetStyleName();
918 
919     // get settings of the row and assign them to new row style
920     XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
921     XFRowStyle *pTempRowStyle = static_cast<XFRowStyle*>(pXFStyleManager->FindStyle(styleName));
922     if (pTempRowStyle)
923         *xRowStyle = *pTempRowStyle;
924 
925     for (i=1;i<=nRowNum;i++)
926     {
927         styleName = pTmpTable->GetRow(i)->GetStyleName();
928         fHeight+=static_cast<XFRowStyle*>(pXFStyleManager->FindStyle(styleName))->GetRowHeight();
929     }
930     if (m_nDirection & 0x0030)
931     {
932         xRowStyle->SetMinRowHeight(static_cast<float>(fHeight));
933     }
934     else
935     {
936         xRowStyle->SetRowHeight(static_cast<float>(fHeight));
937     }
938     xXFRow->SetStyleName(pXFStyleManager->AddStyle(std::move(xRowStyle)).m_pStyle->GetStyleName());
939 
940     //construct heading row
941     rtl::Reference<XFCell> xXFCell1(new XFCell);
942     rtl::Reference<XFCell> xXFCell2(new XFCell);
943     rtl::Reference<XFTable> xSubTable1(new XFTable);
944     rtl::Reference<XFTable> xSubTable2(new XFTable);
945     XFRow* pOldRow;
946     rtl::Reference<XFCell> xNewCell;
947 
948     for (i=1;i<=nRowNum;i++)
949     {
950         pOldRow = pTmpTable->GetRow(i);
951         rtl::Reference<XFRow> xNewRow(new XFRow);
952         xNewRow->SetStyleName(pOldRow->GetStyleName());
953         for (sal_uInt8 j=1;j<=pCellMark[i];j++)
954         {
955             xNewCell = pOldRow->GetCell(j);
956             xNewRow->AddCell(xNewCell);
957         }
958         xSubTable1->AddRow(xNewRow);
959     }
960     ConvertColumn(xSubTable1, 0, nFirstColSpann);//add column info
961 
962     xXFCell1->Add(xSubTable1.get());
963     xXFCell1->SetColumnSpaned(nFirstColSpann);
964     xXFRow->AddCell(xXFCell1);
965 
966     for (i=1;i<=nRowNum;i++)
967     {
968         pOldRow = pTmpTable->GetRow(i);
969         rtl::Reference<XFRow> xNewRow(new XFRow);
970         xNewRow->SetStyleName(pOldRow->GetStyleName());
971         for(sal_Int32 j=pCellMark[i]+1;j<=pOldRow->GetCellCount();j++)
972         {
973             xNewCell = pOldRow->GetCell(j);
974             xNewRow->AddCell(xNewCell);
975         }
976         xSubTable2->AddRow(xNewRow);
977 
978     }
979     ConvertColumn(xSubTable2, nFirstColSpann, nCol);//add column info
980     xXFCell2->Add(xSubTable2.get());
981     xXFCell2->SetColumnSpaned(nCol-nFirstColSpann);
982     xXFRow->AddCell(xXFCell2);
983 
984     pXFTable->AddHeaderRow(xXFRow.get());
985 
986     //remove tmp table
987     for (i=1;i<=nRowNum;i++)
988     {
989         pOldRow = pTmpTable->GetRow(i);
990         for(sal_Int32 j=1;j<=pOldRow->GetCellCount();j++)
991             pOldRow->RemoveCell(j);
992         pTmpTable->RemoveRow(i);
993     }
994 }
995 
996 /**
997  * @short   find if the heading rows can be split to 2 cells
998  * @param  pXFTable - pointer of tmp XFtable
999  * @param  CellMark - pointer of cell mark array
1000  */
FindSplitColMark(XFTable * pXFTable,std::vector<sal_uInt8> & rCellMark,sal_uInt8 & nMaxColSpan)1001 bool  LwpTableLayout::FindSplitColMark(XFTable* pXFTable, std::vector<sal_uInt8>& rCellMark,
1002             sal_uInt8& nMaxColSpan)
1003 {
1004     sal_uInt16 nRowNum = pXFTable->GetRowCount();
1005     sal_uInt8 nColNum = static_cast<sal_uInt8>(pXFTable->GetColumnCount());
1006     sal_uInt8 nCount;
1007     sal_uInt8 nColSpan;
1008     bool bFindFlag = false;
1009     XFRow* pTmpRow;
1010 
1011     for(sal_uInt8 i=1;i<=nColNum;i++)
1012     {
1013         sal_uInt16 nRowLoop;
1014 
1015         //find current max column span
1016         nMaxColSpan = 1;
1017         for (nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)
1018         {
1019             nColSpan = 0;
1020             for(sal_uInt8 nCellLoop=1; nCellLoop<i+1; nCellLoop++)
1021             {
1022                 pTmpRow = pXFTable->GetRow(nRowLoop);
1023                 XFCell* pCell = pTmpRow->GetCell(nCellLoop);
1024                 if (pCell)
1025                     nColSpan += static_cast<sal_uInt8>(pCell->GetColSpaned());
1026                 else
1027                     return false;
1028             }
1029             if (nColSpan > nMaxColSpan)
1030                 nMaxColSpan = nColSpan;
1031             rCellMark.at(nRowLoop) = 0;//reset all cell mark to zero
1032         }
1033 
1034         //find if other row has the same column
1035         for (nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)
1036         {
1037             pTmpRow = pXFTable->GetRow(nRowLoop);
1038             nCount = 0;
1039             sal_Int32 nCellMark = 0;
1040             for (sal_Int32 nCellLoop=1; nCellLoop<=pTmpRow->GetCellCount(); nCellLoop++)
1041             {
1042                 if (nCount>nMaxColSpan)
1043                     break;
1044                 nCount+= static_cast<sal_uInt8>(pTmpRow->GetCell(nCellLoop)->GetColSpaned());
1045                 if (nCount == nMaxColSpan)
1046                 {
1047                     nCellMark = nCellLoop;
1048                     break;
1049                 }
1050             }
1051             if (nCellMark == 0)
1052                 break;
1053             else
1054                 rCellMark.at(nRowLoop) = nCellMark;
1055         }
1056         for(nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)//check if all ==0,break
1057         {
1058             if (rCellMark.at(nRowLoop) == 0)
1059                 break;
1060         }
1061         if (nRowLoop == nRowNum+1)
1062         {
1063             bFindFlag = true;
1064             return bFindFlag;
1065         }
1066 
1067     }
1068     return bFindFlag;
1069 }
1070 
operator ==(const TableConvertAttempt & a,const TableConvertAttempt & b)1071 static bool operator==(const TableConvertAttempt& a, const TableConvertAttempt& b)
1072 {
1073     return a.mnStartRow == b.mnStartRow &&
1074            a.mnEndRow == b.mnEndRow &&
1075            a.mnStartCol== b.mnStartCol &&
1076            a.mnEndCol == b.mnEndCol;
1077 }
1078 
1079 /**
1080  * @short   convert word pro table to SODC table
1081  * @param  pXFTable - pointer of table
1082  * @param  nStartRow - start row ID
1083  * @param  nEndRow - end row ID
1084  * @param  nStartCol - start column ID
1085  * @param  nEndCol - end column ID
1086  */
ConvertTable(rtl::Reference<XFTable> const & pXFTable,sal_uInt16 nStartRow,sal_uInt16 nEndRow,sal_uInt8 nStartCol,sal_uInt8 nEndCol)1087 void LwpTableLayout::ConvertTable(rtl::Reference<XFTable> const & pXFTable, sal_uInt16 nStartRow,
1088                 sal_uInt16 nEndRow,sal_uInt8 nStartCol,sal_uInt8 nEndCol)
1089 {
1090     TableConvertAttempt aConversionAttempt(nStartRow, nEndRow, nStartCol, nEndCol);
1091     auto itr = std::find(m_aConvertingStack.begin(), m_aConvertingStack.end(), aConversionAttempt);
1092     if (itr != m_aConvertingStack.end())
1093     {
1094         SAL_WARN("lwp", "already trying to convert this range");
1095         return;
1096     }
1097 
1098     m_aConvertingStack.push_back(aConversionAttempt);
1099 
1100     //out put column info TO BE CHANGED
1101     ConvertColumn(pXFTable,nStartCol,nEndCol);
1102 
1103     std::map<sal_uInt16,LwpRowLayout*>::iterator iter;
1104 
1105     for (sal_uInt16 i=nStartRow; i<nEndRow;)
1106     {
1107         iter = m_RowsMap.find(i);
1108         if (iter == m_RowsMap.end())
1109         {
1110             ConvertDefaultRow(pXFTable,nStartCol,nEndCol,i);
1111             i++;
1112         }
1113         else
1114         {
1115             LwpRowLayout* pRow = iter->second;
1116             if (pRow->GetCurMaxSpannedRows(nStartCol,nEndCol) == 1)
1117             {
1118                 pRow->ConvertCommonRow(pXFTable,nStartCol,nEndCol);
1119                 i++;
1120             }
1121             else
1122             {
1123                 pRow->ConvertRow(pXFTable,nStartCol,nEndCol);
1124                 i += pRow->GetCurMaxSpannedRows(nStartCol,nEndCol);
1125             }
1126         }
1127     }
1128 
1129     m_aConvertingStack.pop_back();
1130 }
1131 
1132 /**
1133  * @short   apply numeric value and formula to cell
1134  * @param  pFoundry - pointer of foundry
1135  * @param  aTableID - table ID
1136  */
PutCellVals(LwpFoundry * pFoundry,LwpObjectID aTableID)1137 void LwpTableLayout::PutCellVals(LwpFoundry* pFoundry, LwpObjectID aTableID)
1138 {
1139 
1140     // The old code doesn't check if the LwpFoundry pointer is NULL, so the NULL
1141     // pointer cause sodc frozen. Add code to check the pointer.
1142     if( !pFoundry ) return;
1143 
1144     try{
1145 
1146         LwpDLVListHeadHolder* pHolder = dynamic_cast<LwpDLVListHeadHolder*>(pFoundry->GetNumberManager().GetTableRangeID().obj().get());
1147 
1148         LwpTableRange* pTableRange = pHolder ? dynamic_cast<LwpTableRange*>(pHolder->GetHeadID().obj().get()) : nullptr;
1149 
1150         //Look up the table
1151         o3tl::sorted_vector<LwpTableRange*> aTableSeen;
1152         while (pTableRange)
1153         {
1154             aTableSeen.insert(pTableRange);
1155             LwpObjectID aID = pTableRange->GetTableID();
1156             if (aID == aTableID)
1157             {
1158                 break;
1159             }
1160             pTableRange = pTableRange->GetNext();
1161             if (aTableSeen.find(pTableRange) != aTableSeen.end())
1162                 throw std::runtime_error("loop in conversion");
1163         }
1164 
1165         if (!pTableRange)
1166             return;
1167 
1168         LwpCellRange* pRange = dynamic_cast<LwpCellRange*>(pTableRange->GetCellRangeID().obj().get());
1169         if (!pRange)
1170             return;
1171 
1172         LwpFolder* pFolder = dynamic_cast<LwpFolder*>(pRange->GetFolderID().obj().get());
1173         if (!pFolder)
1174             return;
1175 
1176         LwpObjectID aRowListID = pFolder->GetChildHeadID();
1177         LwpRowList* pRowList = dynamic_cast<LwpRowList*>(aRowListID.obj().get());
1178 
1179         //loop the rowlist
1180         o3tl::sorted_vector<LwpRowList*> aOuterSeen;
1181         while (pRowList)
1182         {
1183             aOuterSeen.insert(pRowList);
1184             sal_uInt16 nRowID =  pRowList->GetRowID();
1185             {
1186                 LwpCellList* pCellList = dynamic_cast<LwpCellList*>(pRowList->GetChildHeadID().obj().get());
1187                 //loop the cellList
1188                 o3tl::sorted_vector<LwpCellList*> aSeen;
1189                 while (pCellList)
1190                 {
1191                     aSeen.insert(pCellList);
1192                     {//put cell
1193                         sal_uInt16 nColID = pCellList->GetColumnID();
1194 
1195                         XFCell* pCell = GetCellsMap(nRowID,static_cast<sal_uInt8>(nColID));
1196                         if (!pCell)
1197                         {
1198                             throw std::runtime_error("Hidden cell would not be in cellsmap");
1199                         }
1200 
1201                         pCellList->Convert(pCell, this);
1202 
1203                         //process paragraph
1204                         PostProcessParagraph(pCell, nRowID, nColID);
1205 
1206                     }
1207                     pCellList = dynamic_cast<LwpCellList*>(pCellList->GetNextID().obj().get());
1208                     if (aSeen.find(pCellList) != aSeen.end())
1209                         throw std::runtime_error("loop in conversion");
1210                 }
1211             }
1212             pRowList = dynamic_cast<LwpRowList*>(pRowList->GetNextID().obj().get());
1213             if (aOuterSeen.find(pRowList) != aOuterSeen.end())
1214                 throw std::runtime_error("loop in conversion");
1215         }
1216 
1217     }catch (...) {
1218         SAL_WARN("lwp", "bad PutCellVals");
1219     }
1220 }
1221 
1222 /**
1223  * @short   1. set number right alignment to right if number 2. remove tab added before if number
1224  * @param  pCell - cell which to be process
1225  * @param  nRowID - row number in Word Pro file
1226  * @param  nColID - column number in Word Pro file
1227  */
PostProcessParagraph(XFCell * pCell,sal_uInt16 nRowID,sal_uInt16 nColID)1228 void LwpTableLayout::PostProcessParagraph(XFCell *pCell, sal_uInt16 nRowID, sal_uInt16 nColID)
1229 {
1230     // if number right, set alignment to right
1231     LwpCellLayout * pCellLayout = GetCellByRowCol(nRowID, nColID);
1232     if(!pCellLayout)
1233         return;
1234 
1235     rtl::Reference<XFContent> first(
1236         pCell->FindFirstContent(enumXFContentPara));
1237     XFParagraph * pXFPara = static_cast<XFParagraph*>(first.get());
1238     if (!pXFPara)
1239         return;
1240     XFColor aNullColor;
1241 
1242     OUString sNumfmt = pCellLayout->GetNumfmtName();
1243     bool bColorMod = false;
1244     XFNumberStyle* pNumStyle = nullptr;
1245     XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
1246     if (!sNumfmt.isEmpty())
1247     {
1248         pNumStyle = static_cast<XFNumberStyle*>(pXFStyleManager->FindStyle(sNumfmt));
1249         XFColor aColor = pNumStyle->GetColor();
1250         if ( aColor != aNullColor )
1251             bColorMod = true;//end
1252     }
1253 
1254     XFParaStyle * pStyle = pXFStyleManager->FindParaStyle(pXFPara->GetStyleName());
1255     if (!((pStyle && pStyle->GetNumberRight()) || bColorMod))
1256         return;
1257 
1258     std::unique_ptr<XFParaStyle> xOverStyle(new XFParaStyle);
1259 
1260     if (pStyle)
1261     {
1262         *xOverStyle = *pStyle;
1263 
1264         if (pStyle->GetNumberRight())
1265             xOverStyle->SetAlignType(enumXFAlignEnd);
1266     }
1267 
1268     if (bColorMod)
1269     {
1270         rtl::Reference<XFFont> xFont = xOverStyle->GetFont();
1271         if (xFont.is())
1272         {
1273             XFColor aColor = xFont->GetColor();
1274             if (aColor == aNullColor)
1275             {
1276                 rtl::Reference<XFFont> pNewFont(new XFFont);
1277                 aColor = pNumStyle->GetColor();
1278                 pNewFont->SetColor(aColor);
1279                 xOverStyle->SetFont(pNewFont);
1280             }
1281         }
1282     }
1283 
1284     xOverStyle->SetStyleName("");
1285     OUString StyleName
1286         = pXFStyleManager->AddStyle(std::move(xOverStyle)).m_pStyle->GetStyleName();
1287 
1288     pXFPara->SetStyleName(StyleName);
1289 }
1290 
1291 /**
1292  * @short   Parse all cols of table
1293  * @param  pXFTable - pointer to created XFTable
1294  */
ConvertColumn(rtl::Reference<XFTable> const & pXFTable,sal_uInt8 nStartCol,sal_uInt8 nEndCol)1295 void LwpTableLayout::ConvertColumn(rtl::Reference<XFTable> const & pXFTable, sal_uInt8 nStartCol, sal_uInt8 nEndCol)
1296 {
1297     LwpTable * pTable = GetTable();
1298     if (!pTable)
1299     {
1300         assert(false);
1301         return;
1302     }
1303 
1304     for (sal_uInt32 iLoop = 0; iLoop < static_cast<sal_uInt32>(nEndCol)-nStartCol; ++iLoop)
1305     {
1306         // add row to table
1307         LwpObjectID *pColID = &GetColumnLayoutHead();
1308         LwpColumnLayout * pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColID->obj().get());
1309         while (pColumnLayout)
1310         {
1311             if (pColumnLayout->GetColumnID() == (iLoop+nStartCol))
1312             {
1313                 pXFTable->SetColumnStyle(iLoop+1,  pColumnLayout->GetStyleName());
1314                 break;
1315             }
1316             pColID = &pColumnLayout->GetNext();
1317             pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColID->obj().get());
1318         }
1319         if (!pColumnLayout)
1320         {
1321             pXFTable->SetColumnStyle(iLoop+1, m_DefaultColumnStyleName);
1322         }
1323     }
1324 }
1325 /**
1326  * @short   split conflict merged cells
1327  */
SplitConflictCells()1328 void LwpTableLayout::SplitConflictCells()
1329 {
1330     LwpTable * pTable = GetTable();
1331     if (!pTable)
1332         return;
1333     sal_uInt16 nCol = pTable->GetColumn();
1334     sal_uInt16 nRow = pTable->GetRow();
1335 
1336     sal_uInt16 nEffectRows;
1337     std::map<sal_uInt16,LwpRowLayout*>::iterator iter1;
1338     std::map<sal_uInt16,LwpRowLayout*>::iterator iter2;
1339     LwpRowLayout* pRowLayout;
1340     LwpRowLayout* pEffectRow;
1341 
1342     for (sal_uInt16 i=0; i<nRow; )
1343     {
1344         iter1 = m_RowsMap.find(i);
1345         if (iter1 == m_RowsMap.end())//default rows
1346         {
1347             i++;
1348             continue;
1349         }
1350         pRowLayout= iter1->second;
1351         if (!pRowLayout->GetMergeCellFlag())
1352         {
1353             i++;
1354             continue;
1355         }
1356         else
1357         {
1358             nEffectRows = i + pRowLayout->GetCurMaxSpannedRows(0,static_cast<sal_uInt8>(nCol));
1359 
1360             for (sal_uInt16 j = i+1; j<nEffectRows; j++)
1361             {
1362                 iter2 = m_RowsMap.find(j);
1363                 if (iter2 == m_RowsMap.end())
1364                         continue;
1365                 pEffectRow = iter2->second;
1366                 if (!pEffectRow->GetMergeCellFlag())
1367                     continue;
1368                 else
1369                     pEffectRow->SetCellSplit(nEffectRows);
1370             }
1371             i = nEffectRows;
1372         }
1373     }//end for
1374 
1375 }
1376 /**
1377  * @short   add default row which are missing in the file
1378  * @param   pXFTable - pointer to new created table
1379  * @param   nStartCol - starting column
1380  * @param   nEndCol  - end column
1381  * @return   pXFTable
1382  */
ConvertDefaultRow(rtl::Reference<XFTable> const & pXFTable,sal_uInt8 nStartCol,sal_uInt8 nEndCol,sal_uInt16 nRowID)1383 void LwpTableLayout::ConvertDefaultRow(rtl::Reference<XFTable> const & pXFTable, sal_uInt8 nStartCol,
1384          sal_uInt8 nEndCol, sal_uInt16 nRowID)
1385 {
1386     // current row doesn't exist in the file
1387     rtl::Reference<XFRow> xRow(new XFRow);
1388     xRow->SetStyleName(m_DefaultRowStyleName);
1389 
1390     for (sal_uInt16 j =0;j < nEndCol-nStartCol; j++)
1391     {
1392         // if table has default cell layout, use it to ConvertCell
1393         // otherwise use blank cell
1394         rtl::Reference<XFCell> xCell;
1395         if (m_pDefaultCellLayout)
1396         {
1397             LwpTable* pTable = GetTable();
1398             assert(pTable);
1399             xCell = m_pDefaultCellLayout->DoConvertCell(
1400                 pTable->GetObjectID(),nRowID,j+nStartCol);
1401         }
1402         else
1403         {
1404             xCell.set(new XFCell);
1405         }
1406         xRow->AddCell(xCell);
1407     }
1408 
1409     pXFTable->AddRow(xRow);
1410 }
1411 
1412 /**
1413  * @short   set cell map info
1414  * @param   pXFCell - pointer to xfcell
1415  * @param   nRow - row id
1416  * @param   nCol - column id
1417  */
SetCellsMap(sal_uInt16 nRow1,sal_uInt8 nCol1,sal_uInt16 nRow2,sal_uInt8 nCol2,XFCell * pXFCell)1418 void LwpTableLayout::SetCellsMap(sal_uInt16 nRow1, sal_uInt8 nCol1,
1419                                  sal_uInt16 nRow2, sal_uInt8 nCol2, XFCell* pXFCell)
1420 {
1421     m_CellsMap.insert({{nRow1, nCol1}, {nRow2, nCol2}}, pXFCell);
1422 }
1423 
1424 /**
1425  * @short   get cell map info
1426  * @param   nRow - row id
1427  * @param   nCol  - column id
1428  * @return  pXFCell
1429  */
GetCellsMap(sal_uInt16 nRow,sal_uInt8 nCol)1430 XFCell* LwpTableLayout::GetCellsMap(sal_uInt16 nRow, sal_uInt8 nCol)
1431 {
1432     auto results = m_CellsMap.search({{nRow, nCol}, {nRow, nCol}}, rt_type::search_type::overlap);
1433     if (results.begin() == results.end())
1434        return nullptr;
1435     // return the last thing inserted for this position
1436     return std::prev(results.end())->GetCell();
1437 }
1438 /**
1439  * @descr   Get row layout by row id
1440  * @param   nRow - row id
1441  */
GetRowLayout(sal_uInt16 nRow)1442 LwpRowLayout* LwpTableLayout::GetRowLayout(sal_uInt16 nRow)
1443 {
1444     LwpObjectID *pRowID = &GetChildHead();
1445     LwpRowLayout * pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
1446     while (pRowLayout)
1447     {
1448         if(pRowLayout->GetRowID() == nRow)
1449             return pRowLayout;
1450 
1451         pRowID = &pRowLayout->GetNext();
1452         pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
1453     }
1454     return nullptr;
1455 }
1456 
1457 //add end by
LwpColumnLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)1458 LwpColumnLayout::LwpColumnLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
1459     : LwpVirtualLayout(objHdr, pStrm)
1460     , ccolid(0)
1461     , cwidth(0)
1462 {}
1463 
~LwpColumnLayout()1464 LwpColumnLayout::~LwpColumnLayout()
1465 {}
Read()1466 void LwpColumnLayout::Read()
1467 {
1468     LwpObjectStream* pStrm = m_pObjStrm.get();
1469 
1470     LwpVirtualLayout::Read();
1471 
1472     sal_uInt16 colid;
1473 
1474     colid = pStrm->QuickReaduInt16();   // forced to lushort
1475     ccolid = static_cast<sal_uInt8>(colid);
1476     cwidth = pStrm->QuickReadInt32();
1477 
1478     pStrm->SkipExtra();
1479 }
1480 
RegisterStyle(double dCalculatedWidth)1481 void LwpColumnLayout::RegisterStyle(double dCalculatedWidth)
1482 {
1483     std::unique_ptr<XFColStyle> xColStyle(new XFColStyle);
1484     xColStyle->SetWidth(static_cast<float>(dCalculatedWidth));
1485     XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
1486     m_StyleName = pXFStyleManager->AddStyle(std::move(xColStyle)).m_pStyle->GetStyleName();
1487 }
1488 
LwpTableHeadingLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)1489 LwpTableHeadingLayout::LwpTableHeadingLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
1490     : LwpTableLayout(objHdr, pStrm)
1491     , cStartRow(0)
1492     , cEndRow(0)
1493 {}
1494 
~LwpTableHeadingLayout()1495 LwpTableHeadingLayout::~LwpTableHeadingLayout()
1496 {}
1497 /**
1498  * @short   read table heading layout
1499  * @param
1500  * @return
1501  */
Read()1502 void LwpTableHeadingLayout::Read()
1503 {
1504     LwpTableLayout::Read();
1505 
1506     cStartRow = m_pObjStrm->QuickReaduInt16();
1507     cEndRow = m_pObjStrm->QuickReaduInt16();
1508 
1509     m_pObjStrm->SkipExtra();
1510 
1511 }
1512 /**
1513  * @short   get start and end row number of table heading
1514  * @param
1515  * @return *pStartRow - starting row number
1516  * @return *pEndRow -   end row number
1517  */
GetStartEndRow(sal_uInt16 & nStartRow,sal_uInt16 & nEndRow)1518 void LwpTableHeadingLayout::GetStartEndRow(sal_uInt16& nStartRow, sal_uInt16& nEndRow)
1519 {
1520     nStartRow = cStartRow;
1521     nEndRow = cEndRow;
1522 }
1523 
LwpSuperParallelColumnLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)1524 LwpSuperParallelColumnLayout::LwpSuperParallelColumnLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpSuperTableLayout(objHdr, pStrm)
1525 {
1526 }
~LwpSuperParallelColumnLayout()1527 LwpSuperParallelColumnLayout::~LwpSuperParallelColumnLayout()
1528 {}
1529 
Read()1530 void LwpSuperParallelColumnLayout::Read()
1531 {
1532     LwpSuperTableLayout::Read();
1533     m_pObjStrm->SkipExtra();
1534 
1535 }
1536 
LwpSuperGlossaryLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)1537 LwpSuperGlossaryLayout::LwpSuperGlossaryLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpSuperTableLayout(objHdr, pStrm)
1538 {
1539 }
1540 
~LwpSuperGlossaryLayout()1541 LwpSuperGlossaryLayout::~LwpSuperGlossaryLayout()
1542 {
1543 }
1544 
Read()1545 void LwpSuperGlossaryLayout::Read()
1546 {
1547     LwpSuperTableLayout::Read();
1548     m_pObjStrm->SkipExtra();
1549 }
1550 
LwpParallelColumnsLayout(LwpObjectHeader const & objHdr,LwpSvStream * pStrm)1551 LwpParallelColumnsLayout::LwpParallelColumnsLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpTableLayout(objHdr, pStrm)
1552 {
1553 }
1554 
~LwpParallelColumnsLayout()1555 LwpParallelColumnsLayout::~LwpParallelColumnsLayout()
1556 {
1557 }
1558 
Read()1559 void LwpParallelColumnsLayout::Read()
1560 {
1561     LwpTableLayout::Read();
1562     m_pObjStrm->SkipExtra();
1563 }
1564 
1565 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1566