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