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