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