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