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