xref: /aoo4110/main/sw/source/filter/ww8/ww8par2.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27 
28 #include <tools/solar.h>
29 #include <vcl/vclenum.hxx>
30 #include <vcl/font.hxx>
31 #include <hintids.hxx>
32 #include <editeng/colritem.hxx>
33 #include <editeng/orphitem.hxx>
34 #include <editeng/widwitem.hxx>
35 #include <editeng/brshitem.hxx>
36 #include <editeng/boxitem.hxx>
37 #include <editeng/lrspitem.hxx>
38 #include <editeng/fhgtitem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/hyznitem.hxx>
41 #include <editeng/frmdiritem.hxx>
42 #include <editeng/langitem.hxx>
43 #include <editeng/charrotateitem.hxx>
44 #include <editeng/pgrditem.hxx>
45 #include <msfilter.hxx>
46 #include <pam.hxx>              // fuer SwPam
47 #include <doc.hxx>
48 #include <docary.hxx>
49 #include <ndtxt.hxx>            // class SwTxtNode
50 #include <paratr.hxx>           // SwNumRuleItem
51 #include <poolfmt.hxx>          // RES_POOLCOLL_STANDARD
52 #include <swtable.hxx>          // class SwTableLines, ...
53 #include <tblsel.hxx>           // class _SwSelBox
54 #include <mdiexp.hxx>
55 #include <fmtpdsc.hxx>
56 #include <txtftn.hxx>
57 #include <frmfmt.hxx>
58 #include <ftnidx.hxx>
59 #include <fmtftn.hxx>
60 #include <charfmt.hxx>
61 #include <SwStyleNameMapper.hxx>
62 #include <fltshell.hxx>         // fuer den Attribut Stack
63 #include <fmtanchr.hxx>
64 #include <fmtrowsplt.hxx>
65 // --> OD 2005-01-27 #i33818#
66 #include <fmtfollowtextflow.hxx>
67 // <--
68 #include <numrule.hxx>
69 #   include "../inc/wwstyles.hxx"
70 #   include "writerhelper.hxx"
71 #include "ww8struc.hxx"         // struct TC
72 #include "ww8par.hxx"
73 #include "ww8par2.hxx"
74 
75 #include <frmatr.hxx>
76 
77 #include <iostream>
78 
79 #define MAX_COL 64  // WW6-Beschreibung: 32, WW6-UI: 31 & WW8-UI: 63!
80 
81 using namespace ::com::sun::star;
82 
83 
84 class WW8SelBoxInfo: public SwSelBoxes_SAR
85 {
86 private:
87     WW8SelBoxInfo(const WW8SelBoxInfo&);
88     WW8SelBoxInfo& operator=(const WW8SelBoxInfo&);
89 public:
90     short nGroupXStart;
91     short nGroupWidth;
92     bool bGroupLocked;
93 
WW8SelBoxInfo(short nXCenter,short nWidth)94     WW8SelBoxInfo(short nXCenter, short nWidth)
95         : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
96     {}
97 };
98 
99 typedef WW8SelBoxInfo* WW8SelBoxInfoPtr;
100 
101 SV_DECL_PTRARR_DEL(WW8MergeGroups, WW8SelBoxInfoPtr, 16,16)
102 SV_IMPL_PTRARR(WW8MergeGroups, WW8SelBoxInfoPtr)
103 
104 struct WW8TabBandDesc
105 {
106     WW8TabBandDesc* pNextBand;
107     short nGapHalf;
108     short mnDefaultLeft;
109     short mnDefaultTop;
110     short mnDefaultRight;
111     short mnDefaultBottom;
112     bool mbHasSpacing;
113     short nLineHeight;
114     short nRows;
115     sal_uInt16 maDirections[MAX_COL + 1];
116     short nCenter[MAX_COL + 1]; // X-Rand aller Zellen dieses Bandes
117     short nWidth[MAX_COL + 1];  // Laenge aller Zellen dieses Bandes
118     short nWwCols;      // sal_uInt8 wuerde reichen, alignment -> short
119     short nSwCols;      // SW: so viele Spalten fuer den Writer
120     bool bLEmptyCol;    // SW: Links eine leere Zusatz-Spalte
121     bool bREmptyCol;    // SW: dito rechts
122     bool bCantSplit;
123     bool bCantSplit90;
124     WW8_TCell* pTCs;
125     sal_uInt8 nOverrideSpacing[MAX_COL + 1];
126     short nOverrideValues[MAX_COL + 1][4];
127     WW8_SHD* pSHDs;
128     sal_uInt32* pNewSHDs;
129     WW8_BRC aDefBrcs[6];
130 
131 
132     // nur fuer WW6-7: diese Zelle hat WW-Flag bMerged (horizontal) gesetzt
133     //bool bWWMergedVer6[MAX_COL];
134 
135 
136     bool bExist[MAX_COL];           // Existiert diese Zelle ?
137     sal_uInt8 nTransCell[MAX_COL + 2];  // UEbersetzung WW-Index -> SW-Index
138 
139     WW8TabBandDesc();
140     WW8TabBandDesc(WW8TabBandDesc& rBand);    // tief kopieren
141     ~WW8TabBandDesc();
142     static void setcelldefaults(WW8_TCell *pCells, short nCells);
143     void ReadDef(bool bVer67, const sal_uInt8* pS);
144     void ProcessDirection(const sal_uInt8* pParams);
145     void ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC);
146     void ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams);
147     void ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol);
148     void ProcessSprmTDelete(const sal_uInt8* pParamsTDelete);
149     void ProcessSprmTInsert(const sal_uInt8* pParamsTInsert);
150     void ProcessSpacing(const sal_uInt8* pParamsTInsert);
151     void ProcessSpecificSpacing(const sal_uInt8* pParamsTInsert);
152     void ReadShd(const sal_uInt8* pS );
153     void ReadNewShd(const sal_uInt8* pS, bool bVer67);
154 
155     enum wwDIR {wwTOP = 0, wwLEFT = 1, wwBOTTOM = 2, wwRIGHT = 3};
156 };
157 
WW8TabBandDesc()158 WW8TabBandDesc::WW8TabBandDesc()
159 {
160     memset(this, 0, sizeof(*this));
161     for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i)
162         maDirections[i] = 4;
163 }
164 
~WW8TabBandDesc()165 WW8TabBandDesc::~WW8TabBandDesc()
166 {
167     delete[] pTCs;
168     delete[] pSHDs;
169     delete[] pNewSHDs;
170 }
171 
172 class WW8TabDesc
173 {
174     std::vector<String> aNumRuleNames;
175     sw::util::RedlineStack *mpOldRedlineStack;
176 
177     SwWW8ImplReader* pIo;
178 
179     WW8TabBandDesc* pFirstBand;
180     WW8TabBandDesc* pActBand;
181 
182     SwPosition* pTmpPos;
183 
184     SwTableNode* pTblNd;            // Tabellen-Node
185     const SwTableLines* pTabLines;  // Zeilen-Array davon
186     SwTableLine* pTabLine;          // akt. Zeile
187     SwTableBoxes* pTabBoxes;        // Boxen-Array in akt. Zeile
188     SwTableBox* pTabBox;            // akt. Zelle
189 
190     WW8MergeGroups* pMergeGroups;   // Listen aller zu verknuepfenden Zellen
191 
192     WW8_TCell* pAktWWCell;
193 
194     short nRows;
195     short nDefaultSwCols;
196     short nBands;
197     short nMinLeft;
198     short nConvertedLeft;
199     short nMaxRight;
200     short nSwWidth;
201     short nPreferredWidth;
202     short nOrgDxaLeft;
203 
204     bool bOk;
205     bool bClaimLineFmt;
206     sal_Int16 eOri;
207     bool bIsBiDi;
208                                 // 2. allgemeine Verwaltungsinfo
209     short nAktRow;
210     short nAktBandRow;          // SW: in dieser Zeile des akt. Bandes bin ich
211                                 // 3. Verwaltungsinfo fuer Writer
212     short nAktCol;
213 
214     sal_uInt16 nRowsToRepeat;
215 
216     // 4. Methoden
217 
218     sal_uInt16 GetLogicalWWCol() const;
219     void SetTabBorders( SwTableBox* pBox, short nIdx );
220     void SetTabShades( SwTableBox* pBox, short nWwIdx );
221     void SetTabVertAlign( SwTableBox* pBox, short nWwIdx );
222     void SetTabDirection( SwTableBox* pBox, short nWwIdx );
223     void CalcDefaults();
224     bool SetPamInCell(short nWwCol, bool bPam);
225     void InsertCells( short nIns );
226     void AdjustNewBand();
227 
228     // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw.
229     // -1 Details siehe bei der Implementierung
230     bool FindMergeGroup(short nX1, short nWidth, bool bExact, short& nMGrIdx);
231 
232     // einzelne Box ggfs. in eine Merge-Gruppe aufnehmen
233     // (die Merge-Gruppen werden dann spaeter auf einen Schlag abgearbeitet)
234     SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
235         WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, sal_uInt16 nCol  );
236     void StartMiserableHackForUnsupportedDirection(short nWwCol);
237     void EndMiserableHackForUnsupportedDirection(short nWwCol);
238     //No copying
239     WW8TabDesc(const WW8TabDesc&);
240     WW8TabDesc &operator=(const WW8TabDesc&);
241 public:
242     const SwTable* pTable;          // Tabelle
243     SwPosition* pParentPos;
244     SwFlyFrmFmt* pFlyFmt;
245     SfxItemSet aItemSet;
246     bool IsValidCell(short nCol) const;
247     bool InFirstParaInCell() const;
248 
249     WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp );
Ok() const250     bool Ok() const { return bOk; }
251     void CreateSwTable();
252     void UseSwTable();
253     void SetSizePosition(SwFrmFmt* pFrmFmt);
254     void TableCellEnd();
255     void MoveOutsideTable();
256     void ParkPaM();
257     void FinishSwTable();
258     void MergeCells();
GetMinLeft() const259     short GetMinLeft() const { return nConvertedLeft; }
260     ~WW8TabDesc();
GetPos()261     SwPosition *GetPos() { return pTmpPos; }
262 
GetAktWWCell() const263     const WW8_TCell* GetAktWWCell() const { return pAktWWCell; }
GetAktCol() const264     short GetAktCol() const { return nAktCol; }
265     // find name of numrule valid for current WW-COL
266     const String& GetNumRuleName() const;
267     void SetNumRuleName( const String& rName );
268 
getOldRedlineStack()269     sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; }
270 };
271 
close(const SwPosition & rPos,RedlineType_t eType,WW8TabDesc * pTabDesc)272 void sw::util::RedlineStack::close( const SwPosition& rPos,
273     RedlineType_t eType, WW8TabDesc* pTabDesc )
274 {
275     // If the redline type is not found in the redline stack, we have to check if there has been
276     // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
277     if( !close( rPos, eType ) )
278     {
279         if( pTabDesc && pTabDesc->getOldRedlineStack() )
280         {
281 #ifdef DBG_UTIL
282             ASSERT( pTabDesc->getOldRedlineStack()->close(rPos, eType), "close without open!");
283 #else
284             pTabDesc->getOldRedlineStack()->close( rPos, eType );
285 #endif
286         }
287     }
288 }
289 
290 
SetCurrentSectionHasFootnote()291 void wwSectionManager::SetCurrentSectionHasFootnote()
292 {
293     ASSERT(!maSegments.empty(),
294         "should not be possible, must be at least one segment");
295     if (!maSegments.empty())
296         maSegments.back().mbHasFootnote = true;
297 }
298 
CurrentSectionIsVertical() const299 bool wwSectionManager::CurrentSectionIsVertical() const
300 {
301     ASSERT(!maSegments.empty(),
302         "should not be possible, must be at least one segment");
303     if (!maSegments.empty())
304         return maSegments.back().IsVertical();
305     return false;
306 }
307 
CurrentSectionIsProtected() const308 bool wwSectionManager::CurrentSectionIsProtected() const
309 {
310     ASSERT(!maSegments.empty(),
311         "should not be possible, must be at least one segment");
312     if (!maSegments.empty())
313         return SectionIsProtected(maSegments.back());
314     return false;
315 }
316 
GetPageLeft() const317 sal_uInt32 wwSectionManager::GetPageLeft() const
318 {
319     return !maSegments.empty() ? maSegments.back().nPgLeft : 0;
320 }
321 
GetPageRight() const322 sal_uInt32 wwSectionManager::GetPageRight() const
323 {
324     return !maSegments.empty() ? maSegments.back().nPgRight : 0;
325 }
326 
GetPageWidth() const327 sal_uInt32 wwSectionManager::GetPageWidth() const
328 {
329     return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
330 }
331 
GetTextAreaWidth() const332 sal_uInt32 wwSectionManager::GetTextAreaWidth() const
333 {
334     return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
335 }
336 
337 // --> OD 2007-07-03 #148498#
GetWWPageTopMargin() const338 sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
339 {
340     return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
341 }
342 // <--
343 
End_Ftn()344 sal_uInt16 SwWW8ImplReader::End_Ftn()
345 {
346     /*
347     #84095#
348     Ignoring Footnote outside of the normal Text. People will put footnotes
349     into field results and field commands.
350     */
351     if (bIgnoreText ||
352         pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
353     {
354         return 0;
355     }
356 
357     ASSERT(!maFtnStack.empty(), "footnote end without start");
358     if (maFtnStack.empty())
359         return 0;
360 
361     bool bFtEdOk = false;
362     const FtnDescriptor &rDesc = maFtnStack.back();
363 
364     //Get the footnote character and remove it from the txtnode. We'll
365     //replace it with the footnote
366     SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode();
367     xub_StrLen nPos = pPaM->GetPoint()->nContent.GetIndex();
368 
369     String sChar;
370     SwTxtAttr* pFN = 0;
371     //There should have been a footnote char, we will replace this.
372     if (pTxt && nPos)
373     {
374         sChar.Append(pTxt->GetTxt().GetChar(--nPos));
375         pPaM->SetMark();
376         pPaM->GetMark()->nContent--;
377         rDoc.DeleteRange( *pPaM );
378         pPaM->DeleteMark();
379         SwFmtFtn aFtn(rDesc.meType == MAN_EDN);
380         pFN = pTxt->InsertItem(aFtn, nPos, nPos);
381     }
382     ASSERT(pFN, "Probleme beim Anlegen des Fussnoten-Textes");
383     if (pFN)
384     {
385 
386         SwPosition aTmpPos( *pPaM->GetPoint() );    // merke alte Cursorposition
387         WW8PLCFxSaveAll aSave;
388         pPlcxMan->SaveAllPLCFx( aSave );
389         WW8PLCFMan* pOldPlcxMan = pPlcxMan;
390 
391         const SwNodeIndex* pSttIdx = ((SwTxtFtn*)pFN)->GetStartNode();
392         ASSERT(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes");
393 
394         ((SwTxtFtn*)pFN)->SetSeqNo( rDoc.GetFtnIdxs().Count() );
395 
396         bool bOld = bFtnEdn;
397         bFtnEdn = true;
398 
399         // read content of Ft-/End-Note
400         Read_HdFtFtnText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
401         bFtEdOk = true;
402         bFtnEdn = bOld;
403 
404         ASSERT(sChar.Len()==1 && ((rDesc.mbAutoNum == (sChar.GetChar(0) == 2))),
405          "footnote autonumbering must be 0x02, and everthing else must not be");
406 
407         // If no automatic numbering use the following char from the main text
408         // as the footnote number
409         if (!rDesc.mbAutoNum)
410             ((SwTxtFtn*)pFN)->SetNumber(0, &sChar);
411 
412         /*
413             Delete the footnote char from the footnote if its at the beginning
414             as usual. Might not be if the user has already deleted it, e.g.
415             #i14737#
416         */
417         SwNodeIndex& rNIdx = pPaM->GetPoint()->nNode;
418         rNIdx = pSttIdx->GetIndex() + 1;
419         SwTxtNode* pTNd = rNIdx.GetNode().GetTxtNode();
420         if (pTNd && pTNd->GetTxt().Len() && sChar.Len())
421         {
422             if (pTNd->GetTxt().GetChar(0) == sChar.GetChar(0))
423             {
424                 pPaM->GetPoint()->nContent.Assign( pTNd, 0 );
425                 pPaM->SetMark();
426                 // Strip out tabs we may have inserted on export #i24762#
427                 if (pTNd->GetTxt().GetChar(1) == 0x09)
428                     pPaM->GetMark()->nContent++;
429                 pPaM->GetMark()->nContent++;
430                 pReffingStck->Delete(*pPaM);
431                 rDoc.DeleteRange( *pPaM );
432                 pPaM->DeleteMark();
433             }
434         }
435 
436         *pPaM->GetPoint() = aTmpPos;        // restore Cursor
437 
438         pPlcxMan = pOldPlcxMan;             // Restore attributes
439         pPlcxMan->RestoreAllPLCFx( aSave );
440     }
441 
442     if (bFtEdOk)
443         maSectionManager.SetCurrentSectionHasFootnote();
444 
445     maFtnStack.pop_back();
446     return 0;
447 }
448 
Read_Ftn(WW8PLCFManResult * pRes)449 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult* pRes)
450 {
451     /*
452     #84095#
453     Ignoring Footnote outside of the normal Text. People will put footnotes
454     into field results and field commands.
455     */
456     if (bIgnoreText ||
457         pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
458     {
459         return 0;
460     }
461 
462     FtnDescriptor aDesc;
463     aDesc.mbAutoNum = true;
464     if (eEDN == pRes->nSprmId)
465     {
466         aDesc.meType = MAN_EDN;
467         if (pPlcxMan->GetEdn())
468             aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetEdn()->GetData();
469     }
470     else
471     {
472         aDesc.meType = MAN_FTN;
473         if (pPlcxMan->GetFtn())
474             aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetFtn()->GetData();
475     }
476 
477     aDesc.mnStartCp = pRes->nCp2OrIdx;
478     aDesc.mnLen = pRes->nMemLen;
479 
480     maFtnStack.push_back(aDesc);
481 
482     return 0;
483 }
484 
SearchRowEnd(WW8PLCFx_Cp_FKP * pPap,WW8_CP & rStartCp,int nLevel) const485 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp,
486     int nLevel) const
487 {
488     WW8PLCFxDesc aRes;
489     aRes.pMemPos = 0;
490     aRes.nEndPos = rStartCp;
491 
492     while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
493     {
494         if (pPap->Where() != WW8_CP_MAX)
495         {
496             const sal_uInt8* pB = pPap->HasSprm(TabRowSprm(nLevel));
497             if (pB && *pB == 1)
498             {
499                 const sal_uInt8 *pLevel = 0;
500                 if (0 != (pLevel = pPap->HasSprm(0x6649)))
501                 {
502                     if (nLevel + 1 == *pLevel)
503                         return true;
504                 }
505                 else
506                 {
507                     ASSERT(!nLevel || pLevel, "sublevel without level sprm");
508                     return true;    // RowEnd found
509                 }
510             }
511         }
512 
513         aRes.nStartPos = aRes.nEndPos;
514         aRes.pMemPos = 0;
515         //Seek to our next block of properties
516         if (!(pPap->SeekPos(aRes.nStartPos)))
517         {
518             aRes.nEndPos = WW8_CP_MAX;
519             pPap->SetDirty(true);
520         }
521         pPap->GetSprms(&aRes);
522         pPap->SetDirty(false);
523         //Update our aRes to get the new starting point of the next properties
524         rStartCp = aRes.nEndPos;
525     }
526 
527     return false;
528 }
529 
TestApo(int nCellLevel,bool bTableRowEnd,const WW8_TablePos * pTabPos,bool bReadTablePos)530 ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
531         const WW8_TablePos *pTabPos, bool bReadTablePos)
532 {
533     const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0;
534     ApoTestResults aRet;
535     // Frame in Style Definition (word appears to ignore them if inside an
536     // text autoshape, e.g. #94418#)
537     if (!bTxbxFlySection)
538         aRet.mpStyleApo = StyleExists(nAktColl) ? pCollA[nAktColl].pWWFly : 0;
539 
540     /*
541     #i1140#
542     If I have a table and apply a style to one of its frames that should cause
543     a paragraph that its applied to it to only exist as a seperate floating
544     frame, then the behavour depends on which cell that it has been applied
545     to. If its the first cell of a row then the whole table row jumps into the
546     new frame, if its not then then the paragraph attributes are applied
547     "except" for the floating frame stuff. i.e. its ignored. So if theres a
548     table, and we're not in the first cell then we ignore the fact that the
549     paragraph style wants to be in a different frame.
550 
551     This sort of mindbending inconsistency is surely why frames are deprecated
552     in word 97 onwards and hidden away from the user
553 
554 
555     #i1532# & #i5379#
556     If we are already a table in a frame then we must grab the para properties
557     to see if we are still in that frame.
558     */
559     // If table front don't have some content and it is doc first table, ignore table text wrapping property
560     if ( bReadTablePos )
561     {
562         aRet.mpSprm37 = pPlcxMan->HasParaSprm( bVer67 ? 37 : 0x2423 );
563         aRet.mpSprm29 = pPlcxMan->HasParaSprm( bVer67 ? 29 : 0x261B );
564     }
565 
566 
567     // Is there some frame data here
568     bool bNowApo = aRet.HasFrame() || pTopLevelTable;
569     if (bNowApo)
570     {
571         if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos))
572             delete pTest;
573         else
574             bNowApo = false;
575     }
576 
577     bool bTestAllowed = !bTxbxFlySection && !bTableRowEnd;
578     if (bTestAllowed)
579     {
580         //Test is allowed if there is no table.
581         //Otherwise only allowed if we are in the
582         //first paragraph of the first cell of a row.
583         //(And only if the row we are inside is at the
584         //same level as the previous row, think tables
585         //in tables)
586         if (nCellLevel == nInTable)
587         {
588 
589             if (!nInTable)
590                 bTestAllowed = true;
591             else
592             {
593                 if (!pTableDesc)
594                 {
595                     ASSERT(pTableDesc, "What!");
596                     bTestAllowed = false;
597                 }
598                 else
599                 {
600                     // --> OD 2005-02-01 #i39468#
601                     // If current cell isn't valid, the test is allowed.
602                     // The cell isn't valid, if e.g. there is a new row
603                     // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
604                     bTestAllowed =
605                         pTableDesc->GetAktCol() == 0 &&
606                         ( !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) ||
607                           pTableDesc->InFirstParaInCell() );
608                     // <--
609                 }
610             }
611         }
612     }
613 
614     if (!bTestAllowed)
615         return aRet;
616 
617     aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start
618     aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo;  // APO-end
619 
620     //If it happens that we are in a table, then if its not the first cell
621     //then any attributes that might otherwise cause the contents to jump
622     //into another frame don't matter, a table row sticks together as one
623     //unit no matter what else happens. So if we are not in a table at
624     //all, or if we are in the first cell then test that the last frame
625     //data is the same as the current one
626     if (bNowApo && InEqualApo(nCellLevel))
627     {
628         // two bordering eachother
629         if (!TestSameApo(aRet, pTabPos))
630             aRet.mbStopApo = aRet.mbStartApo = true;
631     }
632 
633     return aRet;
634 }
635 //---------------------------------------------------------------------
636 //   Hilfroutinen fuer Kapitelnummerierung und Aufzaehlung / Gliederung
637 //---------------------------------------------------------------------
638 
SetBaseAnlv(SwNumFmt & rNum,WW8_ANLV & rAV,sal_uInt8 nSwLevel)639 static void SetBaseAnlv(
640     SwNumFmt &rNum,
641     WW8_ANLV &rAV,
642     sal_uInt8 nSwLevel )
643 {
644     static SvxExtNumType eNumA[8] =
645     { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
646       SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N,
647       SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC };
648 
649     static SvxAdjust eAdjA[4] =
650     { SVX_ADJUST_LEFT, SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT };
651 
652     rNum.SetNumberingType(
653         static_cast< sal_Int16 >(( SVBT8ToByte( rAV.nfc ) < 8 )
654             ? eNumA[SVBT8ToByte( rAV.nfc ) ]
655             : SVX_NUM_NUMBER_NONE) );
656 
657     if ((SVBT8ToByte(rAV.aBits1 ) & 0x4) >> 2)
658     {
659         rNum.SetIncludeUpperLevels(nSwLevel + 1);
660     }
661     rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) );
662 
663     rNum.SetNumAdjust( eAdjA[SVBT8ToByte( rAV.aBits1 ) & 0x3] );
664 
665     rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) );
666     sal_Int16 nIndent = Abs( (sal_Int16) SVBT16ToShort( rAV.dxaIndent ) );
667     if ( SVBT8ToByte( rAV.aBits1 ) & 0x08 )      //fHang
668     {
669         rNum.SetFirstLineOffset( -nIndent );
670         rNum.SetLSpace( nIndent );
671         rNum.SetAbsLSpace( nIndent );
672     }
673     else
674         rNum.SetCharTextDistance( nIndent );        // Breite der Nummer fehlt
675 
676     if( SVBT8ToByte( rAV.nfc ) == 5 || SVBT8ToByte( rAV.nfc ) == 7 )
677     {
678         String sP( rNum.GetSuffix() );
679         sP.Insert( '.', 0 );
680         rNum.SetSuffix( sP );   // Ordinalzahlen
681     }
682 }
683 
SetAnlvStrings(SwNumFmt & rNum,WW8_ANLV & rAV,const sal_uInt8 * pTxt,bool bOutline)684 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt &rNum, WW8_ANLV &rAV,
685     const sal_uInt8* pTxt, bool bOutline)
686 {
687     bool bInsert = false;                       // Default
688     CharSet eCharSet = eStructCharSet;
689 
690     const WW8_FFN* pF = pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo
691     bool bListSymbol = pF && ( pF->chs == 2 );      // Symbol/WingDings/...
692 
693     String sTxt;
694     if (bVer67)
695     {
696         sTxt = String( (sal_Char*)pTxt,  SVBT8ToByte( rAV.cbTextBefore )
697                                  + SVBT8ToByte( rAV.cbTextAfter  ), eCharSet );
698     }
699     else
700     {
701         for(xub_StrLen i = SVBT8ToByte(rAV.cbTextBefore);
702             i < SVBT8ToByte(rAV.cbTextAfter); ++i, pTxt += 2)
703         {
704             sTxt.Append(SVBT16ToShort(*(SVBT16*)pTxt));
705         }
706     }
707 
708     if( bOutline )
709     {                             // Gliederung
710         if( !rNum.GetIncludeUpperLevels()           // es sind  <= 1 Nummern anzuzeigen
711             || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ){    // oder dieser Level hat keine
712                                                 // eigenen Ziffern
713             bInsert = true;                     // -> dann uebernehme Zeichen
714 
715             // replace by simple Bullet ?
716             if( bListSymbol )
717                 //JP 14.08.96: cBulletChar benutzen, damit auf dem MAC
718                 //              richtig gemappt wird
719                 sTxt.Fill(  SVBT8ToByte( rAV.cbTextBefore )
720                           + SVBT8ToByte( rAV.cbTextAfter  ), cBulletChar );
721             }
722     }
723     else
724     {                                       // Nummerierung / Aufzaehlung
725         bInsert = true;
726 //      if( SVBT16ToShort( rAV.ftc ) == 1
727 //          || SVBT16ToShort( rAV.ftc ) == 3 ){ // Symbol / WingDings
728         if( bListSymbol )
729         {
730             FontFamily eFamily;
731             String aName;
732             FontPitch ePitch;
733 
734             if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName,
735                                 ePitch, eCharSet ) ){
736 //              sal_uInt16 nSiz = ( SVBT16ToShort( rAV.hps ) ) ?
737 //                          SVBT16ToShort( rAV.hps ) : 24; // Groesse in 1/2 Pt
738 //                      darf nach JP nicht gesetzt werden, da immer die Size
739 //                      genommen wird, die am ZeilenAnfang benutzt wird
740                 Font aFont;
741                 aFont.SetName( aName );
742                 aFont.SetFamily( eFamily );
743 //              aFont.SetPitch( ePitch );       // darf nach JP nicht
744                 aFont.SetCharSet( eCharSet );
745                 rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
746 //              if( rAV.ico )       // geht in UI und SWG-Writer/Reader nicht
747 //                  aFont.SetColor( Color( GetCol( rAV.ico ) ) );
748                 rNum.SetBulletFont( &aFont );
749 
750                 // take only the very first character
751                 if( rAV.cbTextBefore || rAV.cbTextAfter)
752                     rNum.SetBulletChar( sTxt.GetChar( 0 ) );
753                 else
754                     rNum.SetBulletChar( 0x2190 );
755             }
756         }
757     }
758     if( bInsert )
759     {
760         if( rAV.cbTextBefore )
761         {
762             String sP( sTxt.Copy( 0, SVBT8ToByte( rAV.cbTextBefore ) ) );
763             rNum.SetPrefix( sP );
764         }
765         if( SVBT8ToByte( rAV.cbTextAfter ) )
766         {
767             String sP( rNum.GetSuffix() );
768             sP.Insert( sTxt.Copy( SVBT8ToByte( rAV.cbTextBefore ),
769                                   SVBT8ToByte( rAV.cbTextAfter  ) ) );
770             rNum.SetSuffix( sP );
771         }
772 // Die Zeichen vor und hinter mehreren Ziffern koennen leider nicht uebernommen
773 // werden, da sie der Writer ganz anders behandelt und das Ergebnis i.A.
774 // schlechter als ohne waere.
775     }
776 }
777 
778 // SetAnld bekommt einen WW-ANLD-Descriptor und einen Level und modifiziert
779 // die durch pNumR anggebeben NumRules. Wird benutzt fuer alles ausser
780 // Gliederung im Text
SetAnld(SwNumRule * pNumR,WW8_ANLD * pAD,sal_uInt8 nSwLevel,bool bOutLine)781 void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD* pAD, sal_uInt8 nSwLevel,
782     bool bOutLine)
783 {
784     SwNumFmt aNF;
785     if (pAD)
786     {                                   // Es gibt einen Anld-Sprm
787         bAktAND_fNumberAcross = 0 != SVBT8ToByte( pAD->fNumberAcross );
788         WW8_ANLV &rAV = pAD->eAnlv;
789         SetBaseAnlv(aNF, rAV, nSwLevel);        // Setze Basis-Format
790         SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine );// und Rest
791     }
792     pNumR->Set(nSwLevel, aNF);
793 }
794 
795 //-------------------------------------------------------
796 //          Kapitelnummerierung und Kapitelbullets
797 //-------------------------------------------------------
798 // Kapitelnummerierung findet in Styledefinionen statt. Sprm 13 gibt den Level
799 // an, Sprm 12 den Inhalt
800 
GetStyRule()801 SwNumRule* SwWW8ImplReader::GetStyRule()
802 {
803     if( pStyles->pStyRule )         // Bullet-Style bereits vorhanden
804         return pStyles->pStyRule;
805 
806     const String aBaseName(CREATE_CONST_ASC( "WW8StyleNum" ));
807     const String aName( rDoc.GetUniqueNumRuleName( &aBaseName, false) );
808 
809     // --> OD 2008-06-04 #i86652#
810 //    sal_uInt16 nRul = rDoc.MakeNumRule( aName );
811     sal_uInt16 nRul = rDoc.MakeNumRule( aName, 0, sal_False,
812                                     SvxNumberFormat::LABEL_ALIGNMENT );
813     // <--
814     pStyles->pStyRule = rDoc.GetNumRuleTbl()[nRul];
815     // Auto == false-> Nummerierungsvorlage
816     pStyles->pStyRule->SetAutoRule(false);
817 
818     return pStyles->pStyRule;
819 }
820 
821 // Sprm 13
Read_ANLevelNo(sal_uInt16,const sal_uInt8 * pData,short nLen)822 void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16, const sal_uInt8* pData, short nLen )
823 {
824     nSwNumLevel = 0xff; // Default: ungueltig
825 
826     if( nLen <= 0 )
827         return;
828 
829     // StyleDef ?
830     if( pAktColl )
831     {
832         // nur fuer SwTxtFmtColl, nicht CharFmt
833         // WW: 0 = no Numbering
834         SwWW8StyInf * pColl = GetStyle(nAktColl);
835         if (pColl != NULL && pColl->bColl && *pData)
836         {
837             // Bereich WW:1..9 -> SW:0..8 keine Aufzaehlung / Nummerierung
838 
839             if (*pData <= MAXLEVEL && *pData <= 9)
840             {
841                 nSwNumLevel = *pData - 1;
842                 if (!bNoAttrImport)
843                     ( (SwTxtFmtColl*) pAktColl )->AssignToListLevelOfOutlineStyle( nSwNumLevel );
844                     // Bei WW-NoNumbering koennte auch NO_NUMBERING gesetzt
845                     // werden. ( Bei normaler Nummerierung muss NO_NUM gesetzt
846                     // werden: NO_NUM : Nummerierungs-Pause,
847                     // NO_NUMBERING : ueberhaupt keine Nummerierung )
848 
849             }
850             else if( *pData == 10 || *pData == 11 )
851             {
852                 // Typ merken, der Rest geschieht bei Sprm 12
853                 pStyles->nWwNumLevel = *pData;
854             }
855         }
856     }
857     else
858     {
859         //Not StyleDef
860         if (!bAnl)
861             StartAnl(pData);        // Anfang der Gliederung / Aufzaehlung
862         NextAnlLine(pData);
863     }
864 }
865 
Read_ANLevelDesc(sal_uInt16,const sal_uInt8 * pData,short nLen)866 void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm 12
867 {
868     {
869         SwWW8StyInf * pStyInf = GetStyle(nAktColl);
870         if( !pAktColl || nLen <= 0                  // nur bei Styledef
871             || (pStyInf && !pStyInf->bColl)              // CharFmt -> ignorieren
872             || ( nIniFlags & WW8FL_NO_OUTLINE ) ){
873             nSwNumLevel = 0xff;
874             return;
875         }
876     }
877 
878     if( nSwNumLevel <= MAXLEVEL         // Bereich WW:1..9 -> SW:0..8
879         && nSwNumLevel <= 9 ){      // keine Aufzaehlung / Nummerierung
880 
881                                         // Falls bereits direkt oder durch
882                                         // Vererbung NumruleItems gesetzt sind,
883                                         // dann jetzt ausschalten #56163
884         pAktColl->SetFmtAttr( SwNumRuleItem() );
885 
886         String aName(CREATE_CONST_ASC( "Outline" ));
887         SwNumRule aNR( rDoc.GetUniqueNumRuleName( &aName ),
888                        SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
889                        OUTLINE_RULE );
890         aNR = *rDoc.GetOutlineNumRule();
891 
892         SetAnld(&aNR, (WW8_ANLD*)pData, nSwNumLevel, true);
893 
894             // fehlende Level muessen nicht aufgefuellt werden
895 
896         rDoc.SetOutlineNumRule( aNR );
897     }else if( pStyles->nWwNumLevel == 10 || pStyles->nWwNumLevel == 11 ){
898         SwNumRule* pNR = GetStyRule();
899         SetAnld(pNR, (WW8_ANLD*)pData, 0, false);
900         pAktColl->SetFmtAttr( SwNumRuleItem( pNR->GetName() ) );
901 
902         SwWW8StyInf * pStyInf = GetStyle(nAktColl);
903         if (pStyInf != NULL)
904             pStyInf->bHasStyNumRule = true;
905     }
906 }
907 
908 //-----------------------------------------
909 //      Nummerierung / Aufzaehlung
910 //-----------------------------------------
911 
912 // SetNumOlst() traegt die Numrules fuer diese Zeile ins SwNumFmt ein
913 // ( nur fuer Gliederungen im Text; Aufzaehlungen / Nummerierungen laufen
914 // ueber ANLDs )
915 // dabei wird die Info aus dem OLST geholt und nicht aus dem ANLD ( s.u. )
SetNumOlst(SwNumRule * pNumR,WW8_OLST * pO,sal_uInt8 nSwLevel)916 void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, sal_uInt8 nSwLevel)
917 {
918     SwNumFmt aNF;
919     WW8_ANLV &rAV = pO->rganlv[nSwLevel];
920     SetBaseAnlv(aNF, rAV, nSwLevel);
921                                             // ... und then the Strings
922     int nTxtOfs = 0;
923     sal_uInt8 i;
924     WW8_ANLV* pAV1;                 // search String-Positions
925     for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
926     {
927         nTxtOfs += SVBT8ToByte(pAV1->cbTextBefore)
928             + SVBT8ToByte(pAV1->cbTextAfter);
929     }
930 
931     if (!bVer67)
932         nTxtOfs *= 2;
933     SetAnlvStrings(aNF, rAV, pO->rgch + nTxtOfs, true); // und rein
934     pNumR->Set(nSwLevel, aNF);
935 }
936 
937 // der OLST kommt am Anfang jeder Section, die Gliederungen enthaelt. Die ANLDs,
938 // die an jeder Gliederungszeile haengen, enthalten nur Stuss, also werden die
939 // OLSTs waehrend der Section gemerkt, damit die Informationen beim Auftreten
940 // von Gliederungsabsaetzen zugreifbar ist.
Read_OLST(sal_uInt16,const sal_uInt8 * pData,short nLen)941 void SwWW8ImplReader::Read_OLST( sal_uInt16, const sal_uInt8* pData, short nLen )
942 {
943     if (nLen <= 0)
944     {
945         delete pNumOlst, pNumOlst = 0;
946         return;
947     }
948     if (pNumOlst)
949         delete pNumOlst;                    // nur sicherheitshalber
950     pNumOlst = new WW8_OLST;
951     if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) )         // auffuellen, falls zu kurz
952         memset( pNumOlst, 0, sizeof( *pNumOlst ) );
953     *pNumOlst = *(WW8_OLST*)pData;
954 }
955 
GetNumType(sal_uInt8 nWwLevelNo)956 WW8LvlType GetNumType(sal_uInt8 nWwLevelNo)
957 {
958     WW8LvlType nRet = WW8_None;
959     if( nWwLevelNo == 12 )
960        nRet = WW8_Pause;
961     else if( nWwLevelNo == 10 )
962        nRet = WW8_Numbering;
963     else if( nWwLevelNo == 11 )
964        nRet = WW8_Sequence;
965     else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
966        nRet = WW8_Outline;
967     return nRet;
968 }
969 
GetNumRule(sal_uInt8 nNumType)970 SwNumRule *ANLDRuleMap::GetNumRule(sal_uInt8 nNumType)
971 {
972     return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule);
973 }
974 
SetNumRule(SwNumRule * pRule,sal_uInt8 nNumType)975 void ANLDRuleMap::SetNumRule(SwNumRule *pRule, sal_uInt8 nNumType)
976 {
977     if (WW8_Numbering == nNumType)
978         mpNumberingNumRule = pRule;
979     else
980         mpOutlineNumRule = pRule;
981 }
982 
983 
984 // StartAnl wird am Anfang eines Zeilenbereichs gerufen,
985 //  der Gliederung / Nummerierung / Aufzaehlung enthaelt
StartAnl(const sal_uInt8 * pSprm13)986 void SwWW8ImplReader::StartAnl(const sal_uInt8* pSprm13)
987 {
988     bAktAND_fNumberAcross = false;
989 
990     sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType(*pSprm13));
991     if (nT == WW8_Pause || nT == WW8_None)
992         return;
993 
994     nWwNumType = nT;
995     SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
996 
997     // check for COL numbering:
998     const sal_uInt8* pS12 = 0;// sprmAnld
999     String sNumRule;
1000 
1001     if (pTableDesc)
1002     {
1003         sNumRule = pTableDesc->GetNumRuleName();
1004         if (sNumRule.Len())
1005         {
1006             pNumRule = rDoc.FindNumRulePtr(sNumRule);
1007             if (!pNumRule)
1008                 sNumRule.Erase();
1009             else
1010             {
1011                 // this is ROW numbering ?
1012                 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1013                 if (pS12 && 0 != SVBT8ToByte(((WW8_ANLD*)pS12)->fNumberAcross))
1014                     sNumRule.Erase();
1015             }
1016         }
1017     }
1018 
1019     SwWW8StyInf * pStyInf = GetStyle(nAktColl);
1020     if (!sNumRule.Len() && pStyInf->bHasStyNumRule)
1021     {
1022         sNumRule = pStyInf->pFmt->GetNumRule().GetValue();
1023         pNumRule = rDoc.FindNumRulePtr(sNumRule);
1024         if (!pNumRule)
1025             sNumRule.Erase();
1026     }
1027 
1028     if (!sNumRule.Len())
1029     {
1030         if (!pNumRule)
1031         {
1032             // --> OD 2008-06-04 #i86652#
1033 //            pNumRule = rDoc.GetNumRuleTbl()[rDoc.MakeNumRule(sNumRule)];
1034             pNumRule = rDoc.GetNumRuleTbl()[
1035                             rDoc.MakeNumRule( sNumRule, 0, sal_False,
1036                                               SvxNumberFormat::LABEL_ALIGNMENT ) ];
1037             // <--
1038         }
1039         if (pTableDesc)
1040         {
1041             if (!pS12)
1042                 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1043             if (!pS12 || !SVBT8ToByte( ((WW8_ANLD*)pS12)->fNumberAcross))
1044                 pTableDesc->SetNumRuleName(pNumRule->GetName());
1045         }
1046     }
1047 
1048     bAnl = true;
1049 
1050     // NumRules ueber Stack setzen
1051     pCtrlStck->NewAttr(*pPaM->GetPoint(),
1052         SfxStringItem(RES_FLTR_NUMRULE, pNumRule->GetName()));
1053 
1054     maANLDRules.SetNumRule(pNumRule, nWwNumType);
1055 }
1056 
1057 // NextAnlLine() wird fuer jede Zeile einer
1058 // Gliederung / Nummerierung / Aufzaehlung einmal gerufen
NextAnlLine(const sal_uInt8 * pSprm13)1059 void SwWW8ImplReader::NextAnlLine(const sal_uInt8* pSprm13)
1060 {
1061     if (!bAnl)
1062         return;
1063 
1064     SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
1065 
1066     // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
1067     // sdw3
1068 
1069     // WW:10 = Nummerierung -> SW:0 & WW:11 = Auffzaehlung -> SW:0
1070     if (*pSprm13 == 10 || *pSprm13 == 11)
1071     {
1072         nSwNumLevel = 0;
1073         if (!pNumRule->GetNumFmt(nSwNumLevel))
1074         {
1075             // noch nicht definiert
1076             // sprmAnld o. 0
1077             const sal_uInt8* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1078             SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1079         }
1080     }
1081     else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL )          // Bereich WW:1..9 -> SW:0..8
1082     {
1083         nSwNumLevel = *pSprm13 - 1;             // Gliederung
1084         // noch nicht definiert
1085         if (!pNumRule->GetNumFmt(nSwNumLevel))
1086         {
1087             if (pNumOlst)                       // es gab ein OLST
1088             {
1089                 //Assure upper levels are set, #i9556#
1090                 for (sal_uInt8 nI = 0; nI < nSwNumLevel; ++nI)
1091                 {
1092                     if (!pNumRule->GetNumFmt(nI))
1093                         SetNumOlst(pNumRule, pNumOlst, nI);
1094                 }
1095 
1096                 SetNumOlst(pNumRule, pNumOlst , nSwNumLevel);
1097             }
1098             else                                // kein Olst, nimm Anld
1099             {
1100                 // sprmAnld
1101                 const sal_uInt8* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1102                 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1103             }
1104         }
1105     }
1106     else
1107         nSwNumLevel = 0xff;                 // keine Nummer
1108 
1109 	SwTxtNode* pNd = pPaM->GetNode()->GetTxtNode();
1110     if (nSwNumLevel < MAXLEVEL)
1111         pNd->SetAttrListLevel( nSwNumLevel );
1112     else
1113     {
1114         pNd->SetAttrListLevel(0);
1115         pNd->SetCountedInList( false );
1116     }
1117 }
1118 
StopAllAnl(bool bGoBack)1119 void SwWW8ImplReader::StopAllAnl(bool bGoBack)
1120 {
1121     //Of course we're not restarting, but we'll make use of our knowledge
1122     //of the implementation to do it.
1123     StopAnlToRestart(WW8_None, bGoBack);
1124 }
1125 
StopAnlToRestart(sal_uInt8 nNewType,bool bGoBack)1126 void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType, bool bGoBack)
1127 {
1128     if (bGoBack)
1129     {
1130         SwPosition aTmpPos(*pPaM->GetPoint());
1131         pPaM->Move(fnMoveBackward, fnGoCntnt);
1132         pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1133         *pPaM->GetPoint() = aTmpPos;
1134     }
1135     else
1136         pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1137 
1138     maANLDRules.mpNumberingNumRule = 0;
1139     /*
1140      #i18816#
1141      my take on this problem is that moving either way from an outline to a
1142      numbering doesn't halt the outline, while the numbering is always halted
1143     */
1144     bool bNumberingNotStopOutline =
1145         (((nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1146         ((nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1147     if (!bNumberingNotStopOutline)
1148         maANLDRules.mpOutlineNumRule = 0;
1149 
1150     nSwNumLevel = 0xff;
1151     nWwNumType = WW8_None;
1152     bAnl = false;
1153 }
1154 
WW8TabBandDesc(WW8TabBandDesc & rBand)1155 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand )
1156 {
1157     *this = rBand;
1158     if( rBand.pTCs )
1159     {
1160         pTCs = new WW8_TCell[nWwCols];
1161         memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1162     }
1163     if( rBand.pSHDs )
1164     {
1165         pSHDs = new WW8_SHD[nWwCols];
1166         memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1167     }
1168     if( rBand.pNewSHDs )
1169     {
1170         pNewSHDs = new sal_uInt32[nWwCols];
1171         memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32));
1172     }
1173     memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1174 }
1175 
1176 // ReadDef liest die Zellenpositionen und ggfs die Umrandungen eines Bandes ein
ReadDef(bool bVer67,const sal_uInt8 * pS)1177 void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS)
1178 {
1179     if (!bVer67)
1180         pS++;
1181 
1182     short nLen = (sal_Int16)SVBT16ToShort( pS - 2 ); // nicht schoen
1183 
1184     sal_uInt8 nCols = *pS;                       // Anzahl der Zellen
1185     short nOldCols = nWwCols;
1186 
1187     if( nCols > MAX_COL )
1188         return;
1189 
1190     nWwCols = nCols;
1191 
1192     const sal_uInt8* pT = &pS[1];
1193     nLen --;
1194     int i;
1195     for(i=0; i<=nCols; i++, pT+=2 )
1196         nCenter[i] = (sal_Int16)SVBT16ToShort( pT );    // X-Raender
1197     nLen -= 2 * ( nCols + 1 );
1198     if( nCols != nOldCols ) // andere Spaltenzahl
1199     {
1200         delete[] pTCs, pTCs = 0;
1201         delete[] pSHDs, pSHDs = 0;
1202         delete[] pNewSHDs, pNewSHDs = 0;
1203     }
1204 
1205     short nFileCols = nLen / ( bVer67 ? 10 : 20 );  // wirklich abgespeichert
1206 
1207     if (!pTCs && nCols)
1208     {
1209         // lege leere TCs an
1210         pTCs = new WW8_TCell[nCols];
1211         setcelldefaults(pTCs,nCols);
1212     }
1213 
1214     short nColsToRead = nFileCols;
1215     if (nColsToRead > nCols)
1216         nColsToRead = nCols;
1217 
1218     if( nColsToRead )
1219     {
1220         // lies TCs ein
1221 
1222         /*
1223             Achtung: ab Ver8 ist ein reserve-ushort je TC eingefuegt und auch
1224                      der Border-Code ist doppelt so gross, daher ist hier
1225                              kein simples kopieren moeglich,
1226                              d.h.: pTCs[i] = *pTc;  geht leider nicht.
1227             ---
1228             Vorteil: Arbeitstruktur ist jetzt viel bequemer zu handhaben!
1229         */
1230         WW8_TCell* pAktTC  = pTCs;
1231         if( bVer67 )
1232         {
1233             WW8_TCellVer6* pTc = (WW8_TCellVer6*)pT;
1234             for(i=0; i<nColsToRead; i++, ++pAktTC,++pTc)
1235             {
1236                 if( i < nColsToRead )
1237                 {               // TC aus File ?
1238                     sal_uInt8 aBits1 = SVBT8ToByte( pTc->aBits1Ver6 );
1239                     pAktTC->bFirstMerged    = ( ( aBits1 & 0x01 ) != 0 );
1240                     pAktTC->bMerged     = ( ( aBits1 & 0x02 ) != 0 );
1241                     memcpy( pAktTC->rgbrc[ WW8_TOP      ].aBits1,
1242                                     pTc->rgbrcVer6[ WW8_TOP     ].aBits1, sizeof( SVBT16 ) );
1243                     memcpy( pAktTC->rgbrc[ WW8_LEFT     ].aBits1,
1244                                     pTc->rgbrcVer6[ WW8_LEFT    ].aBits1, sizeof( SVBT16 ) );
1245                     memcpy( pAktTC->rgbrc[ WW8_BOT      ].aBits1,
1246                                     pTc->rgbrcVer6[ WW8_BOT     ].aBits1, sizeof( SVBT16 ) );
1247                     memcpy( pAktTC->rgbrc[ WW8_RIGHT    ].aBits1,
1248                                     pTc->rgbrcVer6[ WW8_RIGHT   ].aBits1, sizeof( SVBT16 ) );
1249                     if(    ( pAktTC->bMerged )
1250                             && ( i > 0             ) )
1251                     {
1252                         // Cell gemerged -> merken
1253                         //bWWMergedVer6[i] = true;
1254                         memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1,
1255                                 pTc->rgbrcVer6[  WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1256                             // right Border in vorige Zelle uebernehmen
1257                             // Hier darf bExist nicht auf false gesetzt werden, da WW
1258                             // in den Textboxen diese Zellen nicht mitzaehlt....
1259                     }
1260                 }
1261             }
1262         }
1263         else
1264         {
1265             WW8_TCellVer8* pTc = (WW8_TCellVer8*)pT;
1266             for (int k = 0; k < nColsToRead; ++k, ++pAktTC, ++pTc )
1267             {
1268                 sal_uInt16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 );
1269                 pAktTC->bFirstMerged    = ( ( aBits1 & 0x0001 ) != 0 );
1270                 pAktTC->bMerged         = ( ( aBits1 & 0x0002 ) != 0 );
1271                 pAktTC->bVertical       = ( ( aBits1 & 0x0004 ) != 0 );
1272                 pAktTC->bBackward       = ( ( aBits1 & 0x0008 ) != 0 );
1273                 pAktTC->bRotateFont     = ( ( aBits1 & 0x0010 ) != 0 );
1274                 pAktTC->bVertMerge      = ( ( aBits1 & 0x0020 ) != 0 );
1275                 pAktTC->bVertRestart    = ( ( aBits1 & 0x0040 ) != 0 );
1276                 pAktTC->nVertAlign      = ( ( aBits1 & 0x0180 ) >> 7 );
1277                 // am Rande: im aBits1 verstecken sich noch 7 Reserve-Bits,
1278                 //           anschliessend folgen noch 16 weitere Reserve-Bits
1279 
1280                 // In Version 8 koennen wir alle Bordercodes auf einmal kopieren!
1281                 memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) );
1282             }
1283         }
1284 
1285         // #i25071 In '97 text direction appears to be only set using TC properties
1286         // not with sprmTTextFlow so we need to cycle through the maDirections and
1287         // double check any non-default directions
1288         for (int k = 0; k < nCols; ++k)
1289         {
1290             if(maDirections[k] == 4)
1291             {
1292                 if(pTCs[k].bVertical)
1293                 {
1294                     if(pTCs[k].bBackward)
1295                         maDirections[k] = 3;
1296                     else
1297                         maDirections[k] = 1;
1298                 }
1299             }
1300         }
1301 
1302 
1303     }
1304 }
1305 
ProcessSprmTSetBRC(bool bVer67,const sal_uInt8 * pParamsTSetBRC)1306 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC)
1307 {
1308     if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
1309     {
1310         sal_uInt8 nitcFirst= pParamsTSetBRC[0];// first col to be changed
1311         sal_uInt8 nitcLim  = pParamsTSetBRC[1];// (last col to be changed)+1
1312         sal_uInt8 nFlag    = *(pParamsTSetBRC+2);
1313 
1314         if (nitcFirst >= nWwCols)
1315             return;
1316 
1317         if (nitcLim > nWwCols)
1318             nitcLim = nWwCols;
1319 
1320         bool bChangeRight  = (nFlag & 0x08) ? true : false;
1321         bool bChangeBottom = (nFlag & 0x04) ? true : false;
1322         bool bChangeLeft   = (nFlag & 0x02) ? true : false;
1323         bool bChangeTop    = (nFlag & 0x01) ? true : false;
1324 
1325         WW8_TCell* pAktTC  = pTCs + nitcFirst;
1326         if( bVer67 )
1327         {
1328             WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3);
1329 
1330             for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1331             {
1332                 if( bChangeTop )
1333                     memcpy( pAktTC->rgbrc[ WW8_TOP  ].aBits1,
1334                             pBRC->aBits1,
1335                             sizeof( SVBT16 ) );
1336                 if( bChangeLeft )
1337                     memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1338                             pBRC->aBits1,
1339                             sizeof( SVBT16 ) );
1340                 if( bChangeBottom )
1341                     memcpy( pAktTC->rgbrc[ WW8_BOT  ].aBits1,
1342                             pBRC->aBits1,
1343                             sizeof( SVBT16 ) );
1344                 if( bChangeRight )
1345                     memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1346                             pBRC->aBits1,
1347                             sizeof( SVBT16 ) );
1348             }
1349         }
1350         else
1351         {
1352             WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3);
1353 
1354             for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1355             {
1356                 if( bChangeTop )
1357                     memcpy( pAktTC->rgbrc[ WW8_TOP  ].aBits1,
1358                             pBRC->aBits1,
1359                             sizeof( WW8_BRC ) );
1360                 if( bChangeLeft )
1361                     memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1362                             pBRC->aBits1,
1363                             sizeof( WW8_BRC ) );
1364                 if( bChangeBottom )
1365                     memcpy( pAktTC->rgbrc[ WW8_BOT  ].aBits1,
1366                             pBRC->aBits1,
1367                             sizeof( WW8_BRC ) );
1368                 if( bChangeRight )
1369                     memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1370                             pBRC->aBits1,
1371                             sizeof( WW8_BRC ) );
1372             }
1373 
1374 
1375 
1376         }
1377     }
1378 }
1379 
ProcessSprmTTableBorders(bool bVer67,const sal_uInt8 * pParams)1380 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams)
1381 {
1382     // sprmTTableBorders
1383     if( bVer67 )
1384     {
1385         for( int i = 0; i < 6; ++i )
1386         {
1387             aDefBrcs[i].aBits1[0] = pParams[   2*i ];
1388             aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ];
1389         }
1390     }
1391     else // aDefBrcs = *(BRC(*)[6])pS;
1392         memcpy( aDefBrcs, pParams, 24 );
1393 }
1394 
ProcessSprmTDxaCol(const sal_uInt8 * pParamsTDxaCol)1395 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol)
1396 {
1397     // sprmTDxaCol (opcode 0x7623) changes the width of cells
1398     // whose index is within a certain range to be a certain value.
1399 
1400     if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s)
1401     {
1402         sal_uInt8 nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1403         sal_uInt8 nitcLim  = pParamsTDxaCol[1]; // (last col to be changed)+1
1404         short nDxaCol = (sal_Int16)SVBT16ToShort( pParamsTDxaCol + 2 );
1405         short nOrgWidth;
1406         short nDelta;
1407 
1408         for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1409         {
1410             nOrgWidth  = nCenter[i+1] - nCenter[i];
1411             nDelta     = nDxaCol - nOrgWidth;
1412             for( int j = i+1; j <= nWwCols; j++ )
1413             {
1414                 nCenter[j] = nCenter[j] + nDelta;
1415             }
1416         }
1417     }
1418 }
1419 
ProcessSprmTInsert(const sal_uInt8 * pParamsTInsert)1420 void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8* pParamsTInsert)
1421 {
1422     if( nWwCols && pParamsTInsert )        // set one or more cell length(s)
1423     {
1424         sal_uInt8 nitcInsert = pParamsTInsert[0]; // position at which to insert
1425         if (nitcInsert >= MAX_COL)  // cannot insert into cell outside max possible index
1426             return;
1427         sal_uInt8 nctc  = pParamsTInsert[1];      // number of cells
1428         sal_uInt16 ndxaCol = SVBT16ToShort( pParamsTInsert+2 );
1429 
1430         short nNewWwCols;
1431         if (nitcInsert > nWwCols)
1432         {
1433             nNewWwCols = nitcInsert+nctc;
1434             //if new count would be outside max possible count, clip it, and calc a new replacement
1435             //legal nctc
1436             if (nNewWwCols > MAX_COL)
1437             {
1438                 nNewWwCols = MAX_COL;
1439                 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nitcInsert);
1440             }
1441         }
1442         else
1443         {
1444             nNewWwCols = nWwCols+nctc;
1445             //if new count would be outside max possible count, clip it, and calc a new replacement
1446             //legal nctc
1447             if (nNewWwCols > MAX_COL)
1448             {
1449                 nNewWwCols = MAX_COL;
1450                 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nWwCols);
1451             }
1452         }
1453 
1454         WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1455         setcelldefaults(pTC2s, nNewWwCols);
1456 
1457         if (pTCs)
1458         {
1459             memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1460             delete[] pTCs;
1461         }
1462         pTCs = pTC2s;
1463 
1464         //If we have to move some cells
1465         if (nitcInsert <= nWwCols)
1466         {
1467             // adjust the left x-position of the dummy at the very end
1468             nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1469             for( int i = nWwCols-1; i >= nitcInsert; i--)
1470             {
1471                 // adjust the left x-position
1472                 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1473 
1474                 // adjust the cell's borders
1475                 pTCs[i + nctc] = pTCs[i];
1476             }
1477         }
1478 
1479         //if itcMac is larger than full size, fill in missing ones first
1480         for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1481             nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1482 
1483         //now add in our new cells
1484         for( int j = 0;j < nctc; j++)
1485             nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1486 
1487         nWwCols = nNewWwCols;
1488     }
1489 }
1490 
ProcessDirection(const sal_uInt8 * pParams)1491 void WW8TabBandDesc::ProcessDirection(const sal_uInt8* pParams)
1492 {
1493     sal_uInt8 nStartCell = *pParams++;
1494     sal_uInt8 nEndCell = *pParams++;
1495     sal_uInt16 nCode = SVBT16ToShort(pParams);
1496 
1497     ASSERT(nStartCell < nEndCell, "not as I thought");
1498     ASSERT(nEndCell < MAX_COL + 1, "not as I thought");
1499     if (nStartCell > MAX_COL)
1500         return;
1501     if (nEndCell > MAX_COL + 1)
1502         nEndCell = MAX_COL + 1;
1503 
1504     for (;nStartCell < nEndCell; ++nStartCell)
1505         maDirections[nStartCell] = nCode;
1506 }
1507 
ProcessSpacing(const sal_uInt8 * pParams)1508 void WW8TabBandDesc::ProcessSpacing(const sal_uInt8* pParams)
1509 {
1510     sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1511     ASSERT(nLen == 6, "Unexpected spacing len");
1512     if (nLen != 6)
1513         return;
1514     mbHasSpacing=true;
1515 #ifdef DBG_UTIL
1516     sal_uInt8 nWhichCell = *pParams;
1517     ASSERT(nWhichCell == 0, "Expected cell to be 0!");
1518 #endif
1519     ++pParams; //Skip which cell
1520     ++pParams; //unknown byte
1521 
1522     sal_uInt8 nSideBits = *pParams++;
1523     ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1524     ++pParams; //unknown byte
1525     sal_uInt16 nValue =  SVBT16ToShort( pParams );
1526     for (int i = wwTOP; i <= wwRIGHT; i++)
1527     {
1528         switch (nSideBits & (1 << i))
1529         {
1530             case 1 << wwTOP:
1531                 mnDefaultTop = nValue;
1532                 break;
1533             case 1 << wwLEFT:
1534                 mnDefaultLeft = nValue;
1535                 break;
1536             case 1 << wwBOTTOM:
1537                 mnDefaultBottom = nValue;
1538                 break;
1539             case 1 << wwRIGHT:
1540                 mnDefaultRight = nValue;
1541                 break;
1542             case 0:
1543                 break;
1544             default:
1545                 ASSERT(!this, "Impossible");
1546                 break;
1547         }
1548     }
1549 }
1550 
ProcessSpecificSpacing(const sal_uInt8 * pParams)1551 void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8* pParams)
1552 {
1553     sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1554     ASSERT(nLen == 6, "Unexpected spacing len");
1555     if (nLen != 6)
1556         return;
1557     sal_uInt8 nWhichCell = *pParams++;
1558     ASSERT(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1559     if (nWhichCell >= MAX_COL + 1)
1560         return;
1561 
1562     ++pParams; //unknown byte
1563     sal_uInt8 nSideBits = *pParams++;
1564     ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1565     nOverrideSpacing[nWhichCell] |= nSideBits;
1566 
1567     ASSERT(nOverrideSpacing[nWhichCell] < 0x10,
1568         "Unexpected value for nSideBits");
1569 #ifdef DBG_UTIL
1570     sal_uInt8 nUnknown2 = *pParams;
1571     ASSERT(nUnknown2 == 0x3, "Unexpected value for spacing2");
1572 #endif
1573     ++pParams;
1574     sal_uInt16 nValue =  SVBT16ToShort( pParams );
1575 
1576     for (int i=0; i < 4; i++)
1577     {
1578         if (nSideBits & (1 << i))
1579             nOverrideValues[nWhichCell][i] = nValue;
1580     }
1581 }
1582 
ProcessSprmTDelete(const sal_uInt8 * pParamsTDelete)1583 void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8* pParamsTDelete)
1584 {
1585     if( nWwCols && pParamsTDelete )        // set one or more cell length(s)
1586     {
1587         sal_uInt8 nitcFirst= pParamsTDelete[0]; // first col to be deleted
1588         if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1589             return;
1590         sal_uInt8 nitcLim  = pParamsTDelete[1]; // (last col to be deleted)+1
1591         if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1592             return;
1593 
1594         /*
1595          * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1596          * greater than or equal to itcLim to be moved
1597          */
1598         int nShlCnt  = nWwCols - nitcLim; // count of cells to be shifted
1599 
1600         if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1601         {
1602             WW8_TCell* pAktTC  = pTCs + nitcFirst;
1603             int i = 0;
1604             while( i < nShlCnt )
1605             {
1606                 // adjust the left x-position
1607                 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1608 
1609                 // adjust the cell's borders
1610                 *pAktTC = pTCs[ nitcLim + i];
1611 
1612                 ++i;
1613                 ++pAktTC;
1614             }
1615             // adjust the left x-position of the dummy at the very end
1616             nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1617         }
1618 
1619         short nCellsDeleted = nitcLim - nitcFirst;
1620         //clip delete request to available number of cells
1621         if (nCellsDeleted > nWwCols)
1622             nCellsDeleted = nWwCols;
1623         nWwCols -= nCellsDeleted;
1624     }
1625 }
1626 
1627 // ReadShd liest ggfs die Hintergrundfarben einer Zeile ein.
1628 // Es muss vorher ReadDef aufgerufen worden sein
ReadShd(const sal_uInt8 * pS)1629 void WW8TabBandDesc::ReadShd(const sal_uInt8* pS )
1630 {
1631     sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1632     if( !nLen )
1633         return;
1634 
1635     if( !pSHDs )
1636     {
1637         pSHDs = new WW8_SHD[nWwCols];
1638         memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) );
1639     }
1640 
1641     short nAnz = nLen >> 1;
1642     if (nAnz > nWwCols)
1643         nAnz = nWwCols;
1644 
1645     SVBT16* pShd;
1646     int i;
1647     for(i=0, pShd = (SVBT16*)pS; i<nAnz; i++, pShd++ )
1648         pSHDs[i].SetWWValue( *pShd );
1649 }
1650 
ReadNewShd(const sal_uInt8 * pS,bool bVer67)1651 void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67)
1652 {
1653     sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1654     if (!nLen)
1655         return;
1656 
1657     if (!pNewSHDs)
1658         pNewSHDs = new sal_uInt32[nWwCols];
1659 
1660     short nAnz = nLen / 10; //10 bytes each
1661     if (nAnz > nWwCols)
1662         nAnz = nWwCols;
1663 
1664     int i=0;
1665     while (i < nAnz)
1666         pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1667 
1668     while (i < nWwCols)
1669         pNewSHDs[i++] = COL_AUTO;
1670 }
1671 
setcelldefaults(WW8_TCell * pCells,short nCols)1672 void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols)
1673 {
1674     memset( pCells, 0, nCols * sizeof( WW8_TCell ) );
1675 }
1676 
HasTabCellSprm(WW8PLCFx_Cp_FKP * pPap,bool bVer67)1677 const sal_uInt8 *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1678 {
1679     const sal_uInt8 *pParams;
1680     if (bVer67)
1681         pParams = pPap->HasSprm(24);
1682     else
1683     {
1684         if (0 == (pParams = pPap->HasSprm(0x244B)))
1685             pParams = pPap->HasSprm(0x2416);
1686     }
1687     return pParams;
1688 }
1689 
1690 enum wwTableSprm
1691 {
1692     sprmNil,
1693 
1694     sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable,
1695     sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc,
1696     sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
1697     sprmTDxaGapHalf, sprmTTableBorders,
1698 
1699     sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing
1700 };
1701 
GetTableSprm(sal_uInt16 nId,ww::WordVersion eVer)1702 wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1703 {
1704     switch (eVer)
1705     {
1706         case ww::eWW8:
1707             switch (nId)
1708             {
1709                 case 0xF614:
1710                     return sprmTTableWidth;
1711                 case 0x7629:
1712                     return sprmTTextFlow;
1713                 case 0x3403:
1714                     return sprmTFCantSplit;
1715                 case 0x3404:
1716                     return sprmTTableHeader;
1717                 case 0x3466:
1718                     return sprmTFCantSplit90;
1719                 case 0x5400:
1720                     return sprmTJc;
1721                 case 0x560B:
1722                     return sprmTFBiDi;
1723                 case 0x5622:
1724                     return sprmTDelete;
1725                 case 0x7621:
1726                     return sprmTInsert;
1727                 case 0x7623:
1728                     return sprmTDxaCol;
1729                 case 0x9407:
1730                     return sprmTDyaRowHeight;
1731                 case 0x9601:
1732                     return sprmTDxaLeft;
1733                 case 0x9602:
1734                     return sprmTDxaGapHalf;
1735                 case 0xD605:
1736                     return sprmTTableBorders;
1737                 case 0xD608:
1738                     return sprmTDefTable;
1739                 case 0xD609:
1740                     return sprmTDefTableShd;
1741                 case 0xD612:
1742                     return sprmTDefTableNewShd;
1743                 case 0xD620:
1744                     return sprmTSetBrc;
1745                 case 0xD632:
1746                     return sprmTSpacing;
1747                 case 0xD634:
1748                     return sprmTNewSpacing;
1749             }
1750             break;
1751         case ww::eWW7:
1752         case ww::eWW6:
1753             switch (nId)
1754             {
1755                 case 182:
1756                     return sprmTJc;
1757                 case 183:
1758                     return sprmTDxaLeft;
1759                 case 184:
1760                     return sprmTDxaGapHalf;
1761                 case 186:
1762                     return sprmTTableHeader;
1763                 case 187:
1764                     return sprmTTableBorders;
1765                 case 189:
1766                     return sprmTDyaRowHeight;
1767                 case 190:
1768                     return sprmTDefTable;
1769                 case 191:
1770                     return sprmTDefTableShd;
1771                 case 193:
1772                     return sprmTSetBrc;
1773                 case 194:
1774                     return sprmTInsert;
1775                 case 195:
1776                     return sprmTDelete;
1777                 case 196:
1778                     return sprmTDxaCol;
1779             }
1780             break;
1781         case ww::eWW2:
1782             switch (nId)
1783             {
1784                 case 146:
1785                     return sprmTJc;
1786                 case 147:
1787                     return sprmTDxaLeft;
1788                 case 148:
1789                     return sprmTDxaGapHalf;
1790                 case 153:
1791                     return sprmTDyaRowHeight;
1792                 case 154:
1793                     return sprmTDefTable;
1794                 case 155:
1795                     return sprmTDefTableShd;
1796                 case 157:
1797                     return sprmTSetBrc;
1798                 case 158:
1799                     return sprmTInsert;
1800                 case 159:
1801                     return sprmTDelete;
1802                 case 160:
1803                     return sprmTDxaCol;
1804             }
1805             break;
1806     }
1807     return sprmNil;
1808 }
1809 
WW8TabDesc(SwWW8ImplReader * pIoClass,WW8_CP nStartCp)1810 WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
1811     mpOldRedlineStack(0),
1812 	pIo(pIoClass),
1813 	pFirstBand(0),
1814 	pActBand(0),
1815     pTmpPos(0),
1816 	pTblNd(0),
1817 	pTabLines(0),
1818 	pTabLine(0),
1819 	pTabBoxes(0),
1820 	pTabBox(0),
1821     pMergeGroups(0),
1822 	pAktWWCell(0),
1823 	nRows(0),
1824 	nDefaultSwCols(0),
1825 	nBands(0),
1826     nMinLeft(0),
1827 	nConvertedLeft(0),
1828 	nMaxRight(0),
1829 	nSwWidth(0),
1830 	nPreferredWidth(0),
1831 	nOrgDxaLeft(0),
1832 	bOk(true),
1833 	bClaimLineFmt(false),
1834     eOri(text::HoriOrientation::NONE),
1835 	bIsBiDi(false),
1836     nAktRow(0),
1837 	nAktBandRow(0),
1838 	nAktCol(0),
1839     nRowsToRepeat(0),
1840 	pTable(0),
1841 	pParentPos(0),
1842     pFlyFmt(0),
1843     aItemSet(pIo->rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1)
1844 {
1845     pIo->bAktAND_fNumberAcross = false;
1846 
1847     static const sal_Int16 aOriArr[] =
1848     {
1849         text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1850     };
1851 
1852     bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion());
1853     WW8_TablePos aTabPos;
1854 
1855     WW8PLCFxSave1 aSave;
1856     pIo->pPlcxMan->GetPap()->Save( aSave );
1857 
1858     WW8PLCFx_Cp_FKP* pPap = pIo->pPlcxMan->GetPapPLCF();
1859 
1860     eOri = text::HoriOrientation::LEFT;
1861 
1862     WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1863 
1864     wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion());
1865 
1866     // process pPap until end of table found
1867     do
1868     {
1869         short nTabeDxaNew      = SHRT_MAX;
1870         bool bTabRowJustRead   = false;
1871         const sal_uInt8* pShadeSprm = 0;
1872         const sal_uInt8* pNewShadeSprm = 0;
1873         WW8_TablePos *pTabPos  = 0;
1874 
1875         // Suche Ende einer TabZeile
1876         if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->nInTable)))
1877         {
1878             bOk = false;
1879             break;
1880         }
1881 
1882         // Get the SPRM chains:
1883         // first from PAP and then from PCD (of the Piece Table)
1884         WW8PLCFxDesc aDesc;
1885         pPap->GetSprms( &aDesc );
1886         WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1887 
1888         const sal_uInt8* pParams = aSprmIter.GetAktParams();
1889         for (int nLoop = 0; nLoop < 2; ++nLoop)
1890         {
1891             bool bRepeatedSprm = false;
1892             while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams()))
1893             {
1894                 sal_uInt16 nId = aSprmIter.GetAktId();
1895                 wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion());
1896                 switch (eSprm)
1897                 {
1898                     case sprmTTableWidth:
1899                         {
1900                         const sal_uInt8 b0 = pParams[0];
1901                         const sal_uInt8 b1 = pParams[1];
1902                         const sal_uInt8 b2 = pParams[2];
1903                         if (b0 == 3) // Twips
1904                             nPreferredWidth = b2 * 0x100 + b1;
1905                         }
1906                         break;
1907                     case sprmTTextFlow:
1908                         pNewBand->ProcessDirection(pParams);
1909                         break;
1910                     case sprmTFCantSplit:
1911                         pNewBand->bCantSplit = *pParams;
1912                         bClaimLineFmt = true;
1913                         break;
1914                     case sprmTFCantSplit90:
1915                         pNewBand->bCantSplit90 = *pParams;
1916                         bClaimLineFmt = true;
1917                         break;
1918                     case sprmTTableBorders:
1919                         pNewBand->ProcessSprmTTableBorders(bOldVer, pParams);
1920                         break;
1921                     case sprmTTableHeader:
1922                         if (!bRepeatedSprm)
1923                         {
1924                             nRowsToRepeat++;
1925                             bRepeatedSprm = true;
1926                         }
1927                         break;
1928                     case sprmTJc:
1929                         // sprmTJc  -  Justification Code
1930                         if (nRows == 0)
1931                             eOri = aOriArr[*pParams & 0x3];
1932                         break;
1933                     case sprmTFBiDi:
1934                         bIsBiDi = SVBT16ToShort(pParams) ? true : false;
1935                         break;
1936                     case sprmTDxaGapHalf:
1937                         pNewBand->nGapHalf = (sal_Int16)SVBT16ToShort( pParams );
1938                         break;
1939                     case sprmTDyaRowHeight:
1940                         pNewBand->nLineHeight = (sal_Int16)SVBT16ToShort( pParams );
1941                         bClaimLineFmt = true;
1942                         break;
1943                     case sprmTDefTable:
1944                         pNewBand->ReadDef(bOldVer, pParams);
1945                         bTabRowJustRead = true;
1946                         break;
1947                     case sprmTDefTableShd:
1948                         pShadeSprm = pParams;
1949                         break;
1950                     case sprmTDefTableNewShd:
1951                         pNewShadeSprm = pParams;
1952                         break;
1953                     case sprmTDxaLeft:
1954                         // our Writer cannot shift single table lines
1955                         // horizontally so we have to find the smallest
1956                         // parameter (meaning the left-most position) and then
1957                         // shift the whole table to that margin (see below)
1958                         {
1959                             short nDxaNew = (sal_Int16)SVBT16ToShort( pParams );
1960                             nOrgDxaLeft = nDxaNew;
1961                             if( nDxaNew < nTabeDxaNew )
1962                                 nTabeDxaNew = nDxaNew;
1963                         }
1964                         break;
1965                     case sprmTSetBrc:
1966                         pNewBand->ProcessSprmTSetBRC(bOldVer, pParams);
1967                         break;
1968                     case sprmTDxaCol:
1969                         pNewBand->ProcessSprmTDxaCol(pParams);
1970                         break;
1971                     case sprmTInsert:
1972                         pNewBand->ProcessSprmTInsert(pParams);
1973                         break;
1974                     case sprmTDelete:
1975                         pNewBand->ProcessSprmTDelete(pParams);
1976                         break;
1977                     case sprmTNewSpacing:
1978                         pNewBand->ProcessSpacing(pParams);
1979                         break;
1980                     case sprmTSpacing:
1981                         pNewBand->ProcessSpecificSpacing(pParams);
1982                         break;
1983 					default:
1984 						;
1985                 }
1986                 aSprmIter++;
1987             }
1988 
1989             if( !nLoop )
1990             {
1991                 pPap->GetPCDSprms(  aDesc );
1992                 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1993             }
1994         }
1995 
1996         // #55171: WW-Tabellen koennen Fly-Wechsel beinhalten daher hier
1997         // Tabellen abbrechen und neu beginnen noch steht *pPap noch vor
1998         // TabRowEnd, daher kann TestApo() mit letztem Parameter false und
1999         // damit wirksam gerufen werden.
2000 
2001         if (bTabRowJustRead)
2002         {
2003             if (pShadeSprm)
2004                 pNewBand->ReadShd(pShadeSprm);
2005             if (pNewShadeSprm)
2006                 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
2007         }
2008 
2009         if( nTabeDxaNew < SHRT_MAX )
2010         {
2011             short* pCenter  = pNewBand->nCenter;
2012             short firstDxaCenter = *pCenter;
2013             for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
2014             {
2015                 // #i30298# Use sprmTDxaLeft to adjust the left indent
2016                 // #i40461# Use dxaGapHalf during calculation
2017                 *pCenter +=
2018                     (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
2019             }
2020         }
2021 
2022         if (!pActBand)
2023             pActBand = pFirstBand = pNewBand;
2024         else
2025         {
2026             pActBand->pNextBand = pNewBand;
2027             pActBand = pNewBand;
2028         }
2029         nBands++;
2030 
2031         pNewBand = new WW8TabBandDesc;
2032 
2033         nRows++;
2034         pActBand->nRows++;
2035 
2036         //Seek our pap to its next block of properties
2037         WW8PLCFxDesc aRes;
2038         aRes.pMemPos = 0;
2039         aRes.nStartPos = nStartCp;
2040 
2041         if (!(pPap->SeekPos(aRes.nStartPos)))
2042         {
2043             aRes.nEndPos = WW8_CP_MAX;
2044             pPap->SetDirty(true);
2045         }
2046         pPap->GetSprms(&aRes);
2047         pPap->SetDirty(false);
2048 
2049         //Are we at the end of available properties
2050         if (
2051              !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
2052              aRes.nStartPos == WW8_CP_MAX
2053            )
2054         {
2055             bOk = false;
2056             break;
2057         }
2058 
2059         //Are we still in a table cell
2060         pParams = HasTabCellSprm(pPap, bOldVer);
2061         const sal_uInt8 *pLevel = pPap->HasSprm(0x6649);
2062         // InTable
2063         if (!pParams || (1 != *pParams) ||
2064             (pLevel && (*pLevel <= pIo->nInTable)))
2065         {
2066             break;
2067         }
2068 
2069         //Get the end of row new table positioning data
2070         WW8_CP nMyStartCp=nStartCp;
2071         if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->nInTable))
2072             if (SwWW8ImplReader::ParseTabPos(&aTabPos, pPap))
2073                 pTabPos = &aTabPos;
2074 
2075         //Move back to this cell
2076         aRes.pMemPos = 0;
2077         aRes.nStartPos = nStartCp;
2078 
2079         // #114237 PlcxMan currently points too far ahead so we need to bring
2080         // it back to where we are trying to make a table
2081         pIo->pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2082         if (!(pPap->SeekPos(aRes.nStartPos)))
2083         {
2084             aRes.nEndPos = WW8_CP_MAX;
2085             pPap->SetDirty(true);
2086         }
2087         pPap->GetSprms(&aRes);
2088         pPap->SetDirty(false);
2089 
2090         //Does this row match up with the last row closely enough to be
2091         //considered part of the same table
2092         ApoTestResults aApo = pIo->TestApo(pIo->nInTable + 1, false, pTabPos);
2093 
2094         /*
2095         ##513##, #79474# If this is not sufficent, then we should look at
2096         sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2097         part of this table, but instead is an absolutely positioned table
2098         outside of this one
2099         */
2100         if (aApo.mbStopApo)
2101             break;
2102         if (aApo.mbStartApo)
2103         {
2104             //if there really is a fly here, and not a "null" fly then break.
2105             WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos);
2106             if (pNewFly)
2107                 delete pNewFly;
2108             else
2109                 break;
2110         }
2111 
2112         nStartCp = aRes.nEndPos;
2113     }
2114     while( 1 );
2115 
2116     if( bOk )
2117     {
2118         if( pActBand->nRows > 1 )
2119         {
2120             // Letztes Band hat mehr als 1 Zeile
2121             delete pNewBand;
2122             pNewBand = new WW8TabBandDesc( *pActBand ); // neues machen
2123             pActBand->nRows--;      // wegen Sonderbehandlung Raender-Defaults
2124             pNewBand->nRows = 1;
2125             pActBand->pNextBand = pNewBand; // am Ende einschleifen
2126             nBands++;
2127             pNewBand = 0;                   // nicht loeschen
2128         }
2129         CalcDefaults();
2130     }
2131     delete pNewBand;
2132 
2133     pIo->pPlcxMan->GetPap()->Restore( aSave );
2134 }
2135 
~WW8TabDesc()2136 WW8TabDesc::~WW8TabDesc()
2137 {
2138     WW8TabBandDesc* pR = pFirstBand;
2139     while(pR)
2140     {
2141         WW8TabBandDesc* pR2 = pR->pNextBand;
2142         delete pR;
2143         pR = pR2;
2144     }
2145 
2146     delete pParentPos;
2147     delete pMergeGroups;
2148 }
2149 
CalcDefaults()2150 void WW8TabDesc::CalcDefaults()
2151 {
2152     short nMinCols = SHRT_MAX;
2153     WW8TabBandDesc* pR;
2154 
2155     nMinLeft = SHRT_MAX;
2156     nMaxRight = SHRT_MIN;
2157 
2158     /*
2159     #101175#
2160     If we are an honestly inline centered table, then the normal rules of
2161     engagement for left and right margins do not apply. The multiple rows are
2162     centered regardless of the actual placement of rows, so we cannot have
2163     mismatched rows as is possible in other configurations.
2164 
2165     e.g. change the example bugdoc in word from text wrapping of none (inline)
2166     to around (in frame (bApo)) and the table splits into two very disjoint
2167     rows as the beginning point of each row are very different
2168     */
2169     if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER))
2170     {
2171         for (pR = pFirstBand; pR; pR = pR->pNextBand)
2172             for( short i = pR->nWwCols; i >= 0; --i)
2173                 pR->nCenter[i] = pR->nCenter[i] -  pR->nCenter[0];
2174     }
2175 
2176     // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2177     for( pR = pFirstBand; pR; pR = pR->pNextBand )
2178     {
2179         if( pR->nCenter[0] < nMinLeft )
2180             nMinLeft = pR->nCenter[0];
2181 
2182         for( short i = 0; i < pR->nWwCols; i++ )
2183         {
2184            /*
2185             #74387# If the margins are so large as to make the displayable
2186             area inside them smaller than the minimum allowed then adjust the
2187             width to fit. But only do it if the two cells are not the exact
2188             same value, if they are then the cell does not really exist and will
2189             be blended together into the same cell through the use of the
2190             nTrans(late) array.
2191             #i28333# If the nGapHalf is greater than the cell width best to ignore it
2192             */
2193             int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2194             if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2195             {
2196                 pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
2197             }
2198         }
2199 
2200         if( pR->nCenter[pR->nWwCols] > nMaxRight )
2201             nMaxRight = pR->nCenter[pR->nWwCols];
2202     }
2203     nSwWidth = nMaxRight - nMinLeft;
2204 
2205     // #109830# If the table is right aligned we need to align all rows to the
2206     // row that has the furthest right point
2207 
2208     if(eOri == text::HoriOrientation::RIGHT)
2209     {
2210         for( pR = pFirstBand; pR; pR = pR->pNextBand )
2211         {
2212             int adjust = nMaxRight - pR->nCenter[pR->nWwCols];
2213             for( short i = 0; i < pR->nWwCols + 1; i++ )
2214             {
2215                 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2216             }
2217 
2218         }
2219     }
2220 
2221     // 2. Durchlauf: Zahl der Writer-Spalten feststellen Die Zahl der Writer
2222     // Spalten kann um bis zu 2 hoeher sein als im WW, da der SW im Gegensatz
2223     // zu WW keine ausgefransten linken und rechten Raender kann und diese
2224     // durch leere Boxen aufgefuellt werden.  Durch nichtexistente Zellen
2225     // koennen auch Zellen wegfallen
2226 
2227         // 3. Durchlauf: Wo noetig die Umrandungen durch die Defaults ersetzen
2228     nConvertedLeft = nMinLeft;
2229 
2230     short nLeftMaxThickness = 0, nRightMaxThickness=0;
2231     for( pR = pFirstBand ; pR; pR = pR->pNextBand )
2232     {
2233         if( !pR->pTCs )
2234         {
2235             pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2236             memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) );
2237         }
2238         for (int k = 0; k < pR->nWwCols; ++k)
2239         {
2240             WW8_TCell* pT = &pR->pTCs[k];
2241             int i, j;
2242             for( i = 0; i < 4; i ++ )
2243             {
2244                 if (pT->rgbrc[i].IsZeroed(pIo->bVer67))
2245                 {
2246                     // if shadow is set, its invalid
2247                     j = i;
2248                     switch( i )
2249                     {
2250                     case 0:
2251                         // Aussen oben  / Innen waagerecht
2252                         j = (pR == pFirstBand) ? 0 : 4;
2253                         break;
2254                     case 1:
2255                         // Aussen links / Innen senkrecht
2256                         j = k ? 5 : 1;
2257                         break;
2258                     case 2:
2259                         // Aussen unten / Innen waagerecht
2260                         j = pR->pNextBand ? 4 : 2;
2261                         break;
2262                     case 3:
2263                         // Aussen rechts/ Innen senkrecht
2264                         j = (k == pR->nWwCols - 1) ? 3 : 5;
2265                         break;
2266                     }
2267                     // mangel mit Defaults ueber
2268                     pT->rgbrc[i] = pR->aDefBrcs[j];
2269                 }
2270             }
2271         }
2272         /*
2273         Similiar to graphics and other elements word does not totally
2274         factor the width of the border into its calculations of size, we
2275         do so we must adjust out widths and other dimensions to fit.  It
2276         appears that what occurs is that the last cell's right margin if
2277         the margin width that is not calculated into winwords table
2278         dimensions, so in that case increase the table to include the
2279         extra width of the right margin.
2280         */
2281         if ( pIo->bVer67 ?
2282          !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20)
2283        : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000))
2284         {
2285             short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2286                 DetermineBorderProperties(pIo->bVer67);
2287             pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2288             if (nThickness > nRightMaxThickness)
2289                 nRightMaxThickness = nThickness;
2290         }
2291 
2292         /*
2293         The left space of the table is in nMinLeft, but again this
2294         does not consider the margin thickness to its left in the
2295         placement value, so get the thickness of the left border,
2296         half is placed to the left of the nominal left side, and
2297         half to the right.
2298         */
2299         if ( pIo->bVer67 ?
2300               !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20)
2301             : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000))
2302         {
2303             short nThickness = pR->pTCs[0].rgbrc[1].
2304                 DetermineBorderProperties(pIo->bVer67);
2305             if (nThickness > nLeftMaxThickness)
2306                 nLeftMaxThickness = nThickness;
2307         }
2308     }
2309     nSwWidth = nSwWidth + nRightMaxThickness;
2310     nMaxRight = nMaxRight + nRightMaxThickness;
2311     nConvertedLeft = nMinLeft-(nLeftMaxThickness/2);
2312 
2313     for( pR = pFirstBand; pR; pR = pR->pNextBand )
2314     {
2315         pR->nSwCols = pR->nWwCols;
2316         pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY;
2317         pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2318 
2319         short nAddCols = pR->bLEmptyCol + pR->bREmptyCol;
2320         sal_uInt16 i;
2321         sal_uInt16 j = ( pR->bLEmptyCol ) ? 1 : 0;
2322         for (i = 0; i < pR->nWwCols; ++i)
2323         {
2324             pR->nTransCell[i] = (sal_Int8)j;
2325             if ( pR->nCenter[i] < pR->nCenter[i+1] )
2326             {
2327                 pR->bExist[i] = true;
2328                 j++;
2329             }
2330             else
2331             {
2332                 pR->bExist[i] = false;
2333                 nAddCols--;
2334             }
2335         }
2336 
2337         ASSERT(i,"no columns in row ?");
2338 
2339         /*
2340         #96345#
2341         If the last cell was "false" then there is no valid cell following it,
2342         so the default mapping forward wont't work. So map it (and
2343         contigious invalid cells backwards to the last valid cell instead.
2344         */
2345         if (i && pR->bExist[i-1] == false)
2346         {
2347             sal_uInt16 k=i-1;
2348             while (k && pR->bExist[k] == false)
2349                 k--;
2350             for (sal_uInt16 n=k+1;n<i;n++)
2351                 pR->nTransCell[n] = pR->nTransCell[k];
2352         }
2353 
2354         pR->nTransCell[i++] = (sal_Int8)(j++);  // Wird u.a. wegen bREmptyCol um
2355         pR->nTransCell[i] = (sal_Int8)j;        // max. 2 ueberindiziert
2356 
2357         pR->nSwCols = pR->nSwCols + nAddCols;
2358         if( pR->nSwCols < nMinCols )
2359             nMinCols = pR->nSwCols;
2360     }
2361 
2362     /*
2363     #i9718#
2364     Find the largest of the borders on cells that adjoin top bottom and remove
2365     the val from the top and put in on the bottom cell. I can't seem to make
2366     disjoint upper and lowers to see what happens there.
2367     */
2368 
2369     /* #i29550# FME 2004-06-02 Removed this code because of the implementation
2370        of the collapsing table borders model. So this should not be necessary
2371        anymore. */
2372 
2373     /*    for (pR = pFirstBand; pR; pR = pR->pNextBand)
2374     {
2375         WW8TabBandDesc *pNext = pR->pNextBand;
2376         if (!pNext)
2377             break;
2378 
2379         for (int k = 0; k < pR->nWwCols; ++k)
2380         {
2381             WW8_BRC &rAbove = pR->pTCs[k].rgbrc[WW8_BOT];
2382             short nAboveThick = rAbove.IsEmpty(pIo->bVer67) ?
2383                 0 : rAbove.DetermineBorderProperties(pIo->bVer67);
2384             short nUpperLeft = pR->nCenter[k];
2385             short nUpperRight = pR->nCenter[k+1];
2386 
2387             for (int l = 0; l < pNext->nWwCols; ++l)
2388             {
2389                 short nLowerLeft = pNext->nCenter[l];
2390                 short nLowerRight = pNext->nCenter[l+1];
2391 
2392                 if ((nLowerLeft < nUpperLeft) || (nLowerRight > nUpperRight))
2393                     continue;
2394 
2395                 WW8_BRC &rBelow = pNext->pTCs[l].rgbrc[WW8_TOP];
2396                 short nBelowThick = rBelow.IsEmpty(pIo->bVer67) ?
2397                     0 : rBelow.DetermineBorderProperties(pIo->bVer67);
2398                 if (nAboveThick > nBelowThick)
2399                     rBelow = rAbove;
2400             }
2401 
2402             rAbove = WW8_BRC();
2403         }
2404     } */
2405 
2406     if ((nMinLeft && !bIsBiDi && text::HoriOrientation::LEFT == eOri) ||
2407         (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used
2408         eOri = text::HoriOrientation::LEFT_AND_WIDTH; //  absolutely positioned
2409 
2410     nDefaultSwCols = nMinCols;  // da Zellen einfuegen billiger ist als Mergen
2411     if( nDefaultSwCols == 0 )
2412         bOk = false;
2413     pActBand = pFirstBand;
2414     nAktBandRow = 0;
2415     ASSERT( pActBand, "pActBand ist 0" );
2416 }
2417 
SetSizePosition(SwFrmFmt * pFrmFmt)2418 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt)
2419 {
2420     SwFrmFmt* pApply = pFrmFmt;
2421     if (!pApply )
2422         pApply = pTable->GetFrmFmt();
2423     ASSERT(pApply,"No frame");
2424     pApply->SetFmtAttr(aItemSet);
2425     if (pFrmFmt)
2426     {
2427         SwFmtFrmSize aSize = pFrmFmt->GetFrmSize();
2428         aSize.SetHeightSizeType(ATT_MIN_SIZE);
2429         aSize.SetHeight(MINLAY);
2430         pFrmFmt->SetFmtAttr(aSize);
2431         pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL));
2432     }
2433 }
2434 
PrependedInlineNode(const SwPosition & rPos,const SwNode & rNode)2435 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2436     const SwNode &rNode)
2437 {
2438     ASSERT(!maSegments.empty(),
2439         "should not be possible, must be at least one segment");
2440     if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2441         maSegments.back().maStart = SwNodeIndex(rNode);
2442 }
2443 
CreateSwTable()2444 void WW8TabDesc::CreateSwTable()
2445 {
2446     ::SetProgressState(pIo->nProgress, pIo->mpDocShell);   // Update
2447 
2448     // if there is already some content on the Node append new node to ensure
2449     // that this content remains ABOVE the table
2450     SwPosition* pPoint = pIo->pPaM->GetPoint();
2451     bool bInsNode = pPoint->nContent.GetIndex() ? true : false;
2452     bool bSetMinHeight = false;
2453 
2454     /*
2455      #i8062#
2456      Set fly anchor to its anchor pos, so that if a table starts immediately
2457      at this position a new node will be inserted before inserting the table.
2458     */
2459     if (!bInsNode && pIo->pFmtOfJustInsertedApo)
2460     {
2461         const SwPosition* pAPos =
2462             pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor();
2463         if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2464         {
2465             bInsNode = true;
2466             bSetMinHeight = true;
2467 
2468             SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround());
2469             aSur.SetAnchorOnly(true);
2470             pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur);
2471         }
2472     }
2473 
2474     if (bSetMinHeight == true)
2475     {
2476         // minimize Fontsize to minimize height growth of the header/footer
2477         // set font size to 1 point to minimize y-growth of Hd/Ft
2478         SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2479         pIo->NewAttr( aSz );
2480         pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2481     }
2482 
2483     if (bInsNode)
2484         pIo->AppendTxtNode(*pPoint);
2485 
2486     pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() );
2487 
2488     // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist
2489     // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen
2490     // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender,
2491     // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen
2492     pTable = pIo->rDoc.InsertTable(
2493             SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2494             *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, sal_False, sal_True );
2495 
2496     ASSERT(pTable && pTable->GetFrmFmt(), "insert table failed");
2497     if (!pTable || !pTable->GetFrmFmt())
2498         return;
2499 
2500     SwTableNode* pTableNode = pTable->GetTableNode();
2501     ASSERT(pTableNode, "no table node!");
2502     if (pTableNode)
2503     {
2504         pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(),
2505             *pTableNode);
2506     }
2507 
2508     // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits
2509     // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile
2510     // hinter der Tabelle rutschen, wo er nichts zu suchen hat.  -> loeschen
2511     // und spaeter an das Tabellenformat setzen
2512     if (SwTxtNode *const pNd = pTmpPos->nNode.GetNode().GetTxtNode())
2513     {
2514         if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2515         {
2516             SfxPoolItem *pSetAttr = 0;
2517             const SfxPoolItem* pItem;
2518             if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2519             {
2520                 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem );
2521                 pNd->ResetAttr( RES_BREAK );
2522             }
2523 
2524             // evtl den PageDesc/Break jetzt an der Tabelle setzen
2525             if (pSetAttr)
2526             {
2527                 aItemSet.Put(*pSetAttr);
2528                 delete pSetAttr;
2529             }
2530         }
2531     }
2532 
2533     // Gesamtbreite der Tabelle
2534     if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2535     {
2536         pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2537         aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2538     }
2539 
2540     SvxFrameDirectionItem aDirection(
2541         bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2542     pTable->GetFrmFmt()->SetFmtAttr(aDirection);
2543 
2544     if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2545     {
2546         if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt &&
2547             GetMinLeft())
2548         {
2549             //If we are inside a frame and we have a border, the frames
2550             //placement does not consider the tables border, which word
2551             //displays outside the frame, so adjust here.
2552             SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient());
2553             sal_Int16 eHori = aHori.GetHoriOrient();
2554             if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2555                 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2556             {
2557                 //With multiple table, use last table settings. Perhaps
2558                 //the maximum is what word does ?
2559                 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft());
2560                 aHori.SetHoriOrient(text::HoriOrientation::NONE);
2561                 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori);
2562             }
2563         }
2564         else
2565         {
2566             //If bApo is set, then this table is being placed in a floating
2567             //frame, and the frame matches the left and right *lines* of the
2568             //table, so the space to the left of the table isn't to be used
2569             //inside the frame, in word the dialog involved greys out the
2570             //ability to set the margin.
2571             SvxLRSpaceItem aL( RES_LR_SPACE );
2572             // set right to original DxaLeft (i28656)
2573 
2574             long nLeft = 0;
2575             if (!bIsBiDi)
2576                 nLeft = GetMinLeft();
2577             else
2578             {
2579                 if (nPreferredWidth)
2580                 {
2581                     nLeft = pIo->maSectionManager.GetTextAreaWidth();
2582                     nLeft = nLeft - nPreferredWidth  - nOrgDxaLeft;
2583                 }
2584                 else
2585                     nLeft = -GetMinLeft();
2586             }
2587 
2588             aL.SetLeft(nLeft);
2589 
2590             aItemSet.Put(aL);
2591         }
2592     }
2593 
2594     mpOldRedlineStack = pIo->mpRedlineStack;
2595     pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc);
2596 }
2597 
UseSwTable()2598 void WW8TabDesc::UseSwTable()
2599 {
2600     // globale Varis initialisieren
2601     pTabLines = &pTable->GetTabLines();
2602     nAktRow = nAktCol = nAktBandRow = 0;
2603 
2604     pTblNd  = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]->
2605         GetSttNd()->FindTableNode();
2606     ASSERT( pTblNd, "wo ist mein TabellenNode" );
2607 
2608     // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value
2609     if ( nRowsToRepeat == static_cast<sal_uInt16>(nRows) )
2610         nRowsToRepeat = 1;
2611     // <--
2612 
2613     pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2614     // ggfs. Zusatz-Zellen einfuegen u.dgl.
2615     AdjustNewBand();
2616 
2617     WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2618     pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false);
2619 
2620     // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten...
2621     SetPamInCell(nAktCol, true);
2622     aDup.Insert(*pIo->pPaM->GetPoint());
2623 
2624     pIo->bWasTabRowEnd = false;
2625     pIo->bWasTabCellEnd = false;
2626 }
2627 
MergeCells()2628 void WW8TabDesc::MergeCells()
2629 {
2630     short nRow;
2631 
2632     for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2633     {
2634         //
2635         // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen
2636         //
2637         if( pActBand->pTCs )
2638         {
2639             for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2640                 for( short i = 0; i < pActBand->nWwCols; i++ )
2641                 {
2642                     WW8SelBoxInfoPtr pActMGroup = 0;
2643                     //
2644                     // ggfs. eine neue Merge-Gruppe beginnen
2645                     //
2646                     ASSERT(nRow < pTabLines->Count(),
2647                         "Too few lines, table ended early");
2648                     if (nRow >= pTabLines->Count())
2649                         return;
2650                     pTabLine = (*pTabLines)[ nRow ];
2651                     pTabBoxes = &pTabLine->GetTabBoxes();
2652 
2653                     sal_uInt16 nCol = pActBand->nTransCell[ i ];
2654                     if (!pActBand->bExist[i])    //#113434#
2655                         continue;
2656                     ASSERT(nCol < pTabBoxes->Count(),
2657                         "Too few columns, table ended early");
2658                     if (nCol >= pTabBoxes->Count())
2659                         return;
2660                     pTabBox = (*pTabBoxes)[nCol];
2661                     WW8_TCell& rCell = pActBand->pTCs[ i ];
2662                     // ist dies die obere, linke-Zelle einer Merge-Gruppe ?
2663 
2664                     bool bMerge = false;
2665                     if ( rCell.bVertRestart && !rCell.bMerged )
2666                         bMerge = true;
2667                     else if (rCell.bFirstMerged && pActBand->bExist[i])
2668                     {
2669                         //#91211# Some tests to avoid merging cells
2670                         //which previously were declared invalid because
2671                         //of sharing the exact same dimensions as their
2672                         //previous cell
2673 
2674                         //If theres anything underneath/above we're ok.
2675                         if (rCell.bVertMerge || rCell.bVertRestart)
2676                             bMerge = true;
2677                         else
2678                         {
2679                         //If its a hori merge only, and the only things in
2680                         //it are invalid cells then its already taken care
2681                         //of, so don't merge.
2682                             for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2683                                 if (pActBand->pTCs[ i2 ].bMerged &&
2684                                     !pActBand->pTCs[ i2 ].bFirstMerged  )
2685                                 {
2686                                     if (pActBand->bExist[i2])
2687                                     {
2688                                         bMerge = true;
2689                                         break;
2690                                     }
2691                                 }
2692                                 else
2693                                     break;
2694                         }
2695                     }
2696 
2697 
2698                     if (bMerge)
2699                     {
2700                         short nX1    = pActBand->nCenter[ i ];
2701                         short nWidth = pActBand->nWidth[ i ];
2702 
2703                         // 0. falls noetig das Array fuer die Merge-Gruppen
2704                         // anlegen
2705                         if( !pMergeGroups )
2706                             pMergeGroups = new WW8MergeGroups;
2707 
2708                         // 2. aktuelle Merge-Gruppe anlegen
2709                         pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2710 
2711                         // --> OD 2005-02-04 #118544# - determine size of new
2712                         // merge group before inserted the new merge group.
2713                         // Needed to correctly locked previously created merge groups.
2714                         // Gesamtbreite ermitteln und zuweisen
2715                         short nSizCell = pActBand->nWidth[ i ];
2716                         for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2717                             if (pActBand->pTCs[ i2 ].bMerged &&
2718                                 !pActBand->pTCs[ i2 ].bFirstMerged  )
2719                             {
2720                                 nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2721                             }
2722                             else
2723                                 break;
2724                         pActMGroup->nGroupWidth = nSizCell;
2725                         // <--
2726 
2727                         // --> OD 2005-02-03 #118544# - locked previously
2728                         // created merge groups, after determining the size
2729                         // for the new merge group.
2730                         // 1. ggfs. alte Mergegruppe(n) schliessen, die
2731                         // den von unserer neuen Gruppe betroffenen
2732                         // X-Bereich ueberdecken
2733                         short nMGrIdx;
2734                         while ( FindMergeGroup( nX1, pActMGroup->nGroupWidth,
2735                                                 false, nMGrIdx ) )
2736                         {
2737                             (*pMergeGroups)[ nMGrIdx ]->bGroupLocked = true;
2738                         }
2739                         // <--
2740 
2741                         // 3. und in Gruppen-Array eintragen
2742                         pMergeGroups->Insert(pActMGroup, pMergeGroups->Count());
2743                     }
2744 
2745                     // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies
2746                     // kann eine soeben angelegte, oder eine andere Gruppe
2747                     // sein)
2748                     UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2749                 }
2750             }
2751     }
2752 }
2753 
2754 //There is a limbo area in word at the end of the row marker
2755 //where properties can live in word, there is no location in
2756 //writer equivalent, so try and park the cursor in the best
2757 //match, see #i23022#/#i18644#
ParkPaM()2758 void WW8TabDesc::ParkPaM()
2759 {
2760     SwTableBox *pTabBox2 = 0;
2761     short nRow = nAktRow + 1;
2762     if (nRow < pTabLines->Count())
2763     {
2764         if (SwTableLine *pLine = (*pTabLines)[nRow])
2765         {
2766             SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2767             pTabBox2 = rBoxes.Count() ? rBoxes[0] : 0;
2768         }
2769     }
2770 
2771     if (!pTabBox2 || !pTabBox2->GetSttNd())
2772     {
2773         MoveOutsideTable();
2774         return;
2775     }
2776 
2777     if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1)
2778     {
2779         pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1;
2780         pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2781         pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2782     }
2783 }
2784 
MoveOutsideTable()2785 void WW8TabDesc::MoveOutsideTable()
2786 {
2787     ASSERT(pTmpPos && pIo, "I've forgotten where the table is anchored");
2788     if (pTmpPos && pIo)
2789         *pIo->pPaM->GetPoint() = *pTmpPos;
2790 }
2791 
FinishSwTable()2792 void WW8TabDesc::FinishSwTable()
2793 {
2794     pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint());
2795     delete pIo->mpRedlineStack;
2796     pIo->mpRedlineStack = mpOldRedlineStack;
2797     mpOldRedlineStack = 0;
2798 
2799     WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2800     pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false);
2801 
2802     MoveOutsideTable();
2803     delete pTmpPos, pTmpPos = 0;
2804 
2805     aDup.Insert(*pIo->pPaM->GetPoint());
2806 
2807     pIo->bWasTabRowEnd = false;
2808     pIo->bWasTabCellEnd = false;
2809 
2810     pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM);
2811 
2812     MergeCells();
2813 
2814     // falls noetig, zu mergende Zellen gruppenweise zusammenfassen
2815     if( pMergeGroups )
2816     {
2817         // bearbeite alle Merge-Gruppen nacheinander
2818         WW8SelBoxInfo* pActMGroup;
2819         sal_uInt16         nActBoxCount;
2820 
2821 		for (sal_uInt16 iGr = 0; iGr < pMergeGroups->Count(); ++iGr)
2822         {
2823             pActMGroup   = (*pMergeGroups)[ iGr ];
2824             nActBoxCount = pActMGroup->Count();
2825 
2826             if( ( 1 < nActBoxCount ) && pActMGroup && (*pActMGroup)[ 0 ] )
2827 			{
2828 				const sal_uInt16 nRowSpan = pActMGroup->Count();
2829 				for (sal_uInt16 n = 0; n < nRowSpan; ++n)
2830 				{
2831                     SwTableBox* pCurrentBox = (*pActMGroup)[n];
2832 					const long nRowSpanSet = n == 0 ?
2833 									  		 nRowSpan :
2834 											 ((-1) * (nRowSpan - n));
2835 					pCurrentBox->setRowSpan( nRowSpanSet );
2836 				}
2837             }
2838         }
2839         pIo->pFmtOfJustInsertedApo = 0;
2840         DELETEZ( pMergeGroups );
2841     }
2842 }
2843 
2844 
2845 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1
2846 //
2847 // Parameter: nXcenter  = Mittenposition der anfragenden Box
2848 //            nWidth    = Breite der anfragenden Box
2849 //            bExact    = Flag, ob Box in dieser Gruppe passen muss,
2850 //                          oder diese nur zu tangieren braucht
2851 //
FindMergeGroup(short nX1,short nWidth,bool bExact,short & nMGrIdx)2852 bool WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact,
2853     short& nMGrIdx)
2854 {
2855     nMGrIdx = -1;
2856     if( pMergeGroups )
2857     {
2858         // noch als gueltig angesehener Bereich in der Naehe der Grenzen
2859         const short nToleranz = 4;
2860         // die aktuell untersuchte Gruppe
2861         WW8SelBoxInfoPtr pActGroup;
2862         // Boxgrenzen
2863         short nX2 = nX1 + nWidth;
2864         // ungefaehre Gruppengrenzen
2865         short nGrX1;
2866         short nGrX2;
2867 
2868         // --> OD 2005-02-04 #118544# - improvement: search backwards
2869         //for ( sal_uInt16 iGr = 0; iGr < pMergeGroups->Count(); iGr++ )
2870         for ( short iGr = pMergeGroups->Count() - 1; iGr >= 0; --iGr )
2871         {
2872             // die aktuell untersuchte Gruppe
2873             pActGroup = (*pMergeGroups)[ iGr ];
2874             if (!pActGroup->bGroupLocked)
2875             {
2876                 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin
2877                 nGrX1 = pActGroup->nGroupXStart - nToleranz;
2878                 nGrX2 = pActGroup->nGroupXStart
2879                              +pActGroup->nGroupWidth  + nToleranz;
2880                 //
2881                 // Falls Box reinpasst, melde auf jeden Fall den Erfolg
2882                 //
2883                 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2884                 {
2885                     nMGrIdx = iGr;  break;
2886                 }
2887                 //
2888                 // hat die Box Bereiche mit der Gruppe gemeinsam?
2889                 //
2890                 if( !bExact )
2891                 {
2892                     // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen
2893                     if(    (     ( nX1 > nGrX1 )
2894                                         && ( nX1 < nGrX2 - 2*nToleranz ) )
2895                             || (     ( nX2 > nGrX1 + 2*nToleranz )
2896                                         && ( nX2 < nGrX2 ) )
2897                             // oder nX1 und nX2 die Gruppe umfassen
2898                             || (     ( nX1 <=nGrX1 )
2899                                         && ( nX2 >=nGrX2 ) ) )
2900                     {
2901                         nMGrIdx = iGr;  break;
2902                     }
2903                 }
2904             }
2905         }
2906     }
2907     return ( -1 < nMGrIdx );
2908 }
2909 
IsValidCell(short nCol) const2910 bool WW8TabDesc::IsValidCell(short nCol) const
2911 {
2912     return pActBand->bExist[nCol] && (sal_uInt16)nAktRow < pTabLines->Count();
2913 }
2914 
InFirstParaInCell() const2915 bool WW8TabDesc::InFirstParaInCell() const
2916 {
2917     //e.g. #i19718#
2918     if (!pTabBox || !pTabBox->GetSttNd())
2919     {
2920         ASSERT(false, "Problem with table");
2921         return false;
2922     }
2923 
2924     if (!IsValidCell(GetAktCol()))
2925         return false;
2926 
2927     if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2928         return true;
2929 
2930     return false;
2931 }
2932 
StartMiserableHackForUnsupportedDirection(short nWwCol)2933 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2934 {
2935     ASSERT(pActBand, "Impossible");
2936     if (pActBand && pActBand->maDirections[nWwCol] == 3)
2937     {
2938         pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(),
2939             SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2940     }
2941 }
2942 
EndMiserableHackForUnsupportedDirection(short nWwCol)2943 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2944 {
2945     ASSERT(pActBand, "Impossible");
2946     if (pActBand && pActBand->maDirections[nWwCol] == 3)
2947         pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE);
2948 }
2949 
SetPamInCell(short nWwCol,bool bPam)2950 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2951 {
2952     ASSERT( pActBand, "pActBand ist 0" );
2953 
2954     sal_uInt16 nCol = pActBand->nTransCell[nWwCol];
2955 
2956     if ((sal_uInt16)nAktRow >= pTabLines->Count())
2957     {
2958         ASSERT(!this, "Actual row bigger than expected." );
2959         if (bPam)
2960             MoveOutsideTable();
2961         return false;
2962     }
2963 
2964     pTabLine = (*pTabLines)[nAktRow];
2965     pTabBoxes = &pTabLine->GetTabBoxes();
2966 
2967     if (nCol >= pTabBoxes->Count())
2968     {
2969         if (bPam)
2970         {
2971             // The first paragraph in a cell with upper autospacing has upper
2972             // spacing set to 0
2973             if (
2974                  pIo->bParaAutoBefore && pIo->bFirstPara &&
2975                  !pIo->pWDop->fDontUseHTMLAutoSpacing
2976                )
2977             {
2978                 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2979             }
2980 
2981             // The last paragraph in a cell with lower autospacing has lower
2982             // spacing set to 0
2983             if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2984                 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2985 
2986             ParkPaM();
2987         }
2988         return false;
2989     }
2990     pTabBox = (*pTabBoxes)[nCol];
2991     if( !pTabBox->GetSttNd() )
2992     {
2993         ASSERT(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2994         if (bPam)
2995             MoveOutsideTable();
2996         return false;
2997     }
2998     if (bPam)
2999     {
3000         pAktWWCell = &pActBand->pTCs[ nWwCol ];
3001 
3002        // The first paragraph in a cell with upper autospacing has upper spacing set to 0
3003         if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing)
3004             pIo->SetUpperSpacing(*pIo->pPaM, 0);
3005 
3006         // The last paragraph in a cell with lower autospacing has lower spacing set to 0
3007         if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
3008             pIo->SetLowerSpacing(*pIo->pPaM, 0);
3009 
3010         //We need to set the pPaM on the first cell, invalid
3011         //or not so that we can collect paragraph proproties over
3012         //all the cells, but in that case on the valid cell we do not
3013         //want to reset the fmt properties
3014         if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1)
3015         {
3016             pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1;
3017             pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3018             // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die
3019             // zum Randausgleich eingefuegt werden, sonst der Style
3020             // nicht gesetzt wird.
3021             pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
3022             // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind,
3023             //            und nur dazu dienen, zerfranste Aussehen der WW-Tabelle
3024             //            nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel()
3025             //            verwendet zu werden.
3026         }
3027 
3028         // Better to turn Snap to Grid off for all paragraphs in tables
3029         if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode())
3030         {
3031             const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID);
3032             SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm);
3033 
3034             if(rSnapToGrid.GetValue())
3035             {
3036                 SvxParaGridItem aGridItem( rSnapToGrid );
3037                 aGridItem.SetValue(false);
3038 
3039                 SwPosition* pGridPos = pIo->pPaM->GetPoint();
3040 
3041                 xub_StrLen nEnd = pGridPos->nContent.GetIndex();
3042                 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3043                 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem);
3044                 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd);
3045                 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
3046             }
3047         }
3048 
3049         StartMiserableHackForUnsupportedDirection(nWwCol);
3050     }
3051     return true;
3052 }
3053 
InsertCells(short nIns)3054 void WW8TabDesc::InsertCells( short nIns )
3055 {
3056     pTabLine = (*pTabLines)[nAktRow];
3057     pTabBoxes = &pTabLine->GetTabBoxes();
3058     pTabBox = (*pTabBoxes)[0];
3059 
3060     pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(),
3061                             (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->Count(), nIns );
3062     // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben.
3063     // hier kann man auch noch optimieren, um FrmFmts zu sparen
3064 }
3065 
SetTabBorders(SwTableBox * pBox,short nWwIdx)3066 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3067 {
3068     if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3069         return;                 // kuenstlich erzeugte Zellen -> Kein Rand
3070 
3071 
3072     SvxBoxItem aFmtBox( RES_BOX );
3073     if (pActBand->pTCs)     // neither Cell Border nor Default Border defined ?
3074     {
3075         WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3076         if (pIo->IsBorder(pT->rgbrc))
3077             pIo->SetBorder(aFmtBox, pT->rgbrc);
3078     }
3079 
3080     if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
3081     {
3082         aFmtBox.SetDistance(
3083             pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
3084             BOX_LINE_TOP);
3085     }
3086     else
3087         aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP);
3088     if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
3089     {
3090         aFmtBox.SetDistance(
3091             pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
3092             BOX_LINE_BOTTOM);
3093     }
3094     else
3095         aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM);
3096 
3097     // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen
3098     // Tabellenzelle und -Inhalt
3099     short nLeftDist =
3100         pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
3101     short nRightDist =
3102         pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
3103     if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
3104     {
3105         aFmtBox.SetDistance(
3106             pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
3107             BOX_LINE_LEFT);
3108     }
3109     else
3110         aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT);
3111     if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
3112     {
3113         aFmtBox.SetDistance(
3114             pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
3115             BOX_LINE_RIGHT);
3116     }
3117     else
3118         aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT);
3119 
3120     pBox->GetFrmFmt()->SetFmtAttr(aFmtBox);
3121 }
3122 
SetTabShades(SwTableBox * pBox,short nWwIdx)3123 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3124 {
3125     if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3126         return;                 // kuenstlich erzeugte Zellen -> Keine Farbe
3127 
3128     bool bFound=false;
3129     if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3130     {
3131         Color aColor(pActBand->pNewSHDs[nWwIdx]);
3132         if (aColor.GetColor() == 0x00333333)
3133             pIo->maTracer.Log(sw::log::eAutoColorBg);
3134         pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND));
3135         bFound = true;
3136     }
3137 
3138     //If there was no new shades, or no new shade setting
3139     if (pActBand->pSHDs && !bFound)
3140     {
3141         WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3142         if (!rSHD.GetValue())       // auto
3143             return;
3144 
3145         SwWW8Shade aSh( pIo->bVer67, rSHD );
3146         pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3147     }
3148 }
3149 
MakeDirection(sal_uInt16 nCode,sal_Bool bIsBiDi)3150 SvxFrameDirection MakeDirection(sal_uInt16 nCode, sal_Bool bIsBiDi)
3151 {
3152     SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3153     // 1: Asian layout with rotated CJK characters
3154     // 5: Asian layout
3155     // 3: Western layout rotated by 90 degrees
3156     // 4: Western layout
3157     switch (nCode)
3158     {
3159         default:
3160             ASSERT(eDir == 4, "unknown direction code, maybe its a bitfield");
3161         case 3:
3162             // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3163             eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3164             // <--
3165             break;
3166         case 5:
3167             eDir = FRMDIR_VERT_TOP_RIGHT;
3168             break;
3169         case 1:
3170             eDir = FRMDIR_VERT_TOP_RIGHT;
3171             break;
3172         case 4:
3173             // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3174             eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3175             // <--
3176             break;
3177     }
3178     return eDir;
3179 }
3180 
SetTabDirection(SwTableBox * pBox,short nWwIdx)3181 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3182 {
3183     if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3184         return;
3185     SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3186     pBox->GetFrmFmt()->SetFmtAttr(aItem);
3187 }
3188 
SetTabVertAlign(SwTableBox * pBox,short nWwIdx)3189 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3190 {
3191     if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3192         return;
3193 
3194     sal_Int16 eVertOri=text::VertOrientation::TOP;
3195 
3196     if( pActBand->pTCs )
3197     {
3198         WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3199         switch (pT->nVertAlign)
3200         {
3201             case 0:
3202             default:
3203                 eVertOri = text::VertOrientation::TOP;
3204                 break;
3205             case 1:
3206                 eVertOri = text::VertOrientation::CENTER;
3207                 break;
3208             case 2:
3209                 eVertOri = text::VertOrientation::BOTTOM;
3210                 break;
3211         }
3212     }
3213 
3214     pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) );
3215 }
3216 
AdjustNewBand()3217 void WW8TabDesc::AdjustNewBand()
3218 {
3219     if( pActBand->nSwCols > nDefaultSwCols )        // Zellen splitten
3220         InsertCells( pActBand->nSwCols - nDefaultSwCols );
3221 
3222     SetPamInCell( 0, false);
3223     ASSERT( pTabBoxes && pTabBoxes->Count() == (sal_uInt16)pActBand->nSwCols,
3224         "Falsche Spaltenzahl in Tabelle" )
3225 
3226     if( bClaimLineFmt )
3227     {
3228         pTabLine->ClaimFrmFmt();            // noetig wg. Zeilenhoehe
3229         SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 );  // default
3230 
3231         if (pActBand->nLineHeight == 0)    // 0 = Auto
3232             aF.SetHeightSizeType( ATT_VAR_SIZE );
3233         else
3234         {
3235             if (pActBand->nLineHeight < 0) // Pos = min, Neg = exakt
3236             {
3237                 aF.SetHeightSizeType(ATT_FIX_SIZE);
3238                 pActBand->nLineHeight = -pActBand->nLineHeight;
3239             }
3240             if (pActBand->nLineHeight < MINLAY) // nicht erlaubte Zeilenhoehe
3241                 pActBand->nLineHeight = MINLAY;
3242 
3243             aF.SetHeight(pActBand->nLineHeight);// Min- / Exakt-Hoehe setzen
3244         }
3245         pTabLine->GetFrmFmt()->SetFmtAttr(aF);
3246     }
3247 
3248     //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3249     //we can split the row
3250 	// bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3251 	// So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3252 	// Word versions >= 2002.
3253 	bool bSetCantSplit = pActBand->bCantSplit;
3254 	if(bSetCantSplit)
3255 		bSetCantSplit = pActBand->bCantSplit90;
3256 
3257     pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit));
3258 
3259     short i;    // SW-Index
3260     short j;    // WW-Index
3261     short nW;   // Breite
3262     SwFmtFrmSize aFS( ATT_FIX_SIZE );
3263     j = pActBand->bLEmptyCol ? -1 : 0;
3264 
3265     for( i = 0; i < pActBand->nSwCols; i++ )
3266     {
3267         // setze Zellenbreite
3268         if( j < 0 )
3269             nW = pActBand->nCenter[0] - nMinLeft;
3270         else
3271         {
3272             //Set j to first non invalid cell
3273             while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3274                 j++;
3275 
3276             if( j < pActBand->nWwCols )
3277                 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3278             else
3279                 nW = nMaxRight - pActBand->nCenter[j];
3280             pActBand->nWidth[ j ] = nW;
3281         }
3282 
3283         SwTableBox* pBox = (*pTabBoxes)[i];
3284         // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter
3285         // verringern
3286         pBox->ClaimFrmFmt();
3287 
3288         SetTabBorders(pBox, j);
3289 
3290         // #i18128# word has only one line between adjoining vertical cells
3291         // we have to mimick this in the filter by picking the larger of the
3292         // sides and using that one on one side of the line (right)
3293         SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX));
3294         const SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT);
3295         int nCurrentRightLineWidth = 0;
3296         if(pLeftLine)
3297             nCurrentRightLineWidth = pLeftLine->GetInWidth() + pLeftLine->GetOutWidth() + pLeftLine->GetDistance();
3298 
3299         if (i != 0)
3300         {
3301             SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3302             SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX));
3303             const SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT);
3304             int nOldBoxRightLineWidth = 0;
3305             if(pRightLine)
3306                 nOldBoxRightLineWidth = pRightLine->GetInWidth() + pRightLine->GetOutWidth() + pRightLine->GetDistance();
3307 
3308             if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3309                 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT);
3310 
3311             aOldBox.SetLine(0, BOX_LINE_RIGHT);
3312             pBox2->GetFrmFmt()->SetFmtAttr(aOldBox);
3313         }
3314 
3315         pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox);
3316 
3317         SetTabVertAlign(pBox, j);
3318         SetTabDirection(pBox, j);
3319         if( pActBand->pSHDs || pActBand->pNewSHDs)
3320             SetTabShades(pBox, j);
3321         j++;
3322 
3323         aFS.SetWidth( nW );
3324         pBox->GetFrmFmt()->SetFmtAttr( aFS );
3325 
3326         // ueberspringe nicht existente Zellen
3327         while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3328         {
3329             pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3330             j++;
3331         }
3332     }
3333 }
3334 
TableCellEnd()3335 void WW8TabDesc::TableCellEnd()
3336 {
3337     ::SetProgressState(pIo->nProgress, pIo->mpDocShell);   // Update
3338 
3339     EndMiserableHackForUnsupportedDirection(nAktCol);
3340 
3341     // neue Zeile
3342     if( pIo->bWasTabRowEnd )
3343     {
3344         // bWasTabRowEnd will be deactivated in
3345         // SwWW8ImplReader::ProcessSpecial()
3346 
3347         sal_uInt16 iCol = GetLogicalWWCol();
3348         if (iCol < aNumRuleNames.size())
3349         {
3350             aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3351                 aNumRuleNames.end());
3352         }
3353 
3354         nAktCol = 0;
3355         nAktRow++;
3356         nAktBandRow++;
3357         ASSERT( pActBand , "pActBand ist 0" );
3358         if( pActBand )
3359         {
3360             if( nAktRow >= nRows )  // am Tabellenende gibt's nichts sinnvolles
3361                 return;                 // mehr zu tun
3362 
3363             bool bNewBand = nAktBandRow >= pActBand->nRows;
3364             if( bNewBand )
3365             {                       // neues Band noetig ?
3366                 pActBand = pActBand->pNextBand; //
3367                 nAktBandRow = 0;
3368                 ASSERT( pActBand, "pActBand ist 0" );
3369                 AdjustNewBand();
3370             }
3371             else
3372             {
3373                 SwTableBox* pBox = (*pTabBoxes)[0];
3374                 SwSelBoxes aBoxes;
3375                 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) );
3376             }
3377         }
3378     }
3379     else
3380     {                       // neue Spalte ( Zelle )
3381         nAktCol++;
3382     }
3383     SetPamInCell(nAktCol, true);
3384 
3385     // finish Annotated Level Numbering ?
3386     if (pIo->bAnl && !pIo->bAktAND_fNumberAcross)
3387         pIo->StopAllAnl(IsValidCell(nAktCol));
3388 }
3389 
3390 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen
UpdateTableMergeGroup(WW8_TCell & rCell,WW8SelBoxInfo * pActGroup,SwTableBox * pActBox,sal_uInt16 nCol)3391 SwTableBox* WW8TabDesc::UpdateTableMergeGroup(  WW8_TCell&     rCell,
3392                                                 WW8SelBoxInfo* pActGroup,
3393                                                 SwTableBox*    pActBox,
3394                                                 sal_uInt16         nCol )
3395 {
3396     // Rueckgabewert defaulten
3397     SwTableBox* pResult = 0;
3398 
3399     // pruefen, ob die Box zu mergen ist
3400     // --> OD 2005-02-04 #118544# - If cell is the first one to be merged,
3401     // a new merge group has to be provided.
3402     // E.g., it could be that a cell is the first one to be merged, but no
3403     // new merge group is provided, because the potential other cell to be merged
3404     // doesn't exist - see method <WW8TabDesc::MergeCells>.
3405     if ( pActBand->bExist[ nCol ] &&
3406          ( ( rCell.bFirstMerged && pActGroup ) ||
3407            rCell.bMerged ||
3408            rCell.bVertMerge ||
3409            rCell.bVertRestart ) )
3410     // <--
3411     {
3412         // passende Merge-Gruppe ermitteln
3413         WW8SelBoxInfo* pTheMergeGroup = 0;
3414         if( pActGroup )
3415             // Gruppe uebernehmen
3416             pTheMergeGroup = pActGroup;
3417         else
3418         {
3419             // Gruppe finden
3420             short nMGrIdx;
3421             if( FindMergeGroup( pActBand->nCenter[ nCol ],
3422                                 pActBand->nWidth[  nCol ], true, nMGrIdx ) )
3423                 pTheMergeGroup = (*pMergeGroups)[ nMGrIdx ];
3424         }
3425         if( pTheMergeGroup )
3426         {
3427             // aktuelle Box der Merge-Gruppe hinzufuegen
3428             pTheMergeGroup->Insert( pActBox, pTheMergeGroup->Count() );
3429 
3430             // Target-Box zurueckmelden
3431             pResult = (*pTheMergeGroup)[ 0 ];
3432         }
3433     }
3434     return pResult;
3435 }
3436 
3437 
GetLogicalWWCol() const3438 sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3439 {
3440     sal_uInt16 nCol = 0;
3441     if( pActBand && pActBand->pTCs)
3442     {
3443         for( sal_uInt16 iCol = 1; iCol <= nAktCol; ++iCol )
3444         {
3445             if( !pActBand->pTCs[ iCol-1 ].bMerged )
3446                 ++nCol;
3447         }
3448     }
3449     return nCol;
3450 }
3451 
3452 // find name of numrule valid for current WW-COL
GetNumRuleName() const3453 const String& WW8TabDesc::GetNumRuleName() const
3454 {
3455     sal_uInt16 nCol = GetLogicalWWCol();
3456     if (nCol < aNumRuleNames.size())
3457         return aNumRuleNames[nCol];
3458     else
3459         return aEmptyStr;
3460 }
3461 
SetNumRuleName(const String & rName)3462 void WW8TabDesc::SetNumRuleName( const String& rName )
3463 {
3464     sal_uInt16 nCol = GetLogicalWWCol();
3465     for (sal_uInt16 nSize = static_cast< sal_uInt16 >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3466         aNumRuleNames.push_back(aEmptyStr);
3467     aNumRuleNames[nCol] = rName;
3468 }
3469 
StartTable(WW8_CP nStartCp)3470 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp)
3471 {
3472     // Entering a table so make sure the the FirstPara flag gets set
3473     bFirstPara = true;
3474     // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3475     // Fussnote
3476     if (bReadNoTbl)
3477         return false;
3478 
3479     if (pTableDesc)
3480         maTableStack.push(pTableDesc);
3481 
3482     // --> OD 2005-01-27 #i33818# - determine absolute position object attributes,
3483     // if possible. It's needed for nested tables.
3484     WW8FlyPara* pTableWFlyPara( 0L );
3485     WW8SwFlyPara* pTableSFlyPara( 0L );
3486     // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame
3487     // only at-character, if absolute position object attributes are available.
3488     // Thus, default anchor type is as-character anchored.
3489     RndStdIds eAnchor( FLY_AS_CHAR );
3490     // <--
3491     if ( nInTable )
3492     {
3493         WW8_TablePos* pNestedTabPos( 0L );
3494         WW8_TablePos aNestedTabPos;
3495         WW8PLCFxSave1 aSave;
3496         pPlcxMan->GetPap()->Save( aSave );
3497         WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
3498         WW8_CP nMyStartCp = nStartCp;
3499         if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) &&
3500              ParseTabPos( &aNestedTabPos, pPap ) )
3501         {
3502             pNestedTabPos = &aNestedTabPos;
3503         }
3504         pPlcxMan->GetPap()->Restore( aSave );
3505         if ( pNestedTabPos )
3506         {
3507             ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos );
3508             pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3509             if ( pTableWFlyPara )
3510             {
3511                 // --> OD 2007-07-03 #148498#
3512                 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3513                 // containing WW8 page top margin.
3514                 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara,
3515                     maSectionManager.GetWWPageTopMargin(),
3516                     maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(),
3517                     nIniFlyDx, nIniFlyDy);
3518                 // <--
3519                 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly
3520                 // frame at-character
3521                 eAnchor = FLY_AT_CHAR;
3522                 // <--
3523             }
3524         }
3525     }
3526     // <--
3527 
3528     pTableDesc = new WW8TabDesc( this, nStartCp );
3529 
3530     if( pTableDesc->Ok() )
3531     {
3532         int nNewInTable = nInTable + 1;
3533         if (InEqualApo(nNewInTable))
3534         {
3535             ASSERT(pSFlyPara->pFlyFmt,
3536                 "how could we be in a local apo and have no apo");
3537         }
3538 
3539         if ((eAnchor == FLY_AT_CHAR)
3540             && !maTableStack.empty() && !InEqualApo(nNewInTable) )
3541         {
3542             pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint());
3543             SfxItemSet aItemSet(rDoc.GetAttrPool(),
3544                                 RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3545             // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for
3546             // the nested table at-character.
3547             // --> OD 2005-03-21 #i45301#
3548             SwFmtAnchor aAnchor( eAnchor );
3549             aAnchor.SetAnchor( pTableDesc->pParentPos );
3550             aItemSet.Put( aAnchor );
3551             pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor,
3552                                                       pTableDesc->pParentPos, &aItemSet);
3553             ASSERT( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor,
3554                    "Not the anchor type requested!" );
3555             // <--
3556             MoveInsideFly(pTableDesc->pFlyFmt);
3557         }
3558         pTableDesc->CreateSwTable();
3559         if (pTableDesc->pFlyFmt)
3560         {
3561             pTableDesc->SetSizePosition(pTableDesc->pFlyFmt);
3562             // --> OD 2005-01-26 #i33818# - Use absolute position object
3563             // attributes, if existing, and apply them to the created Writer fly
3564             // frame.
3565             if ( pTableWFlyPara && pTableSFlyPara )
3566             {
3567                 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3568                 SwFmtAnchor aAnchor( FLY_AT_CHAR );
3569                 aAnchor.SetAnchor( pTableDesc->pParentPos );
3570                 aFlySet.Put( aAnchor );
3571                 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet );
3572             }
3573             else
3574             {
3575                 SwFmtHoriOrient aHori =
3576                             pTableDesc->pTable->GetFrmFmt()->GetHoriOrient();
3577                 pTableDesc->pFlyFmt->SetFmtAttr(aHori);
3578                 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) );
3579             }
3580             // <--
3581             // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave
3582             // the table cell. Thus, the Writer fly frame has to follow the text flow.
3583             pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( sal_True ) );
3584             // <--
3585         }
3586         else
3587             pTableDesc->SetSizePosition(0);
3588         pTableDesc->UseSwTable();
3589     }
3590     else
3591         PopTableDesc();
3592 
3593     // --> OD 2005-01-28 #i33818#
3594     delete pTableWFlyPara;
3595     delete pTableSFlyPara;
3596     // <--
3597 
3598     bool bSuccess = (0 != pTableDesc);
3599     if (bSuccess)
3600     {
3601         maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3602             static_cast<sal_Int32>(maTableStack.size())));
3603     }
3604     return bSuccess;
3605 }
3606 
lcl_PamContainsFly(SwPaM & rPam)3607 bool lcl_PamContainsFly(SwPaM & rPam)
3608 {
3609     bool bResult = false;
3610     SwNodeRange aRg( rPam.Start()->nNode, rPam.End()->nNode );
3611     SwDoc * pDoc = rPam.GetDoc();
3612 
3613     sal_uInt16 n = 0;
3614     SwSpzFrmFmts * pSpzFmts = pDoc->GetSpzFrmFmts();
3615     sal_uInt16 nCount = pSpzFmts->Count();
3616     while (!bResult && n < nCount)
3617     {
3618         SwFrmFmt* pFly = (*pSpzFmts)[n];
3619         const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
3620 
3621         switch (pAnchor->GetAnchorId())
3622         {
3623             case FLY_AT_PARA:
3624             case FLY_AT_CHAR:
3625             {
3626                 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
3627 
3628                 if (pAPos != NULL &&
3629                     aRg.aStart <= pAPos->nNode &&
3630                     pAPos->nNode <= aRg.aEnd)
3631                 {
3632                     bResult = true;
3633                 }
3634             }
3635                 break;
3636             default:
3637                 break;
3638         }
3639 
3640         ++n;
3641     }
3642 
3643     return bResult;
3644 }
3645 
TabCellEnd()3646 void SwWW8ImplReader::TabCellEnd()
3647 {
3648     if (nInTable && pTableDesc)
3649     {
3650         pTableDesc->TableCellEnd();
3651 
3652         if (bReadTable
3653             && pWFlyPara == NULL
3654             && mpTableEndPaM.get() != NULL
3655             && (! SwPaM::Overlap(*pPaM, *mpTableEndPaM))
3656             && SwPaM::LessThan(*mpTableEndPaM, *pPaM)
3657             && mpTableEndPaM->GetPoint()->nNode.GetNode().IsTxtNode()
3658             && !lcl_PamContainsFly(*mpTableEndPaM)
3659             )
3660         {
3661             rDoc.DelFullPara(*mpTableEndPaM);
3662         }
3663     }
3664 
3665     bFirstPara = true;    // We have come to the end of a cell so FirstPara flag
3666     bReadTable = false;
3667     mpTableEndPaM.reset();
3668 }
3669 
Read_TabCellEnd(sal_uInt16,const sal_uInt8 * pData,short nLen)3670 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16, const sal_uInt8* pData, short nLen)
3671 {
3672     if( ( nLen > 0 ) && ( *pData == 1 ) )
3673         bWasTabCellEnd = true;
3674 }
3675 
Read_TabRowEnd(sal_uInt16,const sal_uInt8 * pData,short nLen)3676 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16, const sal_uInt8* pData, short nLen )   // Sprm25
3677 {
3678     if( ( nLen > 0 ) && ( *pData == 1 ) )
3679         bWasTabRowEnd = true;
3680 }
3681 
PopTableDesc()3682 void SwWW8ImplReader::PopTableDesc()
3683 {
3684     if (pTableDesc && pTableDesc->pFlyFmt)
3685     {
3686         MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos);
3687     }
3688 
3689     delete pTableDesc;
3690     if (maTableStack.empty())
3691         pTableDesc = 0;
3692     else
3693     {
3694        pTableDesc = maTableStack.top();
3695        maTableStack.pop();
3696     }
3697 }
3698 
StopTable()3699 void SwWW8ImplReader::StopTable()
3700 {
3701     maTracer.LeaveEnvironment(sw::log::eTable);
3702 
3703     ASSERT(pTableDesc, "Panic, stop table with no table!");
3704     if (!pTableDesc)
3705         return;
3706 
3707     // We are leaving a table so make sure the next paragraph doesn't think
3708     // it's the first paragraph
3709     bFirstPara = false;
3710 
3711     pTableDesc->FinishSwTable();
3712     PopTableDesc();
3713 
3714     if (!maTableStack.empty())
3715     {
3716         maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3717             static_cast<sal_Int32>(maTableStack.size())));
3718     }
3719 
3720     bReadTable = true;
3721     // --> OD 2009-04-16 #i101116#
3722     // Keep PaM on table end only for nested tables
3723     if ( nInTable > 1 )
3724     {
3725         mpTableEndPaM.reset(new SwPaM(*pPaM));
3726     }
3727     // <--
3728 }
3729 
3730 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen
3731 // gebraucht.
3732 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle
3733 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand.
GetTableLeft()3734 short SwWW8ImplReader::GetTableLeft()
3735 {
3736     return (pTableDesc) ? pTableDesc->GetMinLeft() : 0;
3737 }
3738 
IsInvalidOrToBeMergedTabCell() const3739 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3740 {
3741     if( !pTableDesc )
3742         return false;
3743 
3744     const WW8_TCell* pCell = pTableDesc->GetAktWWCell();
3745 
3746     return     !pTableDesc->IsValidCell( pTableDesc->GetAktCol() )
3747             || (    pCell
3748                  && (    !pCell->bFirstMerged
3749                       && (    pCell->bMerged
3750                            || (    pCell->bVertMerge
3751                                 && !pCell->bVertRestart
3752                               )
3753                          )
3754                     )
3755                 );
3756 }
3757 
StyleUsingLFO(sal_uInt16 nLFOIndex) const3758 sal_uInt16 SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex ) const
3759 {
3760     sal_uInt16 nRes = USHRT_MAX;
3761     if( pCollA )
3762     {
3763         for(sal_uInt16 nI = 0; nI < pStyles->GetCount(); nI++ )
3764             if(    pCollA[ nI ].bValid
3765                 && (nLFOIndex == pCollA[ nI ].nLFOIndex) )
3766                 nRes = nI;
3767     }
3768     return nRes;
3769 }
3770 
GetStyleWithOrgWWName(String & rName) const3771 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const
3772 {
3773     SwFmt* pRet = 0;
3774     if( pCollA )
3775     {
3776         for(sal_uInt16 nI = 0; nI < pStyles->GetCount(); nI++ )
3777             if(    pCollA[ nI ].bValid
3778                 && (rName.Equals( pCollA[ nI ].GetOrgWWName())) )
3779             {
3780                 pRet = pCollA[ nI ].pFmt;
3781                 break;
3782             }
3783     }
3784     return pRet;
3785 }
3786 
3787 //-----------------------------------------
3788 //          class WW8RStyle
3789 //-----------------------------------------
3790 
HasParaSprm(sal_uInt16 nId) const3791 const sal_uInt8* WW8RStyle::HasParaSprm( sal_uInt16 nId ) const
3792 {
3793     if( !pParaSprms || !nSprmsLen )
3794         return 0;
3795 
3796     const sal_uInt8* pSprms = pParaSprms;
3797     sal_uInt16 i, x;
3798 
3799     for( i=0; i < nSprmsLen; )
3800     {
3801         sal_uInt16 nAktId = maSprmParser.GetSprmId(pSprms);
3802         // Sprm found ?
3803         if( nAktId == nId )
3804             return pSprms + maSprmParser.DistanceToData(nId);
3805 
3806         x = maSprmParser.GetSprmSize(nAktId, pSprms);
3807         i = i + x;
3808         pSprms += x;
3809     }
3810     return 0;                               // Sprm not found
3811 }
3812 
ImportSprms(sal_uInt8 * pSprms,short nLen,bool bPap)3813 void WW8RStyle::ImportSprms(sal_uInt8 *pSprms, short nLen, bool bPap)
3814 {
3815     if (!nLen)
3816         return;
3817 
3818     if( bPap )
3819     {
3820         pParaSprms = pSprms;   // fuer HasParaSprms()
3821         nSprmsLen = nLen;
3822     }
3823 
3824     while ( nLen > 0 )
3825     {
3826         sal_uInt16 nL1 = pIo->ImportSprm(pSprms);
3827         nLen = nLen - nL1;
3828         pSprms += nL1;
3829     }
3830 
3831     pParaSprms = 0;
3832     nSprmsLen = 0;
3833 }
3834 
ImportSprms(sal_Size nPosFc,short nLen,bool bPap)3835 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3836 {
3837     if (!nLen)
3838         return;
3839 
3840     sal_uInt8 *pSprms = new sal_uInt8[nLen];
3841 
3842     pStStrm->Seek(nPosFc);
3843     pStStrm->Read(pSprms, nLen);
3844 
3845     ImportSprms(pSprms, nLen, bPap);
3846 
3847     delete[] pSprms;
3848 }
3849 
WW8SkipOdd(SvStream * pSt)3850 static inline short WW8SkipOdd(SvStream* pSt )
3851 {
3852     if ( pSt->Tell() & 0x1 )
3853     {
3854         sal_uInt8 c;
3855         pSt->Read( &c, 1 );
3856         return 1;
3857     }
3858     return 0;
3859 }
3860 
WW8SkipEven(SvStream * pSt)3861 static inline short WW8SkipEven(SvStream* pSt )
3862 {
3863     if (!(pSt->Tell() & 0x1))
3864     {
3865         sal_uInt8 c;
3866         pSt->Read( &c, 1 );
3867         return 1;
3868     }
3869     return 0;
3870 }
3871 
ImportUPX(short nLen,bool bPAP,bool bOdd)3872 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3873 {
3874     sal_Int16 cbUPX;
3875 
3876     if( 0 < nLen ) // Empty ?
3877     {
3878         if (bOdd)
3879             nLen = nLen - WW8SkipEven( pStStrm );
3880         else
3881             nLen = nLen - WW8SkipOdd( pStStrm );
3882 
3883         *pStStrm >> cbUPX;
3884 
3885         nLen-=2;
3886 
3887         if ( cbUPX > nLen )
3888             cbUPX = nLen;       // !cbUPX auf nLen verkleinert!
3889 
3890         if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3891         {
3892             if( bPAP )
3893             {
3894                 sal_uInt16 id;
3895                 *pStStrm >> id;
3896 
3897                 cbUPX-=  2;
3898                 nLen-=  2;
3899             }
3900 
3901             if( 0 < cbUPX )
3902             {
3903                 sal_Size nPos = pStStrm->Tell(); // falls etwas falsch interpretiert
3904                                                  // wird, gehts danach wieder richtig
3905                 ImportSprms( nPos, cbUPX, bPAP );
3906 
3907                 if ( pStStrm->Tell() != nPos + cbUPX )
3908                     pStStrm->Seek( nPos+cbUPX );
3909 
3910                 nLen = nLen - cbUPX;
3911             }
3912         }
3913     }
3914     return nLen;
3915 }
3916 
ImportGrupx(short nLen,bool bPara,bool bOdd)3917 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3918 {
3919     if( nLen <= 0 )
3920         return;
3921     if (bOdd)
3922         nLen = nLen - WW8SkipEven( pStStrm );
3923     else
3924         nLen = nLen - WW8SkipOdd( pStStrm );
3925 
3926     if( bPara ) // Grupx.Papx
3927         nLen = ImportUPX(nLen, true, bOdd);
3928     ImportUPX(nLen, false, bOdd);                   // Grupx.Chpx
3929 }
3930 
WW8RStyle(WW8Fib & _rFib,SwWW8ImplReader * pI)3931 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3932     : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()),
3933     pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0)
3934 {
3935     pIo->nColls = cstd;
3936     pIo->pCollA = cstd ? new SwWW8StyInf[ cstd ] : NULL; // Style-UEbersetzung WW->SW
3937 }
3938 
Set1StyleDefaults()3939 void WW8RStyle::Set1StyleDefaults()
3940 {
3941     // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3942     if (!bCJKFontChanged)   // Style no CJK Font? set the default
3943         pIo->SetNewFontAttr(ftcFE, true, RES_CHRATR_CJK_FONT);
3944 
3945     if (!bCTLFontChanged)   // Style no CTL Font? set the default
3946         pIo->SetNewFontAttr(ftcBi, true, RES_CHRATR_CTL_FONT);
3947 
3948     //#88976# western 2nd to make western charset conversion the default
3949     if (!bFontChanged)      // Style has no Font? set the default,
3950     {
3951         pIo->SetNewFontAttr(ftcAsci, true, RES_CHRATR_FONT);
3952 		/* removed by a patch from cmc for #i52786#
3953         if (pIo->bVer67)
3954             SetStyleCharSet(pIo->pCollA[pIo->nAktColl]);
3955 		*/
3956     }
3957 
3958     if( !pIo->bNoAttrImport )
3959     {
3960         // Style has no text color set, winword default is auto
3961         if ( !bTxtColChanged )
3962             pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3963 
3964         // Style has no FontSize ? WinWord Default is 10pt for western and asian
3965         if( !bFSizeChanged )
3966         {
3967             SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3968             pIo->pAktColl->SetFmtAttr(aAttr);
3969             aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3970             pIo->pAktColl->SetFmtAttr(aAttr);
3971         }
3972 
3973         // Style has no FontSize ? WinWord Default is 10pt for western and asian
3974         if( !bFCTLSizeChanged )
3975         {
3976             SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3977             aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3978             pIo->pAktColl->SetFmtAttr(aAttr);
3979         }
3980 
3981         if( /*pIo->pWDop->fWidowControl &&*/ !bWidowsChanged )  // Widows ?
3982         {
3983             pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3984             pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3985         }
3986     }
3987 }
3988 
PrepareStyle(SwWW8StyInf & rSI,ww::sti eSti,sal_uInt16 nThisStyle,sal_uInt16 nNextStyle)3989 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3990 {
3991     SwFmt* pColl;
3992     bool bStyExist;
3993     if (rSI.bColl)
3994     {
3995         // Para-Style
3996         sw::util::ParaStyleMapper::StyleResult aResult =
3997             pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3998         pColl = aResult.first;
3999         bStyExist = aResult.second;
4000     }
4001     else
4002     {
4003         // Char-Style
4004         sw::util::CharStyleMapper::StyleResult aResult =
4005             pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
4006         pColl = aResult.first;
4007         bStyExist = aResult.second;
4008     }
4009 
4010     bool bImport = !bStyExist || pIo->mbNewDoc; // Inhalte Importieren ?
4011     bool bOldNoImp = pIo->bNoAttrImport;
4012     rSI.bImportSkipped = !bImport;
4013 
4014     if( !bImport )
4015         pIo->bNoAttrImport = true;
4016     else
4017     {
4018         if (bStyExist)
4019         {
4020             // --> OD 2007-01-25 #i73790# - method renamed
4021             pColl->ResetAllFmtAttr();
4022             // <--
4023         }
4024         pColl->SetAuto(false);          // nach Empfehlung JP
4025     }                                   // macht die UI aber anders
4026     pIo->pAktColl = pColl;
4027     rSI.pFmt = pColl;                  // UEbersetzung WW->SW merken
4028     rSI.bImportSkipped = !bImport;
4029 
4030     // Set Based on style
4031     sal_uInt16 j = rSI.nBase;
4032     if (j != nThisStyle && j < cstd )
4033     {
4034         SwWW8StyInf* pj = &pIo->pCollA[j];
4035         if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl)
4036         {
4037             rSI.pFmt->SetDerivedFrom( pj->pFmt );  // ok, Based on eintragen
4038             rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
4039             rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
4040             rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
4041             rSI.n81Flags = pj->n81Flags;
4042             rSI.n81BiDiFlags = pj->n81BiDiFlags;
4043             if ( !rSI.IsWW8BuiltInHeadingStyle() )
4044             {
4045                 rSI.mnWW8OutlineLevel = pj->mnWW8OutlineLevel;
4046             }
4047             rSI.bParaAutoBefore = pj->bParaAutoBefore;
4048             rSI.bParaAutoAfter = pj->bParaAutoAfter;
4049 
4050             if (pj->pWWFly)
4051                 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly);
4052         }
4053     }
4054     else if( pIo->mbNewDoc && bStyExist )
4055         rSI.pFmt->SetDerivedFrom(0);
4056 
4057     rSI.nFollow = nNextStyle;       // Follow merken
4058 
4059     pStyRule = 0;                   // falls noetig, neu anlegen
4060     bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
4061         bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
4062     pIo->SetNAktColl( nThisStyle );
4063     pIo->bStyNormal = nThisStyle == 0;
4064     return bOldNoImp;
4065 }
4066 
PostStyle(SwWW8StyInf & rSI,bool bOldNoImp)4067 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
4068 {
4069     // Alle moeglichen Attribut-Flags zuruecksetzen,
4070     // da es in Styles keine Attr-Enden gibt
4071 
4072     pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol
4073         = pIo->bSpec = pIo->bObj = pIo->bSymbol = false;
4074     pIo->nCharFmt = -1;
4075 
4076     // If Style basiert auf Nichts oder Basis ignoriert
4077     if ((rSI.nBase >= cstd || pIo->pCollA[rSI.nBase].bImportSkipped) && rSI.bColl)
4078     {
4079         //! Char-Styles funktionieren aus
4080         // unerfindlichen Gruenden nicht
4081         // -> dann evtl. harte WW-Defaults
4082         // reinsetzen
4083         Set1StyleDefaults();
4084     }
4085 
4086     pStyRule = 0;                   // zur Sicherheit
4087     pIo->bStyNormal = false;
4088     pIo->SetNAktColl( 0 );
4089     pIo->bNoAttrImport = bOldNoImp;
4090     // rasch nochmal die Listen-Merk-Felder zuruecksetzen,
4091     // fuer den Fall dass sie beim einlesen des Styles verwendet wurden
4092     pIo->nLFOPosition = USHRT_MAX;
4093     pIo->nListLevel = WW8ListManager::nMaxLevel;
4094 }
4095 
Import1Style(sal_uInt16 nNr)4096 void WW8RStyle::Import1Style( sal_uInt16 nNr )
4097 {
4098     SwWW8StyInf &rSI = pIo->pCollA[nNr];
4099 
4100     if( rSI.bImported || !rSI.bValid )
4101         return;
4102 
4103     rSI.bImported = true;                      // jetzt schon Flag setzen
4104                                                 // verhindert endlose Rekursion
4105                                                 //
4106     // gueltig und nicht NIL und noch nicht Importiert
4107 
4108     if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4109         Import1Style( rSI.nBase );
4110 
4111     pStStrm->Seek( rSI.nFilePos );
4112 
4113     short nSkip, cbStd;
4114     String sName;
4115 
4116     WW8_STD* pStd = Read1Style( nSkip, &sName, &cbStd );// lies Style
4117 
4118     if (pStd)
4119         rSI.SetOrgWWIdent( sName, pStd->sti );
4120 
4121     // either no Name or unused Slot or unknown Style
4122 
4123     if ( !pStd || (0 == sName.Len()) || ((1 != pStd->sgc) && (2 != pStd->sgc)) )
4124     {
4125         pStStrm->SeekRel( nSkip );
4126         return;
4127     }
4128 
4129     bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(pStd->sti), nNr, pStd->istdNext);
4130 
4131     // falls etwas falsch interpretiert wird, gehts danach wieder richtig
4132     long nPos = pStStrm->Tell();
4133 
4134     //Variable parts of the STD start at even byte offsets, but "inside
4135     //the STD", which I take to meaning even in relation to the starting
4136     //position of the STD, which matches findings in #89439#, generally it
4137     //doesn't matter as the STSHI starts off nearly always on an even
4138     //offset
4139 
4140     //Import of the Style Contents
4141     ImportGrupx(nSkip, pStd->sgc == 1, rSI.nFilePos & 1);
4142 
4143     PostStyle(rSI, bOldNoImp);
4144 
4145     pStStrm->Seek( nPos+nSkip );
4146     delete pStd;
4147 }
4148 
RecursiveReg(sal_uInt16 nNr)4149 void WW8RStyle::RecursiveReg(sal_uInt16 nNr)
4150 {
4151     SwWW8StyInf &rSI = pIo->pCollA[nNr];
4152     if( rSI.bImported || !rSI.bValid )
4153         return;
4154 
4155     rSI.bImported = true;
4156 
4157     if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4158         RecursiveReg(rSI.nBase);
4159 
4160     pIo->RegisterNumFmtOnStyle(nNr);
4161 
4162 }
4163 
4164 /*
4165  After all styles are imported then we can recursively apply numbering
4166  styles to them, and change their tab stop settings if they turned out
4167  to have special first line indentation.
4168 */
PostProcessStyles()4169 void WW8RStyle::PostProcessStyles()
4170 {
4171     sal_uInt16 i;
4172     /*
4173      Clear all imported flags so that we can recursively apply numbering
4174      formats and use it to mark handled ones
4175     */
4176     for (i=0; i < cstd; ++i)
4177         pIo->pCollA[i].bImported = false;
4178 
4179     /*
4180      Register the num formats and tabstop changes on the styles recursively.
4181     */
4182 
4183     /*
4184      In the same loop apply the tabstop changes required because we need to
4185      change their location if theres a special indentation for the first line,
4186      By avoiding making use of each styles margins during reading of their
4187      tabstops we don't get problems with doubly adjusting tabstops that
4188      are inheritied.
4189     */
4190     for (i=0; i < cstd; ++i)
4191     {
4192         if (pIo->pCollA[i].bValid)
4193         {
4194             RecursiveReg(i);
4195         }
4196     }
4197 }
4198 
ScanStyles()4199 void WW8RStyle::ScanStyles()        // untersucht Style-Abhaengigkeiten
4200 {                               // und ermittelt die Filepos fuer jeden Style
4201     /*
4202     WW8_FC nStyleStart = rFib.fcStshf;
4203     pStStrm->Seek( nStyleStart );
4204     */
4205     for (sal_uInt16 i = 0; i < cstd; ++i)
4206     {
4207         short nSkip;
4208         SwWW8StyInf &rSI = pIo->pCollA[i];
4209 
4210         rSI.nFilePos = pStStrm->Tell();        // merke FilePos
4211         WW8_STD* pStd = Read1Style( nSkip, 0, 0 );  // read STD
4212         rSI.bValid = (0 != pStd);
4213         if (rSI.bValid)
4214         {
4215             rSI.nBase = pStd->istdBase;        // merke Basis
4216             rSI.bColl = ( pStd->sgc == 1 );    // Para-Style
4217         }
4218         else
4219             rSI = SwWW8StyInf();
4220 
4221         delete pStd;
4222         pStStrm->SeekRel( nSkip );              // ueberlese Namen und Sprms
4223     }
4224 }
4225 
ChpxToSprms(const Word2CHPX & rChpx)4226 std::vector<sal_uInt8> ChpxToSprms(const Word2CHPX &rChpx)
4227 {
4228     std::vector<sal_uInt8> aRet;
4229 
4230     aRet.push_back(60);
4231     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBold) );
4232 
4233     aRet.push_back(61);
4234     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalic) );
4235 
4236     aRet.push_back(62);
4237     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fStrike) );
4238 
4239     aRet.push_back(63);
4240     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fOutline) );
4241 
4242     aRet.push_back(65);
4243     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fSmallCaps) );
4244 
4245     aRet.push_back(66);
4246     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fCaps) );
4247 
4248     aRet.push_back(67);
4249     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fVanish) );
4250 
4251     if (rChpx.fsFtc)
4252     {
4253         aRet.push_back(68);
4254         SVBT16 a;
4255         ShortToSVBT16(rChpx.ftc, a);
4256         aRet.push_back(a[1]);
4257         aRet.push_back(a[0]);
4258     }
4259 
4260     if (rChpx.fsKul)
4261     {
4262         aRet.push_back(69);
4263         aRet.push_back(rChpx.kul);
4264     }
4265 
4266     if (rChpx.fsLid)
4267     {
4268         aRet.push_back(72);
4269         SVBT16 a;
4270         ShortToSVBT16(rChpx.lid, a);
4271         aRet.push_back(a[1]);
4272         aRet.push_back(a[0]);
4273     }
4274 
4275     if (rChpx.fsIco)
4276     {
4277         aRet.push_back(73);
4278         aRet.push_back(rChpx.ico);
4279     }
4280 
4281     if (rChpx.fsHps)
4282     {
4283         aRet.push_back(74);
4284 
4285         SVBT16 a;
4286         ShortToSVBT16(rChpx.hps, a);
4287         aRet.push_back(a[0]);
4288 //        aRet.push_back(a[1]);
4289     }
4290 
4291     if (rChpx.fsPos)
4292     {
4293         aRet.push_back(76);
4294         aRet.push_back(rChpx.hpsPos);
4295     }
4296 
4297     aRet.push_back(80);
4298     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBoldBi) );
4299 
4300     aRet.push_back(81);
4301     aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalicBi) );
4302 
4303     if (rChpx.fsFtcBi)
4304     {
4305         aRet.push_back(82);
4306         SVBT16 a;
4307         ShortToSVBT16(rChpx.fsFtcBi, a);
4308         aRet.push_back(a[1]);
4309         aRet.push_back(a[0]);
4310     }
4311 
4312     if (rChpx.fsLidBi)
4313     {
4314         aRet.push_back(83);
4315         SVBT16 a;
4316         ShortToSVBT16(rChpx.lidBi, a);
4317         aRet.push_back(a[1]);
4318         aRet.push_back(a[0]);
4319     }
4320 
4321     if (rChpx.fsIcoBi)
4322     {
4323         aRet.push_back(84);
4324         aRet.push_back(rChpx.icoBi);
4325     }
4326 
4327     if (rChpx.fsHpsBi)
4328     {
4329         aRet.push_back(85);
4330         SVBT16 a;
4331         ShortToSVBT16(rChpx.hpsBi, a);
4332         aRet.push_back(a[1]);
4333         aRet.push_back(a[0]);
4334     }
4335 
4336     return aRet;
4337 }
4338 
ReadWord2Chpx(SvStream & rSt,sal_Size nOffset,sal_uInt8 nSize)4339 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4340 {
4341     Word2CHPX aChpx;
4342 
4343     if (!nSize)
4344         return aChpx;
4345 
4346     rSt.Seek(nOffset);
4347 
4348     sal_uInt8 nCount=0;
4349 
4350     while (1)
4351     {
4352         sal_uInt8 nFlags8;
4353         rSt >> nFlags8;
4354         nCount++;
4355 
4356         aChpx.fBold = nFlags8 & 0x01;
4357         aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4358         aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4359         aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4360         aChpx.fFldVanish = (nFlags8 & 0x10) >> 4;
4361         aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4362         aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4363         aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4364 
4365         if (nCount >= nSize) break;
4366         rSt >> nFlags8;
4367         nCount++;
4368 
4369         aChpx.fRMark = nFlags8 & 0x01;
4370         aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4371         aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4372         aChpx.fObj = (nFlags8 & 0x08) >> 3;
4373         aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4374         aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4375         aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4376         aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4377 
4378         if (nCount >= nSize) break;
4379         rSt >> nFlags8;
4380         nCount++;
4381 
4382         aChpx.fsIco = nFlags8 & 0x01;
4383         aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4384         aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4385         aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4386         aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4387         aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4388         aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4389         aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4390 
4391         if (nCount >= nSize) break;
4392         rSt >> nFlags8;
4393         nCount++;
4394 
4395         aChpx.fsFtcBi = nFlags8 & 0x01;
4396         aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4397         aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4398 
4399         if (nCount >= nSize) break;
4400         rSt >> aChpx.ftc;
4401         nCount+=2;
4402 
4403         if (nCount >= nSize) break;
4404         rSt >> aChpx.hps;
4405         nCount+=2;
4406 
4407         if (nCount >= nSize) break;
4408         rSt >> nFlags8;
4409         nCount++;
4410 
4411         aChpx.qpsSpace = nFlags8 & 0x3F;
4412         aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4413         aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4414 
4415         if (nCount >= nSize) break;
4416         rSt >> nFlags8;
4417         nCount++;
4418 
4419         aChpx.ico = nFlags8 & 0x1F;
4420         aChpx.kul = (nFlags8 & 0xE0) >> 5;
4421 
4422         if (nCount >= nSize) break;
4423         rSt >> aChpx.hpsPos;
4424         nCount++;
4425 
4426         if (nCount >= nSize) break;
4427         rSt >> aChpx.icoBi;
4428         nCount++;
4429 
4430         if (nCount >= nSize) break;
4431         rSt >> aChpx.lid;
4432         nCount+=2;
4433 
4434         if (nCount >= nSize) break;
4435         rSt >> aChpx.ftcBi;
4436         nCount+=2;
4437 
4438         if (nCount >= nSize) break;
4439         rSt >> aChpx.hpsBi;
4440         nCount+=2;
4441 
4442         if (nCount >= nSize) break;
4443         rSt >> aChpx.lidBi;
4444         nCount+=2;
4445 
4446         if (nCount >= nSize) break;
4447         rSt >> aChpx.fcPic;
4448         nCount+=4;
4449 
4450         break;
4451     }
4452 
4453     rSt.SeekRel(nSize-nCount);
4454     return aChpx;
4455 }
4456 
4457 namespace
4458 {
4459     struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4460 }
4461 
ImportOldFormatStyles()4462 void WW8RStyle::ImportOldFormatStyles()
4463 {
4464     for (sal_uInt16 i=0; i < cstd; ++i)
4465     {
4466         pIo->pCollA[i].bColl = true;
4467         //every chain must end eventually at the null style (style code 222)
4468         pIo->pCollA[i].nBase = 222;
4469     }
4470 
4471     rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4472         pIo->pWwFib->chseTables);
4473 
4474     sal_uInt16 cstcStd;
4475     rSt >> cstcStd;
4476 
4477     sal_uInt16 cbName;
4478     rSt >> cbName;
4479     sal_uInt16 nByteCount = 2;
4480     sal_uInt16 stcp=0;
4481     while (nByteCount < cbName)
4482     {
4483         sal_uInt8 nCount;
4484         rSt >> nCount;
4485         nByteCount++;
4486 
4487         sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4488         SwWW8StyInf &rSI = pIo->pCollA[stc];
4489         if (nCount != 0xFF)    // undefined style
4490         {
4491             String sName;
4492             if (nCount == 0)   // inbuilt style
4493             {
4494                 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4495                 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4496                     sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4497                 else
4498                     sName = String(CREATE_CONST_ASC("Unknown"));
4499             }
4500             else               // user style
4501             {
4502                 ByteString aTmp;
4503                 nByteCount = static_cast< sal_uInt16 >(nByteCount + SafeReadString(aTmp, nCount, rSt));
4504                 sName = String(aTmp, eStructChrSet);
4505             }
4506             rSI.SetOrgWWIdent(sName, stc);
4507             rSI.bImported = true;
4508         }
4509         else
4510         {
4511             ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4512             if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4513             {
4514                 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4515                 rSI.SetOrgWWIdent(sName, stc);
4516             }
4517         }
4518         stcp++;
4519     }
4520 
4521     sal_uInt16 nStyles=stcp;
4522 
4523     std::vector<pxoffset> aCHPXOffsets(stcp);
4524     sal_uInt16 cbChpx;
4525     rSt >> cbChpx;
4526     nByteCount = 2;
4527     stcp=0;
4528     std::vector< std::vector<sal_uInt8> > aConvertedChpx;
4529     while (nByteCount < cbChpx)
4530     {
4531         sal_uInt8 cb;
4532         rSt >> cb;
4533         nByteCount++;
4534 
4535         aCHPXOffsets.at(stcp).mnSize = 0;
4536 
4537         if (cb != 0xFF)
4538         {
4539             sal_uInt8 nRemainder = cb;
4540 
4541             aCHPXOffsets.at(stcp).mnOffset = rSt.Tell();
4542             aCHPXOffsets.at(stcp).mnSize = nRemainder;
4543 
4544             Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets.at(stcp).mnOffset,
4545                 aCHPXOffsets.at(stcp).mnSize);
4546             aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4547 
4548             nByteCount += nRemainder;
4549         }
4550         else
4551             aConvertedChpx.push_back( std::vector<sal_uInt8>() );
4552 
4553         stcp++;
4554         if (stcp == nStyles)
4555 	{
4556             rSt.SeekRel(cbChpx-nByteCount);
4557             nByteCount += cbChpx-nByteCount;
4558 	}
4559     }
4560 
4561     std::vector<pxoffset> aPAPXOffsets(stcp);
4562     sal_uInt16 cbPapx;
4563     rSt >> cbPapx;
4564     nByteCount = 2;
4565     stcp=0;
4566     while (nByteCount < cbPapx)
4567     {
4568         sal_uInt8 cb;
4569         rSt >> cb;
4570         nByteCount++;
4571 
4572         aPAPXOffsets[stcp].mnSize = 0;
4573 
4574         if (cb != 0xFF)
4575         {
4576             sal_uInt8 stc2;
4577             rSt >> stc2;
4578             rSt.SeekRel(6);
4579             nByteCount+=7;
4580             sal_uInt8 nRemainder = cb-7;
4581 
4582             aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4583             aPAPXOffsets[stcp].mnSize = nRemainder;
4584 
4585             rSt.SeekRel(nRemainder);
4586             nByteCount += nRemainder;
4587         }
4588 
4589         stcp++;
4590 
4591         if (stcp == nStyles)
4592 	{
4593             rSt.SeekRel(cbPapx-nByteCount);
4594             nByteCount += cbPapx-nByteCount;
4595 	}
4596     }
4597 
4598     sal_uInt16 iMac;
4599     rSt >> iMac;
4600 
4601     if (iMac > nStyles) iMac = nStyles;
4602 
4603     for (stcp = 0; stcp < iMac; ++stcp)
4604     {
4605         sal_uInt8 stcNext, stcBase;
4606         rSt >> stcNext;
4607         rSt >> stcBase;
4608 
4609         sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4610 
4611         /*
4612           #i64557# style based on itself
4613           every chain must end eventually at the null style (style code 222)
4614         */
4615         if (stc == stcBase)
4616             stcBase = 222;
4617 
4618         SwWW8StyInf &rSI = pIo->pCollA[stc];
4619         rSI.nBase = stcBase;
4620 
4621         ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4622 
4623         if (eSti == ww::stiNil)
4624             continue;
4625 
4626         rSI.bValid = true;
4627 
4628         if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4629             pIo->pCollA[stc].bColl = false;
4630 
4631         bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4632 
4633         ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4634             true);
4635 
4636         if (aConvertedChpx[stcp].size() > 0)
4637             ImportSprms(&(aConvertedChpx[stcp][0]),
4638                         static_cast< short >(aConvertedChpx[stcp].size()),
4639                         false);
4640 
4641         PostStyle(rSI, bOldNoImp);
4642     }
4643 }
4644 
ImportNewFormatStyles()4645 void WW8RStyle::ImportNewFormatStyles()
4646 {
4647     ScanStyles();                       // Scanne Based On
4648 
4649     for (sal_uInt16 i = 0; i < cstd; ++i) // import Styles
4650         if (pIo->pCollA[i].bValid)
4651             Import1Style( i );
4652 }
4653 
ImportStyles()4654 void WW8RStyle::ImportStyles()
4655 {
4656     if (ww::eWW2 == pIo->pWwFib->GetFIBVersion())
4657         ImportOldFormatStyles();
4658     else
4659         ImportNewFormatStyles();
4660 }
4661 
Import()4662 void WW8RStyle::Import()
4663 {
4664     pIo->pDfltTxtFmtColl  = pIo->rDoc.GetDfltTxtFmtColl();
4665     pIo->pStandardFmtColl =
4666         pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
4667 
4668     if( pIo->nIniFlags & WW8FL_NO_STYLES )
4669         return;
4670 
4671     ImportStyles();
4672 
4673     for (sal_uInt16 i = 0; i < cstd; ++i)
4674     {
4675         // Follow chain
4676         SwWW8StyInf* pi = &pIo->pCollA[i];
4677         sal_uInt16 j = pi->nFollow;
4678         if( j < cstd )
4679         {
4680             SwWW8StyInf* pj = &pIo->pCollA[j];
4681             if ( j != i                             // sinnvoller Index ?
4682                  && pi->pFmt                        // Format ok ?
4683                  && pj->pFmt                        // Derived-Format ok ?
4684                  && pi->bColl                       // geht nur bei Absatz-Vorlagen (WW)
4685                  && pj->bColl ){                    // beides gleicher Typ ?
4686                     ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl(
4687                      *(SwTxtFmtColl*)pj->pFmt );    // ok, eintragen
4688             }
4689         }
4690     }
4691 // Die Sonderbehandlung zur Setzen der
4692 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt
4693 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der
4694 // WW-UI nicht zu veraendern, so dass das nicht stoert.
4695 // Der Mechanismus waere folgender:
4696 //  if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4697 //
4698     // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht
4699 
4700     if( pIo->StyleExists(0) && pIo->pCollA[0].pFmt && pIo->pCollA[0].bColl && pIo->pCollA[0].bValid )
4701         pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->pCollA[0].pFmt;
4702     else
4703         pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4704 
4705 
4706     // set Hyphenation flag on BASIC para-style
4707     if (pIo->mbNewDoc && pIo->pStandardFmtColl)
4708     {
4709         if (pIo->pWDop->fAutoHyphen
4710             && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(
4711                                             RES_PARATR_HYPHENZONE, false) )
4712         {
4713             SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4714             aAttr.GetMinLead()    = 2;
4715             aAttr.GetMinTrail()   = 2;
4716             aAttr.GetMaxHyphens() = 0;
4717 
4718             pIo->pStandardFmtColl->SetFmtAttr( aAttr );
4719         }
4720 
4721         /*
4722         Word defaults to ltr not from environment like writer. Regardless of
4723         the page/sections rtl setting the standard style lack of rtl still
4724         means ltr
4725         */
4726         if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR,
4727             false))
4728         {
4729            pIo->pStandardFmtColl->SetFmtAttr(
4730                 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4731         }
4732     }
4733 
4734     // wir sind jetzt nicht mehr beim Style einlesen:
4735     pIo->pAktColl = 0;
4736 }
4737 
GetCharSet() const4738 CharSet SwWW8StyInf::GetCharSet() const
4739 {
4740     if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4741         return eRTLFontSrcCharSet;
4742     return eLTRFontSrcCharSet;
4743 }
4744 
GetCJKCharSet() const4745 CharSet SwWW8StyInf::GetCJKCharSet() const
4746 {
4747     if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4748         return eRTLFontSrcCharSet;
4749     return eCJKFontSrcCharSet;
4750 }
4751 
4752 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
4753