update ooo310-m15
[ooovba.git] / sw / source / filter / ww8 / ww8par2.cxx
blobd593816523738470314ef6bff64699cc7663856c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ww8par2.cxx,v $
10 * $Revision: 1.145.76.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
35 #include <tools/solar.h>
36 #include <vcl/vclenum.hxx>
37 #include <vcl/font.hxx>
38 #include <hintids.hxx>
39 #include <svx/colritem.hxx>
40 #include <svx/orphitem.hxx>
41 #include <svx/widwitem.hxx>
42 #include <svx/brshitem.hxx>
43 #include <svx/boxitem.hxx>
44 #include <svx/lrspitem.hxx>
45 #include <svx/fhgtitem.hxx>
46 #include <svx/fhgtitem.hxx>
47 #include <svx/hyznitem.hxx>
48 #include <svx/frmdiritem.hxx>
49 #include <svx/langitem.hxx>
50 #include <svx/charrotateitem.hxx>
51 #include <svx/pgrditem.hxx>
52 #include <msfilter.hxx>
53 #include <pam.hxx> // fuer SwPam
54 #include <doc.hxx>
55 #include <docary.hxx>
56 #include <ndtxt.hxx> // class SwTxtNode
57 #include <paratr.hxx> // SwNumRuleItem
58 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD
59 #include <swtable.hxx> // class SwTableLines, ...
60 #include <tblsel.hxx> // class _SwSelBox
61 #include <mdiexp.hxx>
62 #include <fmtpdsc.hxx>
63 #include <txtftn.hxx>
64 #include <frmfmt.hxx>
65 #include <ftnidx.hxx>
66 #include <fmtftn.hxx>
67 #include <charfmt.hxx>
68 #include <SwStyleNameMapper.hxx>
69 #include <fltshell.hxx> // fuer den Attribut Stack
70 #include <fmtanchr.hxx>
71 #include <fmtrowsplt.hxx>
72 // --> OD 2005-01-27 #i33818#
73 #include <fmtfollowtextflow.hxx>
74 // <--
75 #include <numrule.hxx>
76 # include "../inc/wwstyles.hxx"
77 # include "writerhelper.hxx"
78 #include "ww8struc.hxx" // struct TC
79 #include "ww8par.hxx"
80 #include "ww8par2.hxx"
82 #include <frmatr.hxx>
84 #include <iostream>
86 #define MAX_COL 64 // WW6-Beschreibung: 32, WW6-UI: 31 & WW8-UI: 63!
88 using namespace ::com::sun::star;
91 class WW8SelBoxInfo: public SwSelBoxes_SAR
93 private:
94 WW8SelBoxInfo(const WW8SelBoxInfo&);
95 WW8SelBoxInfo& operator=(const WW8SelBoxInfo&);
96 public:
97 short nGroupXStart;
98 short nGroupWidth;
99 bool bGroupLocked;
101 WW8SelBoxInfo(short nXCenter, short nWidth)
102 : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
106 typedef WW8SelBoxInfo* WW8SelBoxInfoPtr;
108 SV_DECL_PTRARR_DEL(WW8MergeGroups, WW8SelBoxInfoPtr, 16,16)
109 SV_IMPL_PTRARR(WW8MergeGroups, WW8SelBoxInfoPtr)
111 struct WW8TabBandDesc
113 WW8TabBandDesc* pNextBand;
114 short nGapHalf;
115 short mnDefaultLeft;
116 short mnDefaultTop;
117 short mnDefaultRight;
118 short mnDefaultBottom;
119 bool mbHasSpacing;
120 short nLineHeight;
121 short nRows;
122 sal_uInt16 maDirections[MAX_COL + 1];
123 short nCenter[MAX_COL + 1]; // X-Rand aller Zellen dieses Bandes
124 short nWidth[MAX_COL + 1]; // Laenge aller Zellen dieses Bandes
125 short nWwCols; // BYTE wuerde reichen, alignment -> short
126 short nSwCols; // SW: so viele Spalten fuer den Writer
127 bool bLEmptyCol; // SW: Links eine leere Zusatz-Spalte
128 bool bREmptyCol; // SW: dito rechts
129 bool bCantSplit;
130 bool bCantSplit90;
131 WW8_TCell* pTCs;
132 BYTE nOverrideSpacing[MAX_COL + 1];
133 short nOverrideValues[MAX_COL + 1][4];
134 WW8_SHD* pSHDs;
135 sal_uInt32* pNewSHDs;
136 WW8_BRC aDefBrcs[6];
139 // nur fuer WW6-7: diese Zelle hat WW-Flag bMerged (horizontal) gesetzt
140 //bool bWWMergedVer6[MAX_COL];
143 bool bExist[MAX_COL]; // Existiert diese Zelle ?
144 UINT8 nTransCell[MAX_COL + 2]; // UEbersetzung WW-Index -> SW-Index
146 WW8TabBandDesc();
147 WW8TabBandDesc(WW8TabBandDesc& rBand); // tief kopieren
148 ~WW8TabBandDesc();
149 static void setcelldefaults(WW8_TCell *pCells, short nCells);
150 void ReadDef(bool bVer67, const BYTE* pS);
151 void ProcessDirection(const BYTE* pParams);
152 void ProcessSprmTSetBRC(bool bVer67, const BYTE* pParamsTSetBRC);
153 void ProcessSprmTTableBorders(bool bVer67, const BYTE* pParams);
154 void ProcessSprmTDxaCol(const BYTE* pParamsTDxaCol);
155 void ProcessSprmTDelete(const BYTE* pParamsTDelete);
156 void ProcessSprmTInsert(const BYTE* pParamsTInsert);
157 void ProcessSpacing(const BYTE* pParamsTInsert);
158 void ProcessSpecificSpacing(const BYTE* pParamsTInsert);
159 void ReadShd(const BYTE* pS );
160 void ReadNewShd(const BYTE* pS, bool bVer67);
162 enum wwDIR {wwTOP = 0, wwLEFT = 1, wwBOTTOM = 2, wwRIGHT = 3};
165 WW8TabBandDesc::WW8TabBandDesc()
167 memset(this, 0, sizeof(*this));
168 for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i)
169 maDirections[i] = 4;
172 WW8TabBandDesc::~WW8TabBandDesc()
174 delete[] pTCs;
175 delete[] pSHDs;
176 delete[] pNewSHDs;
179 class WW8TabDesc
181 std::vector<String> aNumRuleNames;
182 sw::util::RedlineStack *mpOldRedlineStack;
184 SwWW8ImplReader* pIo;
186 WW8TabBandDesc* pFirstBand;
187 WW8TabBandDesc* pActBand;
189 SwPosition* pTmpPos;
191 SwTableNode* pTblNd; // Tabellen-Node
192 const SwTableLines* pTabLines; // Zeilen-Array davon
193 SwTableLine* pTabLine; // akt. Zeile
194 SwTableBoxes* pTabBoxes; // Boxen-Array in akt. Zeile
195 SwTableBox* pTabBox; // akt. Zelle
197 WW8MergeGroups* pMergeGroups; // Listen aller zu verknuepfenden Zellen
199 WW8_TCell* pAktWWCell;
201 short nRows;
202 short nDefaultSwCols;
203 short nBands;
204 short nMinLeft;
205 short nConvertedLeft;
206 short nMaxRight;
207 short nSwWidth;
208 short nPreferredWidth;
209 short nOrgDxaLeft;
211 bool bOk;
212 bool bClaimLineFmt;
213 sal_Int16 eOri;
214 bool bIsBiDi;
215 // 2. allgemeine Verwaltungsinfo
216 short nAktRow;
217 short nAktBandRow; // SW: in dieser Zeile des akt. Bandes bin ich
218 // 3. Verwaltungsinfo fuer Writer
219 short nAktCol;
221 USHORT nRowsToRepeat;
223 // 4. Methoden
225 USHORT GetLogicalWWCol() const;
226 void SetTabBorders( SwTableBox* pBox, short nIdx );
227 void SetTabShades( SwTableBox* pBox, short nWwIdx );
228 void SetTabVertAlign( SwTableBox* pBox, short nWwIdx );
229 void SetTabDirection( SwTableBox* pBox, short nWwIdx );
230 void CalcDefaults();
231 bool SetPamInCell(short nWwCol, bool bPam);
232 void InsertCells( short nIns );
233 void AdjustNewBand();
235 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw.
236 // -1 Details siehe bei der Implementierung
237 bool FindMergeGroup(short nX1, short nWidth, bool bExact, short& nMGrIdx);
239 // einzelne Box ggfs. in eine Merge-Gruppe aufnehmen
240 // (die Merge-Gruppen werden dann spaeter auf einen Schlag abgearbeitet)
241 SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
242 WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, USHORT nCol );
243 void StartMiserableHackForUnsupportedDirection(short nWwCol);
244 void EndMiserableHackForUnsupportedDirection(short nWwCol);
245 //No copying
246 WW8TabDesc(const WW8TabDesc&);
247 WW8TabDesc &operator=(const WW8TabDesc&);
248 public:
249 const SwTable* pTable; // Tabelle
250 SwPosition* pParentPos;
251 SwFlyFrmFmt* pFlyFmt;
252 SfxItemSet aItemSet;
253 bool IsValidCell(short nCol) const;
254 bool InFirstParaInCell() const;
256 WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp );
257 bool Ok() const { return bOk; }
258 void CreateSwTable();
259 void UseSwTable();
260 void SetSizePosition(SwFrmFmt* pFrmFmt);
261 void TableCellEnd();
262 void MoveOutsideTable();
263 void ParkPaM();
264 void FinishSwTable();
265 void MergeCells();
266 short GetMinLeft() const { return nConvertedLeft; }
267 ~WW8TabDesc();
268 SwPosition *GetPos() { return pTmpPos; }
270 const WW8_TCell* GetAktWWCell() const { return pAktWWCell; }
271 short GetAktCol() const { return nAktCol; }
272 // find name of numrule valid for current WW-COL
273 const String& GetNumRuleName() const;
274 void SetNumRuleName( const String& rName );
276 sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; }
279 void sw::util::RedlineStack::close( const SwPosition& rPos,
280 RedlineType_t eType, WW8TabDesc* pTabDesc )
282 // If the redline type is not found in the redline stack, we have to check if there has been
283 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
284 if( !close( rPos, eType ) )
286 if( pTabDesc && pTabDesc->getOldRedlineStack() )
288 #ifndef PRODUCT
289 ASSERT( pTabDesc->getOldRedlineStack()->close(rPos, eType), "close without open!");
290 #else
291 pTabDesc->getOldRedlineStack()->close( rPos, eType );
292 #endif
298 void wwSectionManager::SetCurrentSectionHasFootnote()
300 ASSERT(!maSegments.empty(),
301 "should not be possible, must be at least one segment");
302 if (!maSegments.empty())
303 maSegments.back().mbHasFootnote = true;
306 bool wwSectionManager::CurrentSectionIsVertical() const
308 ASSERT(!maSegments.empty(),
309 "should not be possible, must be at least one segment");
310 if (!maSegments.empty())
311 return maSegments.back().IsVertical();
312 return false;
315 bool wwSectionManager::CurrentSectionIsProtected() const
317 ASSERT(!maSegments.empty(),
318 "should not be possible, must be at least one segment");
319 if (!maSegments.empty())
320 return SectionIsProtected(maSegments.back());
321 return false;
324 sal_uInt32 wwSectionManager::GetPageLeft() const
326 return !maSegments.empty() ? maSegments.back().nPgLeft : 0;
329 sal_uInt32 wwSectionManager::GetPageRight() const
331 return !maSegments.empty() ? maSegments.back().nPgRight : 0;
334 sal_uInt32 wwSectionManager::GetPageWidth() const
336 return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
339 sal_uInt32 wwSectionManager::GetTextAreaWidth() const
341 return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
344 // --> OD 2007-07-03 #148498#
345 sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
347 return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
349 // <--
351 sal_uInt16 SwWW8ImplReader::End_Ftn()
354 #84095#
355 Ignoring Footnote outside of the normal Text. People will put footnotes
356 into field results and field commands.
358 if (bIgnoreText ||
359 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
361 return 0;
364 ASSERT(!maFtnStack.empty(), "footnote end without start");
365 if (maFtnStack.empty())
366 return 0;
368 bool bFtEdOk = false;
369 const FtnDescriptor &rDesc = maFtnStack.back();
371 //Get the footnote character and remove it from the txtnode. We'll
372 //replace it with the footnote
373 SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode();
374 xub_StrLen nPos = pPaM->GetPoint()->nContent.GetIndex();
376 String sChar;
377 SwTxtAttr* pFN = 0;
378 //There should have been a footnote char, we will replace this.
379 if (pTxt && nPos)
381 sChar.Append(pTxt->GetTxt().GetChar(--nPos));
382 pPaM->SetMark();
383 pPaM->GetMark()->nContent--;
384 rDoc.Delete( *pPaM );
385 pPaM->DeleteMark();
386 SwFmtFtn aFtn(rDesc.meType == MAN_EDN);
387 pFN = pTxt->InsertItem(aFtn, nPos, nPos);
389 ASSERT(pFN, "Probleme beim Anlegen des Fussnoten-Textes");
390 if (pFN)
393 SwPosition aTmpPos( *pPaM->GetPoint() ); // merke alte Cursorposition
394 WW8PLCFxSaveAll aSave;
395 pPlcxMan->SaveAllPLCFx( aSave );
396 WW8PLCFMan* pOldPlcxMan = pPlcxMan;
398 const SwNodeIndex* pSttIdx = ((SwTxtFtn*)pFN)->GetStartNode();
399 ASSERT(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes");
401 ((SwTxtFtn*)pFN)->SetSeqNo( rDoc.GetFtnIdxs().Count() );
403 bool bOld = bFtnEdn;
404 bFtnEdn = true;
406 // read content of Ft-/End-Note
407 Read_HdFtFtnText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
408 bFtEdOk = true;
409 bFtnEdn = bOld;
411 ASSERT(sChar.Len()==1 && ((rDesc.mbAutoNum == (sChar.GetChar(0) == 2))),
412 "footnote autonumbering must be 0x02, and everthing else must not be");
414 // If no automatic numbering use the following char from the main text
415 // as the footnote number
416 if (!rDesc.mbAutoNum)
417 ((SwTxtFtn*)pFN)->SetNumber(0, &sChar);
420 Delete the footnote char from the footnote if its at the beginning
421 as usual. Might not be if the user has already deleted it, e.g.
422 #i14737#
424 SwNodeIndex& rNIdx = pPaM->GetPoint()->nNode;
425 rNIdx = pSttIdx->GetIndex() + 1;
426 SwTxtNode* pTNd = rNIdx.GetNode().GetTxtNode();
427 if (pTNd && pTNd->GetTxt().Len() && sChar.Len())
429 if (pTNd->GetTxt().GetChar(0) == sChar.GetChar(0))
431 pPaM->GetPoint()->nContent.Assign( pTNd, 0 );
432 pPaM->SetMark();
433 // Strip out tabs we may have inserted on export #i24762#
434 if (pTNd->GetTxt().GetChar(1) == 0x09)
435 pPaM->GetMark()->nContent++;
436 pPaM->GetMark()->nContent++;
437 pReffingStck->Delete(*pPaM);
438 rDoc.Delete( *pPaM );
439 pPaM->DeleteMark();
443 *pPaM->GetPoint() = aTmpPos; // restore Cursor
445 pPlcxMan = pOldPlcxMan; // Restore attributes
446 pPlcxMan->RestoreAllPLCFx( aSave );
449 if (bFtEdOk)
450 maSectionManager.SetCurrentSectionHasFootnote();
452 maFtnStack.pop_back();
453 return 0;
456 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult* pRes)
459 #84095#
460 Ignoring Footnote outside of the normal Text. People will put footnotes
461 into field results and field commands.
463 if (bIgnoreText ||
464 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
466 return 0;
469 FtnDescriptor aDesc;
470 aDesc.mbAutoNum = true;
471 if (eEDN == pRes->nSprmId)
473 aDesc.meType = MAN_EDN;
474 if (pPlcxMan->GetEdn())
475 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetEdn()->GetData();
477 else
479 aDesc.meType = MAN_FTN;
480 if (pPlcxMan->GetFtn())
481 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetFtn()->GetData();
484 aDesc.mnStartCp = pRes->nCp2OrIdx;
485 aDesc.mnLen = pRes->nMemLen;
487 maFtnStack.push_back(aDesc);
489 return 0;
492 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp,
493 int nLevel) const
495 WW8PLCFxDesc aRes;
496 aRes.pMemPos = 0;
497 aRes.nEndPos = rStartCp;
499 while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
501 if (pPap->Where() != WW8_CP_MAX)
503 const BYTE* pB = pPap->HasSprm(TabRowSprm(nLevel));
504 if (pB && *pB == 1)
506 const BYTE *pLevel = 0;
507 if (0 != (pLevel = pPap->HasSprm(0x6649)))
509 if (nLevel + 1 == *pLevel)
510 return true;
512 else
514 ASSERT(!nLevel || pLevel, "sublevel without level sprm");
515 return true; // RowEnd found
520 aRes.nStartPos = aRes.nEndPos;
521 aRes.pMemPos = 0;
522 //Seek to our next block of properties
523 if (!(pPap->SeekPos(aRes.nStartPos)))
525 aRes.nEndPos = WW8_CP_MAX;
526 pPap->SetDirty(true);
528 pPap->GetSprms(&aRes);
529 pPap->SetDirty(false);
530 //Update our aRes to get the new starting point of the next properties
531 rStartCp = aRes.nEndPos;
534 return false;
537 ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
538 const WW8_TablePos *pTabPos)
540 const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0;
541 ApoTestResults aRet;
542 // Frame in Style Definition (word appears to ignore them if inside an
543 // text autoshape, e.g. #94418#)
544 if (!bTxbxFlySection)
545 aRet.mpStyleApo = StyleExists(nAktColl) ? pCollA[nAktColl].pWWFly : 0;
548 #i1140#
549 If I have a table and apply a style to one of its frames that should cause
550 a paragraph that its applied to it to only exist as a seperate floating
551 frame, then the behavour depends on which cell that it has been applied
552 to. If its the first cell of a row then the whole table row jumps into the
553 new frame, if its not then then the paragraph attributes are applied
554 "except" for the floating frame stuff. i.e. its ignored. So if theres a
555 table, and we're not in the first cell then we ignore the fact that the
556 paragraph style wants to be in a different frame.
558 This sort of mindbending inconsistency is surely why frames are deprecated
559 in word 97 onwards and hidden away from the user
562 #i1532# & #i5379#
563 If we are already a table in a frame then we must grab the para properties
564 to see if we are still in that frame.
567 aRet.mpSprm37 = pPlcxMan->HasParaSprm( bVer67 ? 37 : 0x2423 );
568 aRet.mpSprm29 = pPlcxMan->HasParaSprm( bVer67 ? 29 : 0x261B );
570 // Is there some frame data here
571 bool bNowApo = aRet.HasFrame() || pTopLevelTable;
572 if (bNowApo)
574 if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos))
575 delete pTest;
576 else
577 bNowApo = false;
580 bool bTestAllowed = !bTxbxFlySection && !bTableRowEnd;
581 if (bTestAllowed)
583 //Test is allowed if there is no table.
584 //Otherwise only allowed if we are in the
585 //first paragraph of the first cell of a row.
586 //(And only if the row we are inside is at the
587 //same level as the previous row, think tables
588 //in tables)
589 if (nCellLevel == nInTable)
592 if (!nInTable)
593 bTestAllowed = true;
594 else
596 if (!pTableDesc)
598 ASSERT(pTableDesc, "What!");
599 bTestAllowed = false;
601 else
603 // --> OD 2005-02-01 #i39468#
604 // If current cell isn't valid, the test is allowed.
605 // The cell isn't valid, if e.g. there is a new row
606 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
607 bTestAllowed =
608 pTableDesc->GetAktCol() == 0 &&
609 ( !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) ||
610 pTableDesc->InFirstParaInCell() );
611 // <--
617 if (!bTestAllowed)
618 return aRet;
620 aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start
621 aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end
623 //If it happens that we are in a table, then if its not the first cell
624 //then any attributes that might otherwise cause the contents to jump
625 //into another frame don't matter, a table row sticks together as one
626 //unit no matter what else happens. So if we are not in a table at
627 //all, or if we are in the first cell then test that the last frame
628 //data is the same as the current one
629 if (bNowApo && InEqualApo(nCellLevel))
631 // two bordering eachother
632 if (!TestSameApo(aRet, pTabPos))
633 aRet.mbStopApo = aRet.mbStartApo = true;
636 return aRet;
638 //---------------------------------------------------------------------
639 // Hilfroutinen fuer Kapitelnummerierung und Aufzaehlung / Gliederung
640 //---------------------------------------------------------------------
642 static void SetBaseAnlv(SwNumFmt &rNum, WW8_ANLV &rAV, BYTE nSwLevel )
644 static SvxExtNumType eNumA[8] = { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
645 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N, SVX_NUM_ARABIC,
646 SVX_NUM_ARABIC, SVX_NUM_ARABIC };
648 static SvxAdjust eAdjA[4] = { SVX_ADJUST_LEFT,
649 SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT };
650 // eigentlich folgende 2, aber Writer-UI bietet es nicht an
651 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE };
653 rNum.SetNumberingType( static_cast< sal_Int16 >(( SVBT8ToByte( rAV.nfc ) < 8 ) ?
654 eNumA[SVBT8ToByte( rAV.nfc ) ] : SVX_NUM_NUMBER_NONE) );
655 if ((SVBT8ToByte(rAV.aBits1 ) & 0x4) >> 2)
656 rNum.SetIncludeUpperLevels(nSwLevel + 1);
657 rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) );
658 // rNum.eNumAdjust = eAdjA[rAV.jc];
659 rNum.SetNumAdjust( eAdjA[SVBT8ToByte( rAV.aBits1 ) & 0x3] );
661 rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) );
662 INT16 nIndent = Abs((INT16)SVBT16ToShort( rAV.dxaIndent ));
663 if( SVBT8ToByte( rAV.aBits1 ) & 0x08 ) //fHang
665 rNum.SetFirstLineOffset( -nIndent );
666 rNum.SetLSpace( nIndent );
667 rNum.SetAbsLSpace( nIndent );
669 else
670 rNum.SetCharTextDistance( nIndent ); // Breite der Nummer fehlt
672 if( SVBT8ToByte( rAV.nfc ) == 5 || SVBT8ToByte( rAV.nfc ) == 7 )
674 String sP( rNum.GetSuffix() );
675 sP.Insert( '.', 0 );
676 rNum.SetSuffix( sP ); // Ordinalzahlen
680 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt &rNum, WW8_ANLV &rAV,
681 const BYTE* pTxt, bool bOutline)
683 bool bInsert = false; // Default
684 CharSet eCharSet = eStructCharSet;
686 const WW8_FFN* pF = pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo
687 bool bListSymbol = pF && ( pF->chs == 2 ); // Symbol/WingDings/...
689 String sTxt;
690 if (bVer67)
692 sTxt = String( (sal_Char*)pTxt, SVBT8ToByte( rAV.cbTextBefore )
693 + SVBT8ToByte( rAV.cbTextAfter ), eCharSet );
695 else
697 for(xub_StrLen i = SVBT8ToByte(rAV.cbTextBefore);
698 i < SVBT8ToByte(rAV.cbTextAfter); ++i, pTxt += 2)
700 sTxt.Append(SVBT16ToShort(*(SVBT16*)pTxt));
704 if( bOutline )
705 { // Gliederung
706 if( !rNum.GetIncludeUpperLevels() // es sind <= 1 Nummern anzuzeigen
707 || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ){ // oder dieser Level hat keine
708 // eigenen Ziffern
709 bInsert = true; // -> dann uebernehme Zeichen
711 // replace by simple Bullet ?
712 if( bListSymbol )
713 //JP 14.08.96: cBulletChar benutzen, damit auf dem MAC
714 // richtig gemappt wird
715 sTxt.Fill( SVBT8ToByte( rAV.cbTextBefore )
716 + SVBT8ToByte( rAV.cbTextAfter ), cBulletChar );
719 else
720 { // Nummerierung / Aufzaehlung
721 bInsert = true;
722 // if( SVBT16ToShort( rAV.ftc ) == 1
723 // || SVBT16ToShort( rAV.ftc ) == 3 ){ // Symbol / WingDings
724 if( bListSymbol )
726 FontFamily eFamily;
727 String aName;
728 FontPitch ePitch;
730 if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName,
731 ePitch, eCharSet ) ){
732 // USHORT nSiz = ( SVBT16ToShort( rAV.hps ) ) ?
733 // SVBT16ToShort( rAV.hps ) : 24; // Groesse in 1/2 Pt
734 // darf nach JP nicht gesetzt werden, da immer die Size
735 // genommen wird, die am ZeilenAnfang benutzt wird
736 Font aFont;
737 aFont.SetName( aName );
738 aFont.SetFamily( eFamily );
739 // aFont.SetPitch( ePitch ); // darf nach JP nicht
740 aFont.SetCharSet( eCharSet );
741 rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
742 // if( rAV.ico ) // geht in UI und SWG-Writer/Reader nicht
743 // aFont.SetColor( Color( GetCol( rAV.ico ) ) );
744 rNum.SetBulletFont( &aFont );
746 // take only the very first character
747 if( rAV.cbTextBefore || rAV.cbTextAfter)
748 rNum.SetBulletChar( sTxt.GetChar( 0 ) );
749 else
750 rNum.SetBulletChar( 0x2190 );
754 if( bInsert )
756 if( rAV.cbTextBefore )
758 String sP( sTxt.Copy( 0, SVBT8ToByte( rAV.cbTextBefore ) ) );
759 rNum.SetPrefix( sP );
761 if( SVBT8ToByte( rAV.cbTextAfter ) )
763 String sP( rNum.GetSuffix() );
764 sP.Insert( sTxt.Copy( SVBT8ToByte( rAV.cbTextBefore ),
765 SVBT8ToByte( rAV.cbTextAfter ) ) );
766 rNum.SetSuffix( sP );
768 // Die Zeichen vor und hinter mehreren Ziffern koennen leider nicht uebernommen
769 // werden, da sie der Writer ganz anders behandelt und das Ergebnis i.A.
770 // schlechter als ohne waere.
774 // SetAnld bekommt einen WW-ANLD-Descriptor und einen Level und modifiziert
775 // die durch pNumR anggebeben NumRules. Wird benutzt fuer alles ausser
776 // Gliederung im Text
777 void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD* pAD, BYTE nSwLevel,
778 bool bOutLine)
780 SwNumFmt aNF;
781 if (pAD)
782 { // Es gibt einen Anld-Sprm
783 bAktAND_fNumberAcross = 0 != SVBT8ToByte( pAD->fNumberAcross );
784 WW8_ANLV &rAV = pAD->eAnlv;
785 SetBaseAnlv(aNF, rAV, nSwLevel); // Setze Basis-Format
786 SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine );// und Rest
788 pNumR->Set(nSwLevel, aNF);
791 //-------------------------------------------------------
792 // Kapitelnummerierung und Kapitelbullets
793 //-------------------------------------------------------
794 // Kapitelnummerierung findet in Styledefinionen statt. Sprm 13 gibt den Level
795 // an, Sprm 12 den Inhalt
797 SwNumRule* SwWW8ImplReader::GetStyRule()
799 if( pStyles->pStyRule ) // Bullet-Style bereits vorhanden
800 return pStyles->pStyRule;
802 const String aBaseName(CREATE_CONST_ASC( "WW8StyleNum" ));
803 const String aName( rDoc.GetUniqueNumRuleName( &aBaseName, false) );
805 // --> OD 2008-06-04 #i86652#
806 // USHORT nRul = rDoc.MakeNumRule( aName );
807 USHORT nRul = rDoc.MakeNumRule( aName, 0, FALSE,
808 SvxNumberFormat::LABEL_ALIGNMENT );
809 // <--
810 pStyles->pStyRule = rDoc.GetNumRuleTbl()[nRul];
811 // Auto == false-> Nummerierungsvorlage
812 pStyles->pStyRule->SetAutoRule(false);
814 return pStyles->pStyRule;
817 // Sprm 13
818 void SwWW8ImplReader::Read_ANLevelNo( USHORT, const BYTE* pData, short nLen )
820 nSwNumLevel = 0xff; // Default: ungueltig
822 if( nLen <= 0 )
823 return;
825 // StyleDef ?
826 if( pAktColl )
828 // nur fuer SwTxtFmtColl, nicht CharFmt
829 // WW: 0 = no Numbering
830 if (pCollA[nAktColl].bColl && *pData)
832 // Bereich WW:1..9 -> SW:0..8 keine Aufzaehlung / Nummerierung
834 if (*pData <= MAXLEVEL && *pData <= 9)
836 nSwNumLevel = *pData - 1;
837 if (!bNoAttrImport)
838 //((SwTxtFmtColl*)pAktColl)->SetOutlineLevel( nSwNumLevel ); //#outline level,zhaojianwei
839 ((SwTxtFmtColl*)pAktColl)->AssignToListLevelOfOutlineStyle( nSwNumLevel ); //<-end,zhaojianwei
840 // Bei WW-NoNumbering koennte auch NO_NUMBERING gesetzt
841 // werden. ( Bei normaler Nummerierung muss NO_NUM gesetzt
842 // werden: NO_NUM : Nummerierungs-Pause,
843 // NO_NUMBERING : ueberhaupt keine Nummerierung )
846 else if( *pData == 10 || *pData == 11 )
848 // Typ merken, der Rest geschieht bei Sprm 12
849 pStyles->nWwNumLevel = *pData;
853 else
855 //Not StyleDef
856 if (!bAnl)
857 StartAnl(pData); // Anfang der Gliederung / Aufzaehlung
858 NextAnlLine(pData);
862 void SwWW8ImplReader::Read_ANLevelDesc( USHORT, const BYTE* pData, short nLen ) // Sprm 12
864 if( !pAktColl || nLen <= 0 // nur bei Styledef
865 || !pCollA[nAktColl].bColl // CharFmt -> ignorieren
866 || ( nIniFlags & WW8FL_NO_OUTLINE ) ){
867 nSwNumLevel = 0xff;
868 return;
870 if( nSwNumLevel <= MAXLEVEL // Bereich WW:1..9 -> SW:0..8
871 && nSwNumLevel <= 9 ){ // keine Aufzaehlung / Nummerierung
873 // Falls bereits direkt oder durch
874 // Vererbung NumruleItems gesetzt sind,
875 // dann jetzt ausschalten #56163
876 pAktColl->SetFmtAttr( SwNumRuleItem() );
878 String aName(CREATE_CONST_ASC( "Outline" ));
879 // --> OD 2008-02-11 #newlistlevelattrs#
880 SwNumRule aNR( rDoc.GetUniqueNumRuleName( &aName ),
881 SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
882 OUTLINE_RULE );
883 // <--
884 aNR = *rDoc.GetOutlineNumRule();
886 SetAnld(&aNR, (WW8_ANLD*)pData, nSwNumLevel, true);
888 // fehlende Level muessen nicht aufgefuellt werden
890 rDoc.SetOutlineNumRule( aNR );
891 }else if( pStyles->nWwNumLevel == 10 || pStyles->nWwNumLevel == 11 ){
892 SwNumRule* pNR = GetStyRule();
893 SetAnld(pNR, (WW8_ANLD*)pData, 0, false);
894 pAktColl->SetFmtAttr( SwNumRuleItem( pNR->GetName() ) );
895 pCollA[nAktColl].bHasStyNumRule = true;
899 //-----------------------------------------
900 // Nummerierung / Aufzaehlung
901 //-----------------------------------------
903 // SetNumOlst() traegt die Numrules fuer diese Zeile ins SwNumFmt ein
904 // ( nur fuer Gliederungen im Text; Aufzaehlungen / Nummerierungen laufen
905 // ueber ANLDs )
906 // dabei wird die Info aus dem OLST geholt und nicht aus dem ANLD ( s.u. )
907 void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, BYTE nSwLevel)
909 SwNumFmt aNF;
910 WW8_ANLV &rAV = pO->rganlv[nSwLevel];
911 SetBaseAnlv(aNF, rAV, nSwLevel);
912 // ... und then the Strings
913 int nTxtOfs = 0;
914 BYTE i;
915 WW8_ANLV* pAV1; // search String-Positions
916 for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
918 nTxtOfs += SVBT8ToByte(pAV1->cbTextBefore)
919 + SVBT8ToByte(pAV1->cbTextAfter);
922 if (!bVer67)
923 nTxtOfs *= 2;
924 SetAnlvStrings(aNF, rAV, pO->rgch + nTxtOfs, true); // und rein
925 pNumR->Set(nSwLevel, aNF);
928 // der OLST kommt am Anfang jeder Section, die Gliederungen enthaelt. Die ANLDs,
929 // die an jeder Gliederungszeile haengen, enthalten nur Stuss, also werden die
930 // OLSTs waehrend der Section gemerkt, damit die Informationen beim Auftreten
931 // von Gliederungsabsaetzen zugreifbar ist.
932 void SwWW8ImplReader::Read_OLST( USHORT, const BYTE* pData, short nLen )
934 if (nLen <= 0)
936 delete pNumOlst, pNumOlst = 0;
937 return;
939 if (pNumOlst)
940 delete pNumOlst; // nur sicherheitshalber
941 pNumOlst = new WW8_OLST;
942 if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) ) // auffuellen, falls zu kurz
943 memset( pNumOlst, 0, sizeof( *pNumOlst ) );
944 *pNumOlst = *(WW8_OLST*)pData;
947 WW8LvlType GetNumType(BYTE nWwLevelNo)
949 WW8LvlType nRet = WW8_None;
950 if( nWwLevelNo == 12 )
951 nRet = WW8_Pause;
952 else if( nWwLevelNo == 10 )
953 nRet = WW8_Numbering;
954 else if( nWwLevelNo == 11 )
955 nRet = WW8_Sequence;
956 else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
957 nRet = WW8_Outline;
958 return nRet;
961 SwNumRule *ANLDRuleMap::GetNumRule(BYTE nNumType)
963 return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule);
966 void ANLDRuleMap::SetNumRule(SwNumRule *pRule, BYTE nNumType)
968 if (WW8_Numbering == nNumType)
969 mpNumberingNumRule = pRule;
970 else
971 mpOutlineNumRule = pRule;
975 // StartAnl wird am Anfang eines Zeilenbereichs gerufen,
976 // der Gliederung / Nummerierung / Aufzaehlung enthaelt
977 void SwWW8ImplReader::StartAnl(const BYTE* pSprm13)
979 bAktAND_fNumberAcross = false;
981 BYTE nT = static_cast< BYTE >(GetNumType(*pSprm13));
982 if (nT == WW8_Pause || nT == WW8_None)
983 return;
985 nWwNumType = nT;
986 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
988 // check for COL numbering:
989 const BYTE* pS12 = 0;// sprmAnld
990 String sNumRule;
992 if (pTableDesc)
994 sNumRule = pTableDesc->GetNumRuleName();
995 if (sNumRule.Len())
997 pNumRule = rDoc.FindNumRulePtr(sNumRule);
998 if (!pNumRule)
999 sNumRule.Erase();
1000 else
1002 // this is ROW numbering ?
1003 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1004 if (pS12 && 0 != SVBT8ToByte(((WW8_ANLD*)pS12)->fNumberAcross))
1005 sNumRule.Erase();
1010 if (!sNumRule.Len() && pCollA[nAktColl].bHasStyNumRule)
1012 sNumRule = pCollA[nAktColl].pFmt->GetNumRule().GetValue();
1013 pNumRule = rDoc.FindNumRulePtr(sNumRule);
1014 if (!pNumRule)
1015 sNumRule.Erase();
1018 if (!sNumRule.Len())
1020 if (!pNumRule)
1022 // --> OD 2008-06-04 #i86652#
1023 // pNumRule = rDoc.GetNumRuleTbl()[rDoc.MakeNumRule(sNumRule)];
1024 pNumRule = rDoc.GetNumRuleTbl()[
1025 rDoc.MakeNumRule( sNumRule, 0, FALSE,
1026 SvxNumberFormat::LABEL_ALIGNMENT ) ];
1027 // <--
1029 if (pTableDesc)
1031 if (!pS12)
1032 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1033 if (!pS12 || !SVBT8ToByte( ((WW8_ANLD*)pS12)->fNumberAcross))
1034 pTableDesc->SetNumRuleName(pNumRule->GetName());
1038 bAnl = true;
1040 // NumRules ueber Stack setzen
1041 pCtrlStck->NewAttr(*pPaM->GetPoint(),
1042 SfxStringItem(RES_FLTR_NUMRULE, pNumRule->GetName()));
1044 maANLDRules.SetNumRule(pNumRule, nWwNumType);
1047 // NextAnlLine() wird fuer jede Zeile einer
1048 // Gliederung / Nummerierung / Aufzaehlung einmal gerufen
1049 void SwWW8ImplReader::NextAnlLine(const BYTE* pSprm13)
1051 if (!bAnl)
1052 return;
1054 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
1056 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
1057 // sdw3
1059 // WW:10 = Nummerierung -> SW:0 & WW:11 = Auffzaehlung -> SW:0
1060 if (*pSprm13 == 10 || *pSprm13 == 11)
1062 nSwNumLevel = 0;
1063 if (!pNumRule->GetNumFmt(nSwNumLevel))
1065 // noch nicht definiert
1066 // sprmAnld o. 0
1067 const BYTE* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1068 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1071 else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // Bereich WW:1..9 -> SW:0..8
1073 nSwNumLevel = *pSprm13 - 1; // Gliederung
1074 // noch nicht definiert
1075 if (!pNumRule->GetNumFmt(nSwNumLevel))
1077 if (pNumOlst) // es gab ein OLST
1079 //Assure upper levels are set, #i9556#
1080 for (BYTE nI = 0; nI < nSwNumLevel; ++nI)
1082 if (!pNumRule->GetNumFmt(nI))
1083 SetNumOlst(pNumRule, pNumOlst, nI);
1086 SetNumOlst(pNumRule, pNumOlst , nSwNumLevel);
1088 else // kein Olst, nimm Anld
1090 // sprmAnld
1091 const BYTE* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1092 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1096 else
1097 nSwNumLevel = 0xff; // keine Nummer
1099 SwTxtNode* pNd = pPaM->GetNode()->GetTxtNode();
1100 if (nSwNumLevel < MAXLEVEL)
1101 pNd->SetAttrListLevel( nSwNumLevel );
1102 else
1104 pNd->SetAttrListLevel(0);
1105 pNd->SetCountedInList( false );
1109 void SwWW8ImplReader::StopAllAnl(bool bGoBack)
1111 //Of course we're not restarting, but we'll make use of our knowledge
1112 //of the implementation to do it.
1113 StopAnlToRestart(WW8_None, bGoBack);
1116 void SwWW8ImplReader::StopAnlToRestart(BYTE nNewType, bool bGoBack)
1118 if (bGoBack)
1120 SwPosition aTmpPos(*pPaM->GetPoint());
1121 pPaM->Move(fnMoveBackward, fnGoCntnt);
1122 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1123 *pPaM->GetPoint() = aTmpPos;
1125 else
1126 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1128 maANLDRules.mpNumberingNumRule = 0;
1130 #i18816#
1131 my take on this problem is that moving either way from an outline to a
1132 numbering doesn't halt the outline, while the numbering is always halted
1134 bool bNumberingNotStopOutline =
1135 (((nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1136 ((nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1137 if (!bNumberingNotStopOutline)
1138 maANLDRules.mpOutlineNumRule = 0;
1140 nSwNumLevel = 0xff;
1141 nWwNumType = WW8_None;
1142 bAnl = false;
1145 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand )
1147 *this = rBand;
1148 if( rBand.pTCs )
1150 pTCs = new WW8_TCell[nWwCols];
1151 memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1153 if( rBand.pSHDs )
1155 pSHDs = new WW8_SHD[nWwCols];
1156 memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1158 if( rBand.pNewSHDs )
1160 pNewSHDs = new sal_uInt32[nWwCols];
1161 memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32));
1163 memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1166 // ReadDef liest die Zellenpositionen und ggfs die Umrandungen eines Bandes ein
1167 void WW8TabBandDesc::ReadDef(bool bVer67, const BYTE* pS)
1169 if (!bVer67)
1170 pS++;
1172 short nLen = (INT16)SVBT16ToShort( pS - 2 ); // nicht schoen
1173 BYTE nCols = *pS; // Anzahl der Zellen
1174 short nOldCols = nWwCols;
1176 if( nCols > MAX_COL )
1177 return;
1179 nWwCols = nCols;
1181 const BYTE* pT = &pS[1];
1182 nLen --;
1183 int i;
1184 for(i=0; i<=nCols; i++, pT+=2 )
1185 nCenter[i] = (INT16)SVBT16ToShort( pT ); // X-Raender
1186 nLen -= 2 * ( nCols + 1 );
1187 if( nCols != nOldCols ) // andere Spaltenzahl
1189 delete[] pTCs, pTCs = 0;
1190 delete[] pSHDs, pSHDs = 0;
1191 delete[] pNewSHDs, pNewSHDs = 0;
1194 short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // wirklich abgespeichert
1196 if (!pTCs && nCols)
1198 // lege leere TCs an
1199 pTCs = new WW8_TCell[nCols];
1200 setcelldefaults(pTCs,nCols);
1203 if( nFileCols )
1205 // lies TCs ein
1208 Achtung: ab Ver8 ist ein reserve-ushort je TC eingefuegt und auch
1209 der Border-Code ist doppelt so gross, daher ist hier
1210 kein simples kopieren moeglich,
1211 d.h.: pTCs[i] = *pTc; geht leider nicht.
1213 Vorteil: Arbeitstruktur ist jetzt viel bequemer zu handhaben!
1215 WW8_TCell* pAktTC = pTCs;
1216 if( bVer67 )
1218 WW8_TCellVer6* pTc = (WW8_TCellVer6*)pT;
1219 for(i=0; i<nFileCols; i++, ++pAktTC,++pTc)
1221 if( i < nFileCols )
1222 { // TC aus File ?
1223 BYTE aBits1 = SVBT8ToByte( pTc->aBits1Ver6 );
1224 pAktTC->bFirstMerged = ( ( aBits1 & 0x01 ) != 0 );
1225 pAktTC->bMerged = ( ( aBits1 & 0x02 ) != 0 );
1226 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1227 pTc->rgbrcVer6[ WW8_TOP ].aBits1, sizeof( SVBT16 ) );
1228 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1229 pTc->rgbrcVer6[ WW8_LEFT ].aBits1, sizeof( SVBT16 ) );
1230 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1231 pTc->rgbrcVer6[ WW8_BOT ].aBits1, sizeof( SVBT16 ) );
1232 memcpy( pAktTC->rgbrc[ WW8_RIGHT ].aBits1,
1233 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1234 if( ( pAktTC->bMerged )
1235 && ( i > 0 ) )
1237 // Cell gemerged -> merken
1238 //bWWMergedVer6[i] = true;
1239 memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1,
1240 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1241 // right Border in vorige Zelle uebernehmen
1242 // Hier darf bExist nicht auf false gesetzt werden, da WW
1243 // in den Textboxen diese Zellen nicht mitzaehlt....
1248 else
1250 WW8_TCellVer8* pTc = (WW8_TCellVer8*)pT;
1251 for (int k = 0; k < nFileCols; ++k, ++pAktTC, ++pTc )
1253 UINT16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 );
1254 pAktTC->bFirstMerged = ( ( aBits1 & 0x0001 ) != 0 );
1255 pAktTC->bMerged = ( ( aBits1 & 0x0002 ) != 0 );
1256 pAktTC->bVertical = ( ( aBits1 & 0x0004 ) != 0 );
1257 pAktTC->bBackward = ( ( aBits1 & 0x0008 ) != 0 );
1258 pAktTC->bRotateFont = ( ( aBits1 & 0x0010 ) != 0 );
1259 pAktTC->bVertMerge = ( ( aBits1 & 0x0020 ) != 0 );
1260 pAktTC->bVertRestart = ( ( aBits1 & 0x0040 ) != 0 );
1261 pAktTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 );
1262 // am Rande: im aBits1 verstecken sich noch 7 Reserve-Bits,
1263 // anschliessend folgen noch 16 weitere Reserve-Bits
1265 // In Version 8 koennen wir alle Bordercodes auf einmal kopieren!
1266 memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) );
1270 // #i25071 In '97 text direction appears to be only set using TC properties
1271 // not with sprmTTextFlow so we need to cycle through the maDirections and
1272 // double check any non-default directions
1273 for (int k = 0; k < nCols; ++k)
1275 if(maDirections[k] == 4)
1277 if(pTCs[k].bVertical)
1279 if(pTCs[k].bBackward)
1280 maDirections[k] = 3;
1281 else
1282 maDirections[k] = 1;
1291 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const BYTE* pParamsTSetBRC)
1293 if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
1295 BYTE nitcFirst= pParamsTSetBRC[0];// first col to be changed
1296 BYTE nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1
1297 BYTE nFlag = *(pParamsTSetBRC+2);
1299 bool bChangeRight = (nFlag & 0x08) ? true : false;
1300 bool bChangeBottom = (nFlag & 0x04) ? true : false;
1301 bool bChangeLeft = (nFlag & 0x02) ? true : false;
1302 bool bChangeTop = (nFlag & 0x01) ? true : false;
1304 WW8_TCell* pAktTC = pTCs + nitcFirst;
1305 if( bVer67 )
1307 WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3);
1309 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1311 if( bChangeTop )
1312 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1313 pBRC->aBits1,
1314 sizeof( SVBT16 ) );
1315 if( bChangeLeft )
1316 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1317 pBRC->aBits1,
1318 sizeof( SVBT16 ) );
1319 if( bChangeBottom )
1320 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1321 pBRC->aBits1,
1322 sizeof( SVBT16 ) );
1323 if( bChangeRight )
1324 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1325 pBRC->aBits1,
1326 sizeof( SVBT16 ) );
1329 else
1331 WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3);
1333 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1335 if( bChangeTop )
1336 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1337 pBRC->aBits1,
1338 sizeof( WW8_BRC ) );
1339 if( bChangeLeft )
1340 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1341 pBRC->aBits1,
1342 sizeof( WW8_BRC ) );
1343 if( bChangeBottom )
1344 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1345 pBRC->aBits1,
1346 sizeof( WW8_BRC ) );
1347 if( bChangeRight )
1348 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1349 pBRC->aBits1,
1350 sizeof( WW8_BRC ) );
1359 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const BYTE* pParams)
1361 // sprmTTableBorders
1362 if( bVer67 )
1364 for( int i = 0; i < 6; ++i )
1366 aDefBrcs[i].aBits1[0] = pParams[ 2*i ];
1367 aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ];
1370 else // aDefBrcs = *(BRC(*)[6])pS;
1371 memcpy( aDefBrcs, pParams, 24 );
1374 void WW8TabBandDesc::ProcessSprmTDxaCol(const BYTE* pParamsTDxaCol)
1376 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1377 // whose index is within a certain range to be a certain value.
1379 if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s)
1381 BYTE nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1382 BYTE nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1
1383 short nDxaCol = (INT16)SVBT16ToShort( pParamsTDxaCol + 2 );
1384 short nOrgWidth;
1385 short nDelta;
1387 for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1389 nOrgWidth = nCenter[i+1] - nCenter[i];
1390 nDelta = nDxaCol - nOrgWidth;
1391 for( int j = i+1; j <= nWwCols; j++ )
1393 nCenter[j] = nCenter[j] + nDelta;
1399 void WW8TabBandDesc::ProcessSprmTInsert(const BYTE* pParamsTInsert)
1401 if( nWwCols && pParamsTInsert ) // set one or more cell length(s)
1403 BYTE nitcInsert = pParamsTInsert[0]; // position at which to insert
1404 if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index
1405 return;
1406 BYTE nctc = pParamsTInsert[1]; // number of cells
1407 USHORT ndxaCol = SVBT16ToShort( pParamsTInsert+2 );
1409 short nNewWwCols;
1410 if (nitcInsert > nWwCols)
1412 nNewWwCols = nitcInsert+nctc;
1413 //if new count would be outside max possible count, clip it, and calc a new replacement
1414 //legal nctc
1415 if (nNewWwCols > MAX_COL)
1417 nNewWwCols = MAX_COL;
1418 nctc = ::sal::static_int_cast<BYTE>(nNewWwCols-nitcInsert);
1421 else
1423 nNewWwCols = nWwCols+nctc;
1424 //if new count would be outside max possible count, clip it, and calc a new replacement
1425 //legal nctc
1426 if (nNewWwCols > MAX_COL)
1428 nNewWwCols = MAX_COL;
1429 nctc = ::sal::static_int_cast<BYTE>(nNewWwCols-nWwCols);
1433 WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1434 setcelldefaults(pTC2s, nNewWwCols);
1436 if (pTCs)
1438 memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1439 delete[] pTCs;
1441 pTCs = pTC2s;
1443 //If we have to move some cells
1444 if (nitcInsert <= nWwCols)
1446 // adjust the left x-position of the dummy at the very end
1447 nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1448 for( int i = nWwCols-1; i >= nitcInsert; i--)
1450 // adjust the left x-position
1451 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1453 // adjust the cell's borders
1454 pTCs[i + nctc] = pTCs[i];
1458 //if itcMac is larger than full size, fill in missing ones first
1459 for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1460 nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1462 //now add in our new cells
1463 for( int j = 0;j < nctc; j++)
1464 nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1466 nWwCols = nNewWwCols;
1470 void WW8TabBandDesc::ProcessDirection(const BYTE* pParams)
1472 sal_uInt8 nStartCell = *pParams++;
1473 sal_uInt8 nEndCell = *pParams++;
1474 sal_uInt16 nCode = SVBT16ToShort(pParams);
1476 ASSERT(nStartCell < nEndCell, "not as I thought");
1477 ASSERT(nEndCell < MAX_COL + 1, "not as I thought");
1478 if (nStartCell > MAX_COL)
1479 return;
1480 if (nEndCell > MAX_COL + 1)
1481 nEndCell = MAX_COL + 1;
1483 for (;nStartCell < nEndCell; ++nStartCell)
1484 maDirections[nStartCell] = nCode;
1487 void WW8TabBandDesc::ProcessSpacing(const BYTE* pParams)
1489 BYTE nLen = pParams ? *(pParams - 1) : 0;
1490 ASSERT(nLen == 6, "Unexpected spacing len");
1491 if (nLen != 6)
1492 return;
1493 mbHasSpacing=true;
1494 #ifndef PRODUCT
1495 BYTE nWhichCell =
1496 #endif
1497 *pParams++;
1498 ASSERT(nWhichCell == 0, "Expected cell to be 0!");
1499 *pParams++; //unknown byte
1501 BYTE nSideBits = *pParams++;
1502 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1503 *pParams++; //unknown byte
1504 USHORT nValue = SVBT16ToShort( pParams );
1505 for (int i = wwTOP; i <= wwRIGHT; i++)
1507 switch (nSideBits & (1 << i))
1509 case 1 << wwTOP:
1510 mnDefaultTop = nValue;
1511 break;
1512 case 1 << wwLEFT:
1513 mnDefaultLeft = nValue;
1514 break;
1515 case 1 << wwBOTTOM:
1516 mnDefaultBottom = nValue;
1517 break;
1518 case 1 << wwRIGHT:
1519 mnDefaultRight = nValue;
1520 break;
1521 case 0:
1522 break;
1523 default:
1524 ASSERT(!this, "Impossible");
1525 break;
1530 void WW8TabBandDesc::ProcessSpecificSpacing(const BYTE* pParams)
1532 BYTE nLen = pParams ? *(pParams - 1) : 0;
1533 ASSERT(nLen == 6, "Unexpected spacing len");
1534 if (nLen != 6)
1535 return;
1536 BYTE nWhichCell = *pParams++;
1537 ASSERT(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1538 if (nWhichCell >= MAX_COL + 1)
1539 return;
1541 *pParams++; //unknown byte
1542 BYTE nSideBits = *pParams++;
1543 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1544 nOverrideSpacing[nWhichCell] |= nSideBits;
1546 ASSERT(nOverrideSpacing[nWhichCell] < 0x10,
1547 "Unexpected value for nSideBits");
1548 #ifndef PRODUCT
1549 BYTE nUnknown2 =
1550 #endif
1551 *pParams++;
1552 ASSERT(nUnknown2 == 0x3, "Unexpected value for spacing2");
1553 USHORT nValue = SVBT16ToShort( pParams );
1555 for (int i=0; i < 4; i++)
1557 if (nSideBits & (1 << i))
1558 nOverrideValues[nWhichCell][i] = nValue;
1562 void WW8TabBandDesc::ProcessSprmTDelete(const BYTE* pParamsTDelete)
1564 if( nWwCols && pParamsTDelete ) // set one or more cell length(s)
1566 BYTE nitcFirst= pParamsTDelete[0]; // first col to be deleted
1567 if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1568 return;
1569 BYTE nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1570 if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1571 return;
1574 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1575 * greater than or equal to itcLim to be moved
1577 int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1579 if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1581 WW8_TCell* pAktTC = pTCs + nitcFirst;
1582 int i = 0;
1583 while( i < nShlCnt )
1585 // adjust the left x-position
1586 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1588 // adjust the cell's borders
1589 *pAktTC = pTCs[ nitcLim + i];
1591 ++i;
1592 ++pAktTC;
1594 // adjust the left x-position of the dummy at the very end
1595 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1598 short nCellsDeleted = nitcLim - nitcFirst;
1599 //clip delete request to available number of cells
1600 if (nCellsDeleted > nWwCols)
1601 nCellsDeleted = nWwCols;
1602 nWwCols -= nCellsDeleted;
1606 // ReadShd liest ggfs die Hintergrundfarben einer Zeile ein.
1607 // Es muss vorher ReadDef aufgerufen worden sein
1608 void WW8TabBandDesc::ReadShd(const BYTE* pS )
1610 BYTE nLen = pS ? *(pS - 1) : 0;
1611 if( !nLen )
1612 return;
1614 if( !pSHDs )
1616 pSHDs = new WW8_SHD[nWwCols];
1617 memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) );
1620 short nAnz = nLen >> 1;
1621 if (nAnz > nWwCols)
1622 nAnz = nWwCols;
1624 SVBT16* pShd;
1625 int i;
1626 for(i=0, pShd = (SVBT16*)pS; i<nAnz; i++, pShd++ )
1627 pSHDs[i].SetWWValue( *pShd );
1630 void WW8TabBandDesc::ReadNewShd(const BYTE* pS, bool bVer67)
1632 BYTE nLen = pS ? *(pS - 1) : 0;
1633 if (!nLen)
1634 return;
1636 if (!pNewSHDs)
1637 pNewSHDs = new sal_uInt32[nWwCols];
1639 short nAnz = nLen / 10; //10 bytes each
1640 if (nAnz > nWwCols)
1641 nAnz = nWwCols;
1643 int i=0;
1644 while (i < nAnz)
1645 pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1647 while (i < nWwCols)
1648 pNewSHDs[i++] = COL_AUTO;
1651 void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols)
1653 memset( pCells, 0, nCols * sizeof( WW8_TCell ) );
1656 const BYTE *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1658 const BYTE *pParams;
1659 if (bVer67)
1660 pParams = pPap->HasSprm(24);
1661 else
1663 if (0 == (pParams = pPap->HasSprm(0x244B)))
1664 pParams = pPap->HasSprm(0x2416);
1666 return pParams;
1669 enum wwTableSprm
1671 sprmNil,
1673 sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable,
1674 sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc,
1675 sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
1676 sprmTDxaGapHalf, sprmTTableBorders,
1678 sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing
1681 wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1683 switch (eVer)
1685 case ww::eWW8:
1686 switch (nId)
1688 case 0xF614:
1689 return sprmTTableWidth;
1690 case 0x7629:
1691 return sprmTTextFlow;
1692 case 0x3403:
1693 return sprmTFCantSplit;
1694 case 0x3404:
1695 return sprmTTableHeader;
1696 case 0x3466:
1697 return sprmTFCantSplit90;
1698 case 0x5400:
1699 return sprmTJc;
1700 case 0x560B:
1701 return sprmTFBiDi;
1702 case 0x5622:
1703 return sprmTDelete;
1704 case 0x7621:
1705 return sprmTInsert;
1706 case 0x7623:
1707 return sprmTDxaCol;
1708 case 0x9407:
1709 return sprmTDyaRowHeight;
1710 case 0x9601:
1711 return sprmTDxaLeft;
1712 case 0x9602:
1713 return sprmTDxaGapHalf;
1714 case 0xD605:
1715 return sprmTTableBorders;
1716 case 0xD608:
1717 return sprmTDefTable;
1718 case 0xD609:
1719 return sprmTDefTableShd;
1720 case 0xD612:
1721 return sprmTDefTableNewShd;
1722 case 0xD620:
1723 return sprmTSetBrc;
1724 case 0xD632:
1725 return sprmTSpacing;
1726 case 0xD634:
1727 return sprmTNewSpacing;
1729 break;
1730 case ww::eWW7:
1731 case ww::eWW6:
1732 switch (nId)
1734 case 182:
1735 return sprmTJc;
1736 case 183:
1737 return sprmTDxaLeft;
1738 case 184:
1739 return sprmTDxaGapHalf;
1740 case 186:
1741 return sprmTTableHeader;
1742 case 187:
1743 return sprmTTableBorders;
1744 case 189:
1745 return sprmTDyaRowHeight;
1746 case 190:
1747 return sprmTDefTable;
1748 case 191:
1749 return sprmTDefTableShd;
1750 case 193:
1751 return sprmTSetBrc;
1752 case 194:
1753 return sprmTInsert;
1754 case 195:
1755 return sprmTDelete;
1756 case 196:
1757 return sprmTDxaCol;
1759 break;
1760 case ww::eWW2:
1761 switch (nId)
1763 case 146:
1764 return sprmTJc;
1765 case 147:
1766 return sprmTDxaLeft;
1767 case 148:
1768 return sprmTDxaGapHalf;
1769 case 153:
1770 return sprmTDyaRowHeight;
1771 case 154:
1772 return sprmTDefTable;
1773 case 155:
1774 return sprmTDefTableShd;
1775 case 157:
1776 return sprmTSetBrc;
1777 case 158:
1778 return sprmTInsert;
1779 case 159:
1780 return sprmTDelete;
1781 case 160:
1782 return sprmTDxaCol;
1784 break;
1786 return sprmNil;
1789 WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
1790 mpOldRedlineStack(0),
1791 pIo(pIoClass),
1792 pFirstBand(0),
1793 pActBand(0),
1794 pTmpPos(0),
1795 pTblNd(0),
1796 pTabLines(0),
1797 pTabLine(0),
1798 pTabBoxes(0),
1799 pTabBox(0),
1800 pMergeGroups(0),
1801 pAktWWCell(0),
1802 nRows(0),
1803 nDefaultSwCols(0),
1804 nBands(0),
1805 nMinLeft(0),
1806 nConvertedLeft(0),
1807 nMaxRight(0),
1808 nSwWidth(0),
1809 nPreferredWidth(0),
1810 nOrgDxaLeft(0),
1811 bOk(true),
1812 bClaimLineFmt(false),
1813 eOri(text::HoriOrientation::NONE),
1814 bIsBiDi(false),
1815 nAktRow(0),
1816 nAktBandRow(0),
1817 nAktCol(0),
1818 nRowsToRepeat(0),
1819 pTable(0),
1820 pParentPos(0),
1821 pFlyFmt(0),
1822 aItemSet(pIo->rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1)
1824 pIo->bAktAND_fNumberAcross = false;
1826 static const sal_Int16 aOriArr[] =
1828 text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1831 bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion());
1832 WW8_TablePos aTabPos;
1834 WW8PLCFxSave1 aSave;
1835 pIo->pPlcxMan->GetPap()->Save( aSave );
1837 WW8PLCFx_Cp_FKP* pPap = pIo->pPlcxMan->GetPapPLCF();
1839 eOri = text::HoriOrientation::LEFT;
1841 WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1843 wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion());
1845 // process pPap until end of table found
1848 short nTabeDxaNew = SHRT_MAX;
1849 bool bTabRowJustRead = false;
1850 const BYTE* pShadeSprm = 0;
1851 const BYTE* pNewShadeSprm = 0;
1852 WW8_TablePos *pTabPos = 0;
1854 // Suche Ende einer TabZeile
1855 if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->nInTable)))
1857 bOk = false;
1858 break;
1861 // Get the SPRM chains:
1862 // first from PAP and then from PCD (of the Piece Table)
1863 WW8PLCFxDesc aDesc;
1864 pPap->GetSprms( &aDesc );
1865 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1867 const BYTE* pParams = aSprmIter.GetAktParams();
1868 for (int nLoop = 0; nLoop < 2; ++nLoop)
1870 bool bRepeatedSprm = false;
1871 while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams()))
1873 sal_uInt16 nId = aSprmIter.GetAktId();
1874 wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion());
1875 switch (eSprm)
1877 case sprmTTableWidth:
1879 const BYTE b0 = pParams[0];
1880 const BYTE b1 = pParams[1];
1881 const BYTE b2 = pParams[2];
1882 if (b0 == 3) // Twips
1883 nPreferredWidth = b2 * 0x100 + b1;
1885 break;
1886 case sprmTTextFlow:
1887 pNewBand->ProcessDirection(pParams);
1888 break;
1889 case sprmTFCantSplit:
1890 pNewBand->bCantSplit = *pParams;
1891 bClaimLineFmt = true;
1892 break;
1893 case sprmTFCantSplit90:
1894 pNewBand->bCantSplit90 = *pParams;
1895 bClaimLineFmt = true;
1896 break;
1897 case sprmTTableBorders:
1898 pNewBand->ProcessSprmTTableBorders(bOldVer, pParams);
1899 break;
1900 case sprmTTableHeader:
1901 if (!bRepeatedSprm)
1903 nRowsToRepeat++;
1904 bRepeatedSprm = true;
1906 break;
1907 case sprmTJc:
1908 // sprmTJc - Justification Code
1909 if (nRows == 0)
1910 eOri = aOriArr[*pParams & 0x3];
1911 break;
1912 case sprmTFBiDi:
1913 bIsBiDi = SVBT16ToShort(pParams) ? true : false;
1914 break;
1915 case sprmTDxaGapHalf:
1916 pNewBand->nGapHalf = (INT16)SVBT16ToShort( pParams );
1917 break;
1918 case sprmTDyaRowHeight:
1919 pNewBand->nLineHeight = (INT16)SVBT16ToShort( pParams );
1920 bClaimLineFmt = true;
1921 break;
1922 case sprmTDefTable:
1923 pNewBand->ReadDef(bOldVer, pParams);
1924 bTabRowJustRead = true;
1925 break;
1926 case sprmTDefTableShd:
1927 pShadeSprm = pParams;
1928 break;
1929 case sprmTDefTableNewShd:
1930 pNewShadeSprm = pParams;
1931 break;
1932 case sprmTDxaLeft:
1933 // our Writer cannot shift single table lines
1934 // horizontally so we have to find the smallest
1935 // parameter (meaning the left-most position) and then
1936 // shift the whole table to that margin (see below)
1938 short nDxaNew = (INT16)SVBT16ToShort( pParams );
1939 nOrgDxaLeft = nDxaNew;
1940 if( nDxaNew < nTabeDxaNew )
1941 nTabeDxaNew = nDxaNew;
1943 break;
1944 case sprmTSetBrc:
1945 pNewBand->ProcessSprmTSetBRC(bOldVer, pParams);
1946 break;
1947 case sprmTDxaCol:
1948 pNewBand->ProcessSprmTDxaCol(pParams);
1949 break;
1950 case sprmTInsert:
1951 pNewBand->ProcessSprmTInsert(pParams);
1952 break;
1953 case sprmTDelete:
1954 pNewBand->ProcessSprmTDelete(pParams);
1955 break;
1956 case sprmTNewSpacing:
1957 pNewBand->ProcessSpacing(pParams);
1958 break;
1959 case sprmTSpacing:
1960 pNewBand->ProcessSpecificSpacing(pParams);
1961 break;
1962 default:
1965 aSprmIter++;
1968 if( !nLoop )
1970 pPap->GetPCDSprms( aDesc );
1971 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1975 // #55171: WW-Tabellen koennen Fly-Wechsel beinhalten daher hier
1976 // Tabellen abbrechen und neu beginnen noch steht *pPap noch vor
1977 // TabRowEnd, daher kann TestApo() mit letztem Parameter false und
1978 // damit wirksam gerufen werden.
1980 if (bTabRowJustRead)
1982 if (pShadeSprm)
1983 pNewBand->ReadShd(pShadeSprm);
1984 if (pNewShadeSprm)
1985 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
1988 if( nTabeDxaNew < SHRT_MAX )
1990 short* pCenter = pNewBand->nCenter;
1991 short firstDxaCenter = *pCenter;
1992 for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
1994 // #i30298# Use sprmTDxaLeft to adjust the left indent
1995 // #i40461# Use dxaGapHalf during calculation
1996 *pCenter +=
1997 (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
2001 if (!pActBand)
2002 pActBand = pFirstBand = pNewBand;
2003 else
2005 pActBand->pNextBand = pNewBand;
2006 pActBand = pNewBand;
2008 nBands++;
2010 pNewBand = new WW8TabBandDesc;
2012 nRows++;
2013 pActBand->nRows++;
2015 //Seek our pap to its next block of properties
2016 WW8PLCFxDesc aRes;
2017 aRes.pMemPos = 0;
2018 aRes.nStartPos = nStartCp;
2020 if (!(pPap->SeekPos(aRes.nStartPos)))
2022 aRes.nEndPos = WW8_CP_MAX;
2023 pPap->SetDirty(true);
2025 pPap->GetSprms(&aRes);
2026 pPap->SetDirty(false);
2028 //Are we at the end of available properties
2029 if (
2030 !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
2031 aRes.nStartPos == WW8_CP_MAX
2034 bOk = false;
2035 break;
2038 //Are we still in a table cell
2039 pParams = HasTabCellSprm(pPap, bOldVer);
2040 const BYTE *pLevel = pPap->HasSprm(0x6649);
2041 // InTable
2042 if (!pParams || (1 != *pParams) ||
2043 (pLevel && (*pLevel <= pIo->nInTable)))
2045 break;
2048 //Get the end of row new table positioning data
2049 WW8_CP nMyStartCp=nStartCp;
2050 if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->nInTable))
2051 if (SwWW8ImplReader::ParseTabPos(&aTabPos, pPap))
2052 pTabPos = &aTabPos;
2054 //Move back to this cell
2055 aRes.pMemPos = 0;
2056 aRes.nStartPos = nStartCp;
2058 // #114237 PlcxMan currently points too far ahead so we need to bring
2059 // it back to where we are trying to make a table
2060 pIo->pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2061 if (!(pPap->SeekPos(aRes.nStartPos)))
2063 aRes.nEndPos = WW8_CP_MAX;
2064 pPap->SetDirty(true);
2066 pPap->GetSprms(&aRes);
2067 pPap->SetDirty(false);
2069 //Does this row match up with the last row closely enough to be
2070 //considered part of the same table
2071 ApoTestResults aApo = pIo->TestApo(pIo->nInTable + 1, false, pTabPos);
2074 ##513##, #79474# If this is not sufficent, then we should look at
2075 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2076 part of this table, but instead is an absolutely positioned table
2077 outside of this one
2079 if (aApo.mbStopApo)
2080 break;
2081 if (aApo.mbStartApo)
2083 //if there really is a fly here, and not a "null" fly then break.
2084 WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos);
2085 if (pNewFly)
2086 delete pNewFly;
2087 else
2088 break;
2091 nStartCp = aRes.nEndPos;
2093 while( 1 );
2095 if( bOk )
2097 if( pActBand->nRows > 1 )
2099 // Letztes Band hat mehr als 1 Zeile
2100 delete pNewBand;
2101 pNewBand = new WW8TabBandDesc( *pActBand ); // neues machen
2102 pActBand->nRows--; // wegen Sonderbehandlung Raender-Defaults
2103 pNewBand->nRows = 1;
2104 pActBand->pNextBand = pNewBand; // am Ende einschleifen
2105 nBands++;
2106 pNewBand = 0; // nicht loeschen
2108 CalcDefaults();
2110 delete pNewBand;
2112 pIo->pPlcxMan->GetPap()->Restore( aSave );
2115 WW8TabDesc::~WW8TabDesc()
2117 WW8TabBandDesc* pR = pFirstBand;
2118 while(pR)
2120 WW8TabBandDesc* pR2 = pR->pNextBand;
2121 delete pR;
2122 pR = pR2;
2125 delete pParentPos;
2126 delete pMergeGroups;
2129 void WW8TabDesc::CalcDefaults()
2131 short nMinCols = SHRT_MAX;
2132 WW8TabBandDesc* pR;
2134 nMinLeft = SHRT_MAX;
2135 nMaxRight = SHRT_MIN;
2138 #101175#
2139 If we are an honestly inline centered table, then the normal rules of
2140 engagement for left and right margins do not apply. The multiple rows are
2141 centered regardless of the actual placement of rows, so we cannot have
2142 mismatched rows as is possible in other configurations.
2144 e.g. change the example bugdoc in word from text wrapping of none (inline)
2145 to around (in frame (bApo)) and the table splits into two very disjoint
2146 rows as the beginning point of each row are very different
2148 if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER))
2150 for (pR = pFirstBand; pR; pR = pR->pNextBand)
2151 for( short i = pR->nWwCols; i >= 0; --i)
2152 pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2155 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2156 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2158 if( pR->nCenter[0] < nMinLeft )
2159 nMinLeft = pR->nCenter[0];
2161 for( short i = 0; i < pR->nWwCols; i++ )
2164 #74387# If the margins are so large as to make the displayable
2165 area inside them smaller than the minimum allowed then adjust the
2166 width to fit. But only do it if the two cells are not the exact
2167 same value, if they are then the cell does not really exist and will
2168 be blended together into the same cell through the use of the
2169 nTrans(late) array.
2170 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2172 int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2173 if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2175 pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
2179 if( pR->nCenter[pR->nWwCols] > nMaxRight )
2180 nMaxRight = pR->nCenter[pR->nWwCols];
2182 nSwWidth = nMaxRight - nMinLeft;
2184 // #109830# If the table is right aligned we need to align all rows to the
2185 // row that has the furthest right point
2187 if(eOri == text::HoriOrientation::RIGHT)
2189 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2191 int adjust = nMaxRight - pR->nCenter[pR->nWwCols];
2192 for( short i = 0; i < pR->nWwCols + 1; i++ )
2194 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2200 // 2. Durchlauf: Zahl der Writer-Spalten feststellen Die Zahl der Writer
2201 // Spalten kann um bis zu 2 hoeher sein als im WW, da der SW im Gegensatz
2202 // zu WW keine ausgefransten linken und rechten Raender kann und diese
2203 // durch leere Boxen aufgefuellt werden. Durch nichtexistente Zellen
2204 // koennen auch Zellen wegfallen
2206 // 3. Durchlauf: Wo noetig die Umrandungen durch die Defaults ersetzen
2207 nConvertedLeft = nMinLeft;
2209 short nLeftMaxThickness = 0, nRightMaxThickness=0;
2210 for( pR = pFirstBand ; pR; pR = pR->pNextBand )
2212 if( !pR->pTCs )
2214 pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2215 memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) );
2217 for (int k = 0; k < pR->nWwCols; ++k)
2219 WW8_TCell* pT = &pR->pTCs[k];
2220 int i, j;
2221 for( i = 0; i < 4; i ++ )
2223 if (pT->rgbrc[i].IsZeroed(pIo->bVer67))
2225 // if shadow is set, its invalid
2226 j = i;
2227 switch( i )
2229 case 0:
2230 // Aussen oben / Innen waagerecht
2231 j = (pR == pFirstBand) ? 0 : 4;
2232 break;
2233 case 1:
2234 // Aussen links / Innen senkrecht
2235 j = k ? 5 : 1;
2236 break;
2237 case 2:
2238 // Aussen unten / Innen waagerecht
2239 j = pR->pNextBand ? 4 : 2;
2240 break;
2241 case 3:
2242 // Aussen rechts/ Innen senkrecht
2243 j = (k == pR->nWwCols - 1) ? 3 : 5;
2244 break;
2246 // mangel mit Defaults ueber
2247 pT->rgbrc[i] = pR->aDefBrcs[j];
2252 Similiar to graphics and other elements word does not totally
2253 factor the width of the border into its calculations of size, we
2254 do so we must adjust out widths and other dimensions to fit. It
2255 appears that what occurs is that the last cell's right margin if
2256 the margin width that is not calculated into winwords table
2257 dimensions, so in that case increase the table to include the
2258 extra width of the right margin.
2260 if ( pIo->bVer67 ?
2261 !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20)
2262 : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000))
2264 short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2265 DetermineBorderProperties(pIo->bVer67);
2266 pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2267 if (nThickness > nRightMaxThickness)
2268 nRightMaxThickness = nThickness;
2272 The left space of the table is in nMinLeft, but again this
2273 does not consider the margin thickness to its left in the
2274 placement value, so get the thickness of the left border,
2275 half is placed to the left of the nominal left side, and
2276 half to the right.
2278 if ( pIo->bVer67 ?
2279 !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20)
2280 : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000))
2282 short nThickness = pR->pTCs[0].rgbrc[1].
2283 DetermineBorderProperties(pIo->bVer67);
2284 if (nThickness > nLeftMaxThickness)
2285 nLeftMaxThickness = nThickness;
2288 nSwWidth = nSwWidth + nRightMaxThickness;
2289 nMaxRight = nMaxRight + nRightMaxThickness;
2290 nConvertedLeft = nMinLeft-(nLeftMaxThickness/2);
2292 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2294 pR->nSwCols = pR->nWwCols;
2295 pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY;
2296 pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2298 short nAddCols = pR->bLEmptyCol + pR->bREmptyCol;
2299 USHORT i;
2300 USHORT j = ( pR->bLEmptyCol ) ? 1 : 0;
2301 for (i = 0; i < pR->nWwCols; ++i)
2303 pR->nTransCell[i] = (INT8)j;
2304 if ( pR->nCenter[i] < pR->nCenter[i+1] )
2306 pR->bExist[i] = true;
2307 j++;
2309 else
2311 pR->bExist[i] = false;
2312 nAddCols--;
2316 ASSERT(i,"no columns in row ?");
2319 #96345#
2320 If the last cell was "false" then there is no valid cell following it,
2321 so the default mapping forward wont't work. So map it (and
2322 contigious invalid cells backwards to the last valid cell instead.
2324 if (i && pR->bExist[i-1] == false)
2326 USHORT k=i-1;
2327 while (k && pR->bExist[k] == false)
2328 k--;
2329 for (USHORT n=k+1;n<i;n++)
2330 pR->nTransCell[n] = pR->nTransCell[k];
2333 pR->nTransCell[i++] = (INT8)(j++); // Wird u.a. wegen bREmptyCol um
2334 pR->nTransCell[i] = (INT8)j; // max. 2 ueberindiziert
2336 pR->nSwCols = pR->nSwCols + nAddCols;
2337 if( pR->nSwCols < nMinCols )
2338 nMinCols = pR->nSwCols;
2342 #i9718#
2343 Find the largest of the borders on cells that adjoin top bottom and remove
2344 the val from the top and put in on the bottom cell. I can't seem to make
2345 disjoint upper and lowers to see what happens there.
2348 /* #i29550# FME 2004-06-02 Removed this code because of the implementation
2349 of the collapsing table borders model. So this should not be necessary
2350 anymore. */
2352 /* for (pR = pFirstBand; pR; pR = pR->pNextBand)
2354 WW8TabBandDesc *pNext = pR->pNextBand;
2355 if (!pNext)
2356 break;
2358 for (int k = 0; k < pR->nWwCols; ++k)
2360 WW8_BRC &rAbove = pR->pTCs[k].rgbrc[WW8_BOT];
2361 short nAboveThick = rAbove.IsEmpty(pIo->bVer67) ?
2362 0 : rAbove.DetermineBorderProperties(pIo->bVer67);
2363 short nUpperLeft = pR->nCenter[k];
2364 short nUpperRight = pR->nCenter[k+1];
2366 for (int l = 0; l < pNext->nWwCols; ++l)
2368 short nLowerLeft = pNext->nCenter[l];
2369 short nLowerRight = pNext->nCenter[l+1];
2371 if ((nLowerLeft < nUpperLeft) || (nLowerRight > nUpperRight))
2372 continue;
2374 WW8_BRC &rBelow = pNext->pTCs[l].rgbrc[WW8_TOP];
2375 short nBelowThick = rBelow.IsEmpty(pIo->bVer67) ?
2376 0 : rBelow.DetermineBorderProperties(pIo->bVer67);
2377 if (nAboveThick > nBelowThick)
2378 rBelow = rAbove;
2381 rAbove = WW8_BRC();
2383 } */
2385 if (nMinLeft && ((!bIsBiDi && text::HoriOrientation::LEFT == eOri) || (bIsBiDi && text::HoriOrientation::RIGHT == eOri)))
2386 eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2388 nDefaultSwCols = nMinCols; // da Zellen einfuegen billiger ist als Mergen
2389 if( nDefaultSwCols == 0 )
2390 bOk = false;
2391 pActBand = pFirstBand;
2392 nAktBandRow = 0;
2393 ASSERT( pActBand, "pActBand ist 0" );
2396 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt)
2398 SwFrmFmt* pApply = pFrmFmt;
2399 if (!pApply )
2400 pApply = pTable->GetFrmFmt();
2401 ASSERT(pApply,"No frame");
2402 pApply->SetFmtAttr(aItemSet);
2403 if (pFrmFmt)
2405 SwFmtFrmSize aSize = pFrmFmt->GetFrmSize();
2406 aSize.SetHeightSizeType(ATT_MIN_SIZE);
2407 aSize.SetHeight(MINLAY);
2408 pFrmFmt->SetFmtAttr(aSize);
2409 pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL));
2413 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2414 const SwNode &rNode)
2416 ASSERT(!maSegments.empty(),
2417 "should not be possible, must be at least one segment");
2418 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2419 maSegments.back().maStart = SwNodeIndex(rNode);
2422 void WW8TabDesc::CreateSwTable()
2424 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
2426 // if there is already some content on the Node append new node to ensure
2427 // that this content remains ABOVE the table
2428 SwPosition* pPoint = pIo->pPaM->GetPoint();
2429 bool bInsNode = pPoint->nContent.GetIndex() ? true : false;
2430 bool bSetMinHeight = false;
2433 #i8062#
2434 Set fly anchor to its anchor pos, so that if a table starts immediately
2435 at this position a new node will be inserted before inserting the table.
2437 if (!bInsNode && pIo->pFmtOfJustInsertedApo)
2439 const SwPosition* pAPos =
2440 pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor();
2441 if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2443 bInsNode = true;
2444 bSetMinHeight = true;
2446 SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround());
2447 aSur.SetAnchorOnly(true);
2448 pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur);
2452 if (bSetMinHeight == true)
2454 // minimize Fontsize to minimize height growth of the header/footer
2455 // set font size to 1 point to minimize y-growth of Hd/Ft
2456 SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2457 pIo->NewAttr( aSz );
2458 pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2461 if (bInsNode)
2462 pIo->AppendTxtNode(*pPoint);
2464 pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() );
2466 // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist
2467 // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen
2468 // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender,
2469 // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen
2470 pTable = pIo->rDoc.InsertTable(
2471 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2472 *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, FALSE, TRUE );
2474 ASSERT(pTable && pTable->GetFrmFmt(), "insert table failed");
2475 if (!pTable || !pTable->GetFrmFmt())
2476 return;
2478 SwTableNode* pTableNode = pTable->GetTableNode();
2479 ASSERT(pTableNode, "no table node!");
2480 if (pTableNode)
2482 pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(),
2483 *pTableNode);
2486 // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits
2487 // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile
2488 // hinter der Tabelle rutschen, wo er nichts zu suchen hat. -> loeschen
2489 // und spaeter an das Tabellenformat setzen
2490 if (SwTxtNode* pNd = pIo->rDoc.GetNodes()[pTmpPos->nNode]->GetTxtNode())
2492 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2494 SfxPoolItem *pSetAttr = 0;
2495 const SfxPoolItem* pItem;
2496 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2498 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem );
2499 pNd->ResetAttr( RES_BREAK );
2502 // evtl den PageDesc/Break jetzt an der Tabelle setzen
2503 if (pSetAttr)
2505 aItemSet.Put(*pSetAttr);
2506 delete pSetAttr;
2511 // Gesamtbreite der Tabelle
2512 if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2514 pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2515 aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2518 SvxFrameDirectionItem aDirection(
2519 bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2520 pTable->GetFrmFmt()->SetFmtAttr(aDirection);
2522 if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2524 if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt &&
2525 GetMinLeft())
2527 //If we are inside a frame and we have a border, the frames
2528 //placement does not consider the tables border, which word
2529 //displays outside the frame, so adjust here.
2530 SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient());
2531 sal_Int16 eHori = aHori.GetHoriOrient();
2532 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2533 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2535 //With multiple table, use last table settings. Perhaps
2536 //the maximum is what word does ?
2537 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft());
2538 aHori.SetHoriOrient(text::HoriOrientation::NONE);
2539 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori);
2542 else
2544 //If bApo is set, then this table is being placed in a floating
2545 //frame, and the frame matches the left and right *lines* of the
2546 //table, so the space to the left of the table isn't to be used
2547 //inside the frame, in word the dialog involved greys out the
2548 //ability to set the margin.
2549 SvxLRSpaceItem aL( RES_LR_SPACE );
2550 // set right to original DxaLeft (i28656)
2552 long nLeft = 0;
2553 if (!bIsBiDi)
2554 nLeft = GetMinLeft();
2555 else
2556 nLeft = pIo->maSectionManager.GetTextAreaWidth() - nPreferredWidth - nOrgDxaLeft;
2558 aL.SetLeft(nLeft);
2560 aItemSet.Put(aL);
2564 mpOldRedlineStack = pIo->mpRedlineStack;
2565 pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc);
2568 void WW8TabDesc::UseSwTable()
2570 // globale Varis initialisieren
2571 pTabLines = &pTable->GetTabLines();
2572 nAktRow = nAktCol = nAktBandRow = 0;
2574 pTblNd = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]->
2575 GetSttNd()->FindTableNode();
2576 ASSERT( pTblNd, "wo ist mein TabellenNode" );
2578 // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value
2579 if ( nRowsToRepeat == static_cast<USHORT>(nRows) )
2580 nRowsToRepeat = 1;
2581 // <--
2583 pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2584 // ggfs. Zusatz-Zellen einfuegen u.dgl.
2585 AdjustNewBand();
2587 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2588 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false);
2590 // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten...
2591 SetPamInCell(nAktCol, true);
2592 aDup.Insert(*pIo->pPaM->GetPoint());
2594 pIo->bWasTabRowEnd = false;
2595 pIo->bWasTabCellEnd = false;
2598 void WW8TabDesc::MergeCells()
2600 short nRow;
2602 for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2605 // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen
2607 if( pActBand->pTCs )
2609 for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2610 for( short i = 0; i < pActBand->nWwCols; i++ )
2612 WW8SelBoxInfoPtr pActMGroup = 0;
2614 // ggfs. eine neue Merge-Gruppe beginnen
2616 ASSERT(nRow < pTabLines->Count(),
2617 "Too few lines, table ended early");
2618 if (nRow >= pTabLines->Count())
2619 return;
2620 pTabLine = (*pTabLines)[ nRow ];
2621 pTabBoxes = &pTabLine->GetTabBoxes();
2623 USHORT nCol = pActBand->nTransCell[ i ];
2624 if (!pActBand->bExist[i]) //#113434#
2625 continue;
2626 ASSERT(nCol < pTabBoxes->Count(),
2627 "Too few columns, table ended early");
2628 if (nCol >= pTabBoxes->Count())
2629 return;
2630 pTabBox = (*pTabBoxes)[nCol];
2631 WW8_TCell& rCell = pActBand->pTCs[ i ];
2632 // ist dies die obere, linke-Zelle einer Merge-Gruppe ?
2634 bool bMerge = false;
2635 if ( rCell.bVertRestart && !rCell.bMerged )
2636 bMerge = true;
2637 else if (rCell.bFirstMerged && pActBand->bExist[i])
2639 //#91211# Some tests to avoid merging cells
2640 //which previously were declared invalid because
2641 //of sharing the exact same dimensions as their
2642 //previous cell
2644 //If theres anything underneath/above we're ok.
2645 if (rCell.bVertMerge || rCell.bVertRestart)
2646 bMerge = true;
2647 else
2649 //If its a hori merge only, and the only things in
2650 //it are invalid cells then its already taken care
2651 //of, so don't merge.
2652 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2653 if (pActBand->pTCs[ i2 ].bMerged &&
2654 !pActBand->pTCs[ i2 ].bFirstMerged )
2656 if (pActBand->bExist[i2])
2658 bMerge = true;
2659 break;
2662 else
2663 break;
2668 if (bMerge)
2670 short nX1 = pActBand->nCenter[ i ];
2671 short nWidth = pActBand->nWidth[ i ];
2673 // 0. falls noetig das Array fuer die Merge-Gruppen
2674 // anlegen
2675 if( !pMergeGroups )
2676 pMergeGroups = new WW8MergeGroups;
2678 // 2. aktuelle Merge-Gruppe anlegen
2679 pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2681 // --> OD 2005-02-04 #118544# - determine size of new
2682 // merge group before inserted the new merge group.
2683 // Needed to correctly locked previously created merge groups.
2684 // Gesamtbreite ermitteln und zuweisen
2685 short nSizCell = pActBand->nWidth[ i ];
2686 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2687 if (pActBand->pTCs[ i2 ].bMerged &&
2688 !pActBand->pTCs[ i2 ].bFirstMerged )
2690 nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2692 else
2693 break;
2694 pActMGroup->nGroupWidth = nSizCell;
2695 // <--
2697 // --> OD 2005-02-03 #118544# - locked previously
2698 // created merge groups, after determining the size
2699 // for the new merge group.
2700 // 1. ggfs. alte Mergegruppe(n) schliessen, die
2701 // den von unserer neuen Gruppe betroffenen
2702 // X-Bereich ueberdecken
2703 short nMGrIdx;
2704 while ( FindMergeGroup( nX1, pActMGroup->nGroupWidth,
2705 false, nMGrIdx ) )
2707 (*pMergeGroups)[ nMGrIdx ]->bGroupLocked = true;
2709 // <--
2711 // 3. und in Gruppen-Array eintragen
2712 pMergeGroups->Insert(pActMGroup, pMergeGroups->Count());
2715 // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies
2716 // kann eine soeben angelegte, oder eine andere Gruppe
2717 // sein)
2718 UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2724 //There is a limbo area in word at the end of the row marker
2725 //where properties can live in word, there is no location in
2726 //writer equivalent, so try and park the cursor in the best
2727 //match, see #i23022#/#i18644#
2728 void WW8TabDesc::ParkPaM()
2730 SwTableBox *pTabBox2 = 0;
2731 short nRow = nAktRow + 1;
2732 if (nRow < pTabLines->Count())
2734 if (SwTableLine *pLine = (*pTabLines)[nRow])
2736 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2737 pTabBox2 = rBoxes.Count() ? rBoxes[0] : 0;
2741 if (!pTabBox2 || !pTabBox2->GetSttNd())
2743 MoveOutsideTable();
2744 return;
2747 if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1)
2749 pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1;
2750 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2751 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2755 void WW8TabDesc::MoveOutsideTable()
2757 ASSERT(pTmpPos && pIo, "I've forgotten where the table is anchored");
2758 if (pTmpPos && pIo)
2759 *pIo->pPaM->GetPoint() = *pTmpPos;
2762 void WW8TabDesc::FinishSwTable()
2764 pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint());
2765 delete pIo->mpRedlineStack;
2766 pIo->mpRedlineStack = mpOldRedlineStack;
2767 mpOldRedlineStack = 0;
2769 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2770 pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false);
2772 MoveOutsideTable();
2773 delete pTmpPos, pTmpPos = 0;
2775 aDup.Insert(*pIo->pPaM->GetPoint());
2777 pIo->bWasTabRowEnd = false;
2778 pIo->bWasTabCellEnd = false;
2780 pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM);
2782 MergeCells();
2784 // falls noetig, zu mergende Zellen gruppenweise zusammenfassen
2785 if( pMergeGroups )
2787 // bearbeite alle Merge-Gruppen nacheinander
2788 WW8SelBoxInfo* pActMGroup;
2789 USHORT nActBoxCount;
2791 for (USHORT iGr = 0; iGr < pMergeGroups->Count(); ++iGr)
2793 pActMGroup = (*pMergeGroups)[ iGr ];
2794 nActBoxCount = pActMGroup->Count();
2796 if( ( 1 < nActBoxCount ) && pActMGroup && (*pActMGroup)[ 0 ] )
2798 const USHORT nRowSpan = pActMGroup->Count();
2799 for (USHORT n = 0; n < nRowSpan; ++n)
2801 SwTableBox* pCurrentBox = (*pActMGroup)[n];
2802 const long nRowSpanSet = n == 0 ?
2803 nRowSpan :
2804 ((-1) * (nRowSpan - n));
2805 pCurrentBox->setRowSpan( nRowSpanSet );
2809 pIo->pFmtOfJustInsertedApo = 0;
2810 DELETEZ( pMergeGroups );
2815 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1
2817 // Parameter: nXcenter = Mittenposition der anfragenden Box
2818 // nWidth = Breite der anfragenden Box
2819 // bExact = Flag, ob Box in dieser Gruppe passen muss,
2820 // oder diese nur zu tangieren braucht
2822 bool WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact,
2823 short& nMGrIdx)
2825 nMGrIdx = -1;
2826 if( pMergeGroups )
2828 // noch als gueltig angesehener Bereich in der Naehe der Grenzen
2829 const short nToleranz = 4;
2830 // die aktuell untersuchte Gruppe
2831 WW8SelBoxInfoPtr pActGroup;
2832 // Boxgrenzen
2833 short nX2 = nX1 + nWidth;
2834 // ungefaehre Gruppengrenzen
2835 short nGrX1;
2836 short nGrX2;
2838 // --> OD 2005-02-04 #118544# - improvement: search backwards
2839 //for ( USHORT iGr = 0; iGr < pMergeGroups->Count(); iGr++ )
2840 for ( short iGr = pMergeGroups->Count() - 1; iGr >= 0; --iGr )
2842 // die aktuell untersuchte Gruppe
2843 pActGroup = (*pMergeGroups)[ iGr ];
2844 if (!pActGroup->bGroupLocked)
2846 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin
2847 nGrX1 = pActGroup->nGroupXStart - nToleranz;
2848 nGrX2 = pActGroup->nGroupXStart
2849 +pActGroup->nGroupWidth + nToleranz;
2851 // Falls Box reinpasst, melde auf jeden Fall den Erfolg
2853 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2855 nMGrIdx = iGr; break;
2858 // hat die Box Bereiche mit der Gruppe gemeinsam?
2860 if( !bExact )
2862 // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen
2863 if( ( ( nX1 > nGrX1 )
2864 && ( nX1 < nGrX2 - 2*nToleranz ) )
2865 || ( ( nX2 > nGrX1 + 2*nToleranz )
2866 && ( nX2 < nGrX2 ) )
2867 // oder nX1 und nX2 die Gruppe umfassen
2868 || ( ( nX1 <=nGrX1 )
2869 && ( nX2 >=nGrX2 ) ) )
2871 nMGrIdx = iGr; break;
2877 return ( -1 < nMGrIdx );
2880 bool WW8TabDesc::IsValidCell(short nCol) const
2882 return pActBand->bExist[nCol] && (USHORT)nAktRow < pTabLines->Count();
2885 bool WW8TabDesc::InFirstParaInCell() const
2887 //e.g. #i19718#
2888 if (!pTabBox || !pTabBox->GetSttNd())
2890 ASSERT(false, "Problem with table");
2891 return false;
2894 if (!IsValidCell(GetAktCol()))
2895 return false;
2897 if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2898 return true;
2900 return false;
2903 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2905 ASSERT(pActBand, "Impossible");
2906 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2908 pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(),
2909 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2913 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2915 ASSERT(pActBand, "Impossible");
2916 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2917 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE);
2920 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2922 ASSERT( pActBand, "pActBand ist 0" );
2924 USHORT nCol = pActBand->nTransCell[nWwCol];
2926 if ((USHORT)nAktRow >= pTabLines->Count())
2928 ASSERT(!this, "Actual row bigger than expected." );
2929 if (bPam)
2930 MoveOutsideTable();
2931 return false;
2934 pTabLine = (*pTabLines)[nAktRow];
2935 pTabBoxes = &pTabLine->GetTabBoxes();
2937 if (nCol >= pTabBoxes->Count())
2939 if (bPam)
2941 // The first paragraph in a cell with upper autospacing has upper
2942 // spacing set to 0
2943 if (
2944 pIo->bParaAutoBefore && pIo->bFirstPara &&
2945 !pIo->pWDop->fDontUseHTMLAutoSpacing
2948 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2951 // The last paragraph in a cell with lower autospacing has lower
2952 // spacing set to 0
2953 if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2954 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2956 ParkPaM();
2958 return false;
2960 pTabBox = (*pTabBoxes)[nCol];
2961 if( !pTabBox->GetSttNd() )
2963 ASSERT(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2964 if (bPam)
2965 MoveOutsideTable();
2966 return false;
2968 if (bPam)
2970 pAktWWCell = &pActBand->pTCs[ nWwCol ];
2972 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2973 if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2974 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2976 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2977 if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2978 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2980 //We need to set the pPaM on the first cell, invalid
2981 //or not so that we can collect paragraph proproties over
2982 //all the cells, but in that case on the valid cell we do not
2983 //want to reset the fmt properties
2984 if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1)
2986 pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1;
2987 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2988 // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die
2989 // zum Randausgleich eingefuegt werden, sonst der Style
2990 // nicht gesetzt wird.
2991 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2992 // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind,
2993 // und nur dazu dienen, zerfranste Aussehen der WW-Tabelle
2994 // nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel()
2995 // verwendet zu werden.
2998 // Better to turn Snap to Grid off for all paragraphs in tables
2999 if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode())
3001 const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID);
3002 SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm);
3004 if(rSnapToGrid.GetValue())
3006 SvxParaGridItem aGridItem( rSnapToGrid );
3007 aGridItem.SetValue(false);
3009 SwPosition* pGridPos = pIo->pPaM->GetPoint();
3011 xub_StrLen nEnd = pGridPos->nContent.GetIndex();
3012 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3013 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem);
3014 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd);
3015 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
3019 StartMiserableHackForUnsupportedDirection(nWwCol);
3021 return true;
3024 void WW8TabDesc::InsertCells( short nIns )
3026 pTabLine = (*pTabLines)[nAktRow];
3027 pTabBoxes = &pTabLine->GetTabBoxes();
3028 pTabBox = (*pTabBoxes)[0];
3030 pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(),
3031 (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->Count(), nIns );
3032 // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben.
3033 // hier kann man auch noch optimieren, um FrmFmts zu sparen
3036 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3038 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3039 return; // kuenstlich erzeugte Zellen -> Kein Rand
3042 SvxBoxItem aFmtBox( RES_BOX );
3043 if (pActBand->pTCs) // neither Cell Border nor Default Border defined ?
3045 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3046 if (pIo->IsBorder(pT->rgbrc))
3047 pIo->SetBorder(aFmtBox, pT->rgbrc);
3050 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
3052 aFmtBox.SetDistance(
3053 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
3054 BOX_LINE_TOP);
3056 else
3057 aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP);
3058 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
3060 aFmtBox.SetDistance(
3061 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
3062 BOX_LINE_BOTTOM);
3064 else
3065 aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM);
3067 // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen
3068 // Tabellenzelle und -Inhalt
3069 short nLeftDist =
3070 pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
3071 short nRightDist =
3072 pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
3073 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
3075 aFmtBox.SetDistance(
3076 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
3077 BOX_LINE_LEFT);
3079 else
3080 aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT);
3081 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
3083 aFmtBox.SetDistance(
3084 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
3085 BOX_LINE_RIGHT);
3087 else
3088 aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT);
3090 pBox->GetFrmFmt()->SetFmtAttr(aFmtBox);
3093 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3095 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3096 return; // kuenstlich erzeugte Zellen -> Keine Farbe
3098 bool bFound=false;
3099 if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3101 Color aColor(pActBand->pNewSHDs[nWwIdx]);
3102 if (aColor.GetColor() == 0x00333333)
3103 pIo->maTracer.Log(sw::log::eAutoColorBg);
3104 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND));
3105 bFound = true;
3108 //If there was no new shades, or no new shade setting
3109 if (pActBand->pSHDs && !bFound)
3111 WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3112 if (!rSHD.GetValue()) // auto
3113 return;
3115 SwWW8Shade aSh( pIo->bVer67, rSHD );
3116 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3120 SvxFrameDirection MakeDirection(sal_uInt16 nCode, BOOL bIsBiDi)
3122 SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3123 // 1: Asian layout with rotated CJK characters
3124 // 5: Asian layout
3125 // 3: Western layout rotated by 90 degrees
3126 // 4: Western layout
3127 switch (nCode)
3129 default:
3130 ASSERT(eDir == 4, "unknown direction code, maybe its a bitfield");
3131 case 3:
3132 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3133 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3134 // <--
3135 break;
3136 case 5:
3137 eDir = FRMDIR_VERT_TOP_RIGHT;
3138 break;
3139 case 1:
3140 eDir = FRMDIR_VERT_TOP_RIGHT;
3141 break;
3142 case 4:
3143 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3144 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3145 // <--
3146 break;
3148 return eDir;
3151 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3153 if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3154 return;
3155 SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3156 pBox->GetFrmFmt()->SetFmtAttr(aItem);
3159 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3161 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3162 return;
3164 sal_Int16 eVertOri=text::VertOrientation::TOP;
3166 if( pActBand->pTCs )
3168 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3169 switch (pT->nVertAlign)
3171 case 0:
3172 default:
3173 eVertOri = text::VertOrientation::TOP;
3174 break;
3175 case 1:
3176 eVertOri = text::VertOrientation::CENTER;
3177 break;
3178 case 2:
3179 eVertOri = text::VertOrientation::BOTTOM;
3180 break;
3184 pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) );
3187 void WW8TabDesc::AdjustNewBand()
3189 if( pActBand->nSwCols > nDefaultSwCols ) // Zellen splitten
3190 InsertCells( pActBand->nSwCols - nDefaultSwCols );
3192 SetPamInCell( 0, false);
3193 ASSERT( pTabBoxes && pTabBoxes->Count() == (USHORT)pActBand->nSwCols,
3194 "Falsche Spaltenzahl in Tabelle" )
3196 if( bClaimLineFmt )
3198 pTabLine->ClaimFrmFmt(); // noetig wg. Zeilenhoehe
3199 SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3201 if (pActBand->nLineHeight == 0) // 0 = Auto
3202 aF.SetHeightSizeType( ATT_VAR_SIZE );
3203 else
3205 if (pActBand->nLineHeight < 0) // Pos = min, Neg = exakt
3207 aF.SetHeightSizeType(ATT_FIX_SIZE);
3208 pActBand->nLineHeight = -pActBand->nLineHeight;
3210 if (pActBand->nLineHeight < MINLAY) // nicht erlaubte Zeilenhoehe
3211 pActBand->nLineHeight = MINLAY;
3213 aF.SetHeight(pActBand->nLineHeight);// Min- / Exakt-Hoehe setzen
3215 pTabLine->GetFrmFmt()->SetFmtAttr(aF);
3218 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3219 //we can split the row
3220 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3221 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3222 // Word versions >= 2002.
3223 bool bSetCantSplit = pActBand->bCantSplit;
3224 if(bSetCantSplit)
3225 bSetCantSplit = pActBand->bCantSplit90;
3227 pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit));
3229 short i; // SW-Index
3230 short j; // WW-Index
3231 short nW; // Breite
3232 SwFmtFrmSize aFS( ATT_FIX_SIZE );
3233 j = pActBand->bLEmptyCol ? -1 : 0;
3235 for( i = 0; i < pActBand->nSwCols; i++ )
3237 // setze Zellenbreite
3238 if( j < 0 )
3239 nW = pActBand->nCenter[0] - nMinLeft;
3240 else
3242 //Set j to first non invalid cell
3243 while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3244 j++;
3246 if( j < pActBand->nWwCols )
3247 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3248 else
3249 nW = nMaxRight - pActBand->nCenter[j];
3250 pActBand->nWidth[ j ] = nW;
3253 SwTableBox* pBox = (*pTabBoxes)[i];
3254 // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter
3255 // verringern
3256 pBox->ClaimFrmFmt();
3258 SetTabBorders(pBox, j);
3260 // #i18128# word has only one line between adjoining vertical cells
3261 // we have to mimick this in the filter by picking the larger of the
3262 // sides and using that one on one side of the line (right)
3263 SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX));
3264 const SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT);
3265 int nCurrentRightLineWidth = 0;
3266 if(pLeftLine)
3267 nCurrentRightLineWidth = pLeftLine->GetInWidth() + pLeftLine->GetOutWidth() + pLeftLine->GetDistance();
3269 if (i != 0)
3271 SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3272 SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX));
3273 const SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT);
3274 int nOldBoxRightLineWidth = 0;
3275 if(pRightLine)
3276 nOldBoxRightLineWidth = pRightLine->GetInWidth() + pRightLine->GetOutWidth() + pRightLine->GetDistance();
3278 if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3279 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT);
3281 aOldBox.SetLine(0, BOX_LINE_RIGHT);
3282 pBox2->GetFrmFmt()->SetFmtAttr(aOldBox);
3285 pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox);
3287 SetTabVertAlign(pBox, j);
3288 SetTabDirection(pBox, j);
3289 if( pActBand->pSHDs || pActBand->pNewSHDs)
3290 SetTabShades(pBox, j);
3291 j++;
3293 aFS.SetWidth( nW );
3294 pBox->GetFrmFmt()->SetFmtAttr( aFS );
3296 // ueberspringe nicht existente Zellen
3297 while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3299 pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3300 j++;
3305 void WW8TabDesc::TableCellEnd()
3307 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
3309 EndMiserableHackForUnsupportedDirection(nAktCol);
3311 // neue Zeile
3312 if( pIo->bWasTabRowEnd )
3314 // bWasTabRowEnd will be deactivated in
3315 // SwWW8ImplReader::ProcessSpecial()
3317 USHORT iCol = GetLogicalWWCol();
3318 if (iCol < aNumRuleNames.size())
3320 aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3321 aNumRuleNames.end());
3324 nAktCol = 0;
3325 nAktRow++;
3326 nAktBandRow++;
3327 ASSERT( pActBand , "pActBand ist 0" );
3328 if( pActBand )
3330 if( nAktRow >= nRows ) // am Tabellenende gibt's nichts sinnvolles
3331 return; // mehr zu tun
3333 bool bNewBand = nAktBandRow >= pActBand->nRows;
3334 if( bNewBand )
3335 { // neues Band noetig ?
3336 pActBand = pActBand->pNextBand; //
3337 nAktBandRow = 0;
3338 ASSERT( pActBand, "pActBand ist 0" );
3339 AdjustNewBand();
3341 else
3343 SwTableBox* pBox = (*pTabBoxes)[0];
3344 SwSelBoxes aBoxes;
3345 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) );
3349 else
3350 { // neue Spalte ( Zelle )
3351 nAktCol++;
3353 SetPamInCell(nAktCol, true);
3355 // finish Annotated Level Numbering ?
3356 if (pIo->bAnl && !pIo->bAktAND_fNumberAcross)
3357 pIo->StopAllAnl(IsValidCell(nAktCol));
3360 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen
3361 SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell,
3362 WW8SelBoxInfo* pActGroup,
3363 SwTableBox* pActBox,
3364 USHORT nCol )
3366 // Rueckgabewert defaulten
3367 SwTableBox* pResult = 0;
3369 // pruefen, ob die Box zu mergen ist
3370 // --> OD 2005-02-04 #118544# - If cell is the first one to be merged,
3371 // a new merge group has to be provided.
3372 // E.g., it could be that a cell is the first one to be merged, but no
3373 // new merge group is provided, because the potential other cell to be merged
3374 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3375 if ( pActBand->bExist[ nCol ] &&
3376 ( ( rCell.bFirstMerged && pActGroup ) ||
3377 rCell.bMerged ||
3378 rCell.bVertMerge ||
3379 rCell.bVertRestart ) )
3380 // <--
3382 // passende Merge-Gruppe ermitteln
3383 WW8SelBoxInfo* pTheMergeGroup = 0;
3384 if( pActGroup )
3385 // Gruppe uebernehmen
3386 pTheMergeGroup = pActGroup;
3387 else
3389 // Gruppe finden
3390 short nMGrIdx;
3391 if( FindMergeGroup( pActBand->nCenter[ nCol ],
3392 pActBand->nWidth[ nCol ], true, nMGrIdx ) )
3393 pTheMergeGroup = (*pMergeGroups)[ nMGrIdx ];
3395 if( pTheMergeGroup )
3397 // aktuelle Box der Merge-Gruppe hinzufuegen
3398 pTheMergeGroup->Insert( pActBox, pTheMergeGroup->Count() );
3400 // Target-Box zurueckmelden
3401 pResult = (*pTheMergeGroup)[ 0 ];
3404 return pResult;
3408 USHORT WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3410 USHORT nCol = 0;
3411 if( pActBand && pActBand->pTCs)
3413 for( USHORT iCol = 1; iCol <= nAktCol; ++iCol )
3415 if( !pActBand->pTCs[ iCol-1 ].bMerged )
3416 ++nCol;
3419 return nCol;
3422 // find name of numrule valid for current WW-COL
3423 const String& WW8TabDesc::GetNumRuleName() const
3425 USHORT nCol = GetLogicalWWCol();
3426 if (nCol < aNumRuleNames.size())
3427 return aNumRuleNames[nCol];
3428 else
3429 return aEmptyStr;
3432 void WW8TabDesc::SetNumRuleName( const String& rName )
3434 USHORT nCol = GetLogicalWWCol();
3435 for (USHORT nSize = static_cast< USHORT >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3436 aNumRuleNames.push_back(aEmptyStr);
3437 aNumRuleNames[nCol] = rName;
3440 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp)
3442 // Entering a table so make sure the the FirstPara flag gets set
3443 bFirstPara = true;
3444 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3445 // Fussnote
3446 if (bReadNoTbl)
3447 return false;
3449 if (pTableDesc)
3450 maTableStack.push(pTableDesc);
3452 // --> OD 2005-01-27 #i33818# - determine absolute position object attributes,
3453 // if possible. It's needed for nested tables.
3454 WW8FlyPara* pTableWFlyPara( 0L );
3455 WW8SwFlyPara* pTableSFlyPara( 0L );
3456 // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame
3457 // only at-character, if absolute position object attributes are available.
3458 // Thus, default anchor type is as-character anchored.
3459 RndStdIds eAnchor( FLY_IN_CNTNT );
3460 // <--
3461 if ( nInTable )
3463 WW8_TablePos* pNestedTabPos( 0L );
3464 WW8_TablePos aNestedTabPos;
3465 WW8PLCFxSave1 aSave;
3466 pPlcxMan->GetPap()->Save( aSave );
3467 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
3468 WW8_CP nMyStartCp = nStartCp;
3469 if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) &&
3470 ParseTabPos( &aNestedTabPos, pPap ) )
3472 pNestedTabPos = &aNestedTabPos;
3474 pPlcxMan->GetPap()->Restore( aSave );
3475 if ( pNestedTabPos )
3477 ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos );
3478 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3479 if ( pTableWFlyPara )
3481 // --> OD 2007-07-03 #148498#
3482 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3483 // containing WW8 page top margin.
3484 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara,
3485 maSectionManager.GetWWPageTopMargin(),
3486 maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(),
3487 nIniFlyDx, nIniFlyDy);
3488 // <--
3489 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly
3490 // frame at-character
3491 eAnchor = FLY_AUTO_CNTNT;
3492 // <--
3496 // <--
3498 pTableDesc = new WW8TabDesc( this, nStartCp );
3500 if( pTableDesc->Ok() )
3502 int nNewInTable = nInTable + 1;
3503 if (InEqualApo(nNewInTable))
3505 ASSERT(pSFlyPara->pFlyFmt,
3506 "how could we be in a local apo and have no apo");
3509 if ( eAnchor == FLY_AUTO_CNTNT && !maTableStack.empty() && !InEqualApo(nNewInTable) )
3511 pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint());
3512 SfxItemSet aItemSet(rDoc.GetAttrPool(),
3513 RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3514 // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for
3515 // the nested table at-character.
3516 // --> OD 2005-03-21 #i45301#
3517 SwFmtAnchor aAnchor( eAnchor );
3518 aAnchor.SetAnchor( pTableDesc->pParentPos );
3519 aItemSet.Put( aAnchor );
3520 pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor,
3521 pTableDesc->pParentPos, &aItemSet);
3522 ASSERT( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor,
3523 "Not the anchor type requested!" );
3524 // <--
3525 MoveInsideFly(pTableDesc->pFlyFmt);
3527 pTableDesc->CreateSwTable();
3528 if (pTableDesc->pFlyFmt)
3530 pTableDesc->SetSizePosition(pTableDesc->pFlyFmt);
3531 // --> OD 2005-01-26 #i33818# - Use absolute position object
3532 // attributes, if existing, and apply them to the created Writer fly
3533 // frame.
3534 if ( pTableWFlyPara && pTableSFlyPara )
3536 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3537 SwFmtAnchor aAnchor( FLY_AUTO_CNTNT );
3538 aAnchor.SetAnchor( pTableDesc->pParentPos );
3539 aFlySet.Put( aAnchor );
3540 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet );
3542 else
3544 SwFmtHoriOrient aHori =
3545 pTableDesc->pTable->GetFrmFmt()->GetHoriOrient();
3546 pTableDesc->pFlyFmt->SetFmtAttr(aHori);
3547 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) );
3549 // <--
3550 // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave
3551 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3552 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( TRUE ) );
3553 // <--
3555 else
3556 pTableDesc->SetSizePosition(0);
3557 pTableDesc->UseSwTable();
3559 else
3560 PopTableDesc();
3562 // --> OD 2005-01-28 #i33818#
3563 delete pTableWFlyPara;
3564 delete pTableSFlyPara;
3565 // <--
3567 bool bSuccess = (0 != pTableDesc);
3568 if (bSuccess)
3570 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3571 static_cast<sal_Int32>(maTableStack.size())));
3573 return bSuccess;
3576 void SwWW8ImplReader::TabCellEnd()
3578 if (nInTable && pTableDesc)
3580 pTableDesc->TableCellEnd();
3582 if (bReadTable
3583 && pWFlyPara == NULL
3584 && mpTableEndPaM.get() != NULL
3585 && (! SwPaM::Overlap(*pPaM, *mpTableEndPaM))
3586 && SwPaM::LessThan(*mpTableEndPaM, *pPaM))
3588 if (mpTableEndPaM->GetPoint()->nNode.GetNode().IsTxtNode())
3590 rDoc.DelFullPara(*mpTableEndPaM);
3595 bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3596 bReadTable = false;
3597 mpTableEndPaM.reset();
3600 void SwWW8ImplReader::Read_TabCellEnd( USHORT, const BYTE* pData, short nLen)
3602 if( ( nLen > 0 ) && ( *pData == 1 ) )
3603 bWasTabCellEnd = true;
3606 void SwWW8ImplReader::Read_TabRowEnd( USHORT, const BYTE* pData, short nLen ) // Sprm25
3608 if( ( nLen > 0 ) && ( *pData == 1 ) )
3609 bWasTabRowEnd = true;
3612 void SwWW8ImplReader::PopTableDesc()
3614 if (pTableDesc && pTableDesc->pFlyFmt)
3616 MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos);
3619 delete pTableDesc;
3620 if (maTableStack.empty())
3621 pTableDesc = 0;
3622 else
3624 pTableDesc = maTableStack.top();
3625 maTableStack.pop();
3629 void SwWW8ImplReader::StopTable()
3631 maTracer.LeaveEnvironment(sw::log::eTable);
3633 ASSERT(pTableDesc, "Panic, stop table with no table!");
3634 if (!pTableDesc)
3635 return;
3637 // We are leaving a table so make sure the next paragraph doesn't think
3638 // it's the first paragraph
3639 bFirstPara = false;
3641 pTableDesc->FinishSwTable();
3642 PopTableDesc();
3644 if (!maTableStack.empty())
3646 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3647 static_cast<sal_Int32>(maTableStack.size())));
3650 bReadTable = true;
3651 // --> OD 2009-04-16 #i101116#
3652 // Keep PaM on table end only for nested tables
3653 if ( nInTable > 1 )
3655 mpTableEndPaM.reset(new SwPaM(*pPaM));
3657 // <--
3660 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen
3661 // gebraucht.
3662 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle
3663 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand.
3664 short SwWW8ImplReader::GetTableLeft()
3666 return (pTableDesc) ? pTableDesc->GetMinLeft() : 0;
3669 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3671 if( !pTableDesc )
3672 return false;
3674 const WW8_TCell* pCell = pTableDesc->GetAktWWCell();
3676 return !pTableDesc->IsValidCell( pTableDesc->GetAktCol() )
3677 || ( pCell
3678 && ( !pCell->bFirstMerged
3679 && ( pCell->bMerged
3680 || ( pCell->bVertMerge
3681 && !pCell->bVertRestart
3688 USHORT SwWW8ImplReader::StyleUsingLFO( USHORT nLFOIndex ) const
3690 USHORT nRes = USHRT_MAX;
3691 if( pCollA )
3693 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3694 if( pCollA[ nI ].bValid
3695 && (nLFOIndex == pCollA[ nI ].nLFOIndex) )
3696 nRes = nI;
3698 return nRes;
3701 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const
3703 SwFmt* pRet = 0;
3704 if( pCollA )
3706 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3707 if( pCollA[ nI ].bValid
3708 && (rName.Equals( pCollA[ nI ].GetOrgWWName())) )
3710 pRet = pCollA[ nI ].pFmt;
3711 break;
3714 return pRet;
3717 //-----------------------------------------
3718 // class WW8RStyle
3719 //-----------------------------------------
3721 const BYTE* WW8RStyle::HasParaSprm( USHORT nId ) const
3723 if( !pParaSprms || !nSprmsLen )
3724 return 0;
3726 const BYTE* pSprms = pParaSprms;
3727 USHORT i, x;
3729 for( i=0; i < nSprmsLen; )
3731 USHORT nAktId = maSprmParser.GetSprmId(pSprms);
3732 // Sprm found ?
3733 if( nAktId == nId )
3734 return pSprms + maSprmParser.DistanceToData(nId);
3736 x = maSprmParser.GetSprmSize(nAktId, pSprms);
3737 i = i + x;
3738 pSprms += x;
3740 return 0; // Sprm not found
3743 void WW8RStyle::ImportSprms(BYTE *pSprms, short nLen, bool bPap)
3745 if (!nLen)
3746 return;
3748 if( bPap )
3750 pParaSprms = pSprms; // fuer HasParaSprms()
3751 nSprmsLen = nLen;
3754 while ( nLen > 0 )
3756 USHORT nL1 = pIo->ImportSprm(pSprms);
3757 nLen = nLen - nL1;
3758 pSprms += nL1;
3761 pParaSprms = 0;
3762 nSprmsLen = 0;
3765 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3767 if (!nLen)
3768 return;
3770 BYTE *pSprms = new BYTE[nLen];
3772 pStStrm->Seek(nPosFc);
3773 pStStrm->Read(pSprms, nLen);
3775 ImportSprms(pSprms, nLen, bPap);
3777 delete[] pSprms;
3780 static inline short WW8SkipOdd(SvStream* pSt )
3782 if ( pSt->Tell() & 0x1 )
3784 UINT8 c;
3785 pSt->Read( &c, 1 );
3786 return 1;
3788 return 0;
3791 static inline short WW8SkipEven(SvStream* pSt )
3793 if (!(pSt->Tell() & 0x1))
3795 UINT8 c;
3796 pSt->Read( &c, 1 );
3797 return 1;
3799 return 0;
3802 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3804 INT16 cbUPX;
3806 if( 0 < nLen ) // Empty ?
3808 if (bOdd)
3809 nLen = nLen - WW8SkipEven( pStStrm );
3810 else
3811 nLen = nLen - WW8SkipOdd( pStStrm );
3813 *pStStrm >> cbUPX;
3815 nLen-=2;
3817 if ( cbUPX > nLen )
3818 cbUPX = nLen; // !cbUPX auf nLen verkleinert!
3820 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3822 if( bPAP )
3824 UINT16 id;
3825 *pStStrm >> id;
3827 cbUPX-= 2;
3828 nLen-= 2;
3831 if( 0 < cbUPX )
3833 sal_Size nPos = pStStrm->Tell(); // falls etwas falsch interpretiert
3834 // wird, gehts danach wieder richtig
3835 ImportSprms( nPos, cbUPX, bPAP );
3837 if ( pStStrm->Tell() != nPos + cbUPX )
3838 pStStrm->Seek( nPos+cbUPX );
3840 nLen = nLen - cbUPX;
3844 return nLen;
3847 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3849 if( nLen <= 0 )
3850 return;
3851 if (bOdd)
3852 nLen = nLen - WW8SkipEven( pStStrm );
3853 else
3854 nLen = nLen - WW8SkipOdd( pStStrm );
3856 if( bPara ) // Grupx.Papx
3857 nLen = ImportUPX(nLen, true, bOdd);
3858 ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3861 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3862 : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()),
3863 pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0)
3865 pIo->pCollA = new SwWW8StyInf[ cstd ]; // Style-UEbersetzung WW->SW
3866 pIo->nColls = cstd;
3869 void WW8RStyle::Set1StyleDefaults()
3871 if (!bCJKFontChanged) // Style no CJK Font? set the default
3872 pIo->SetNewFontAttr(ftcStandardChpCJKStsh, true, RES_CHRATR_CJK_FONT);
3874 // see i25247
3875 const WW8_FFN* pF = pIo->pFonts->GetFont(3);
3876 if (pF)
3878 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(pF->chs);
3879 if ((ftcStandardChpCTLStsh == 0) && (eEnc == RTL_TEXTENCODING_MS_1255))
3880 ftcStandardChpCTLStsh = 3;
3883 if (ftcStandardChpCJKStsh == 0)
3884 ftcStandardChpCJKStsh = 2;
3886 if (!bCTLFontChanged) // Style no CTL Font? set the default
3887 pIo->SetNewFontAttr(ftcStandardChpCTLStsh, true, RES_CHRATR_CTL_FONT);
3889 //#88976# western 2nd to make western charset conversion the default
3890 if (!bFontChanged) // Style has no Font? set the default,
3892 pIo->SetNewFontAttr(ftcStandardChpStsh, true, RES_CHRATR_FONT);
3893 /* removed by a patch from cmc for #i52786#
3894 if (pIo->bVer67)
3895 SetStyleCharSet(pIo->pCollA[pIo->nAktColl]);
3899 if( !pIo->bNoAttrImport )
3901 // Style has no text color set, winword default is auto
3902 if ( !bTxtColChanged )
3903 pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3905 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3906 if( !bFSizeChanged )
3908 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3909 pIo->pAktColl->SetFmtAttr(aAttr);
3910 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3911 pIo->pAktColl->SetFmtAttr(aAttr);
3914 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3915 if( !bFCTLSizeChanged )
3917 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3918 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3919 pIo->pAktColl->SetFmtAttr(aAttr);
3922 if( pIo->pWDop->fWidowControl && !bWidowsChanged ) // Widows ?
3924 pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3925 pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3930 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3932 SwFmt* pColl;
3933 bool bStyExist;
3934 if (rSI.bColl)
3936 // Para-Style
3937 sw::util::ParaStyleMapper::StyleResult aResult =
3938 pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3939 pColl = aResult.first;
3940 bStyExist = aResult.second;
3942 else
3944 // Char-Style
3945 sw::util::CharStyleMapper::StyleResult aResult =
3946 pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3947 pColl = aResult.first;
3948 bStyExist = aResult.second;
3951 bool bImport = !bStyExist || pIo->mbNewDoc; // Inhalte Importieren ?
3952 bool bOldNoImp = pIo->bNoAttrImport;
3953 rSI.bImportSkipped = !bImport;
3955 if( !bImport )
3956 pIo->bNoAttrImport = true;
3957 else
3959 if (bStyExist)
3961 // --> OD 2007-01-25 #i73790# - method renamed
3962 pColl->ResetAllFmtAttr();
3963 // <--
3965 pColl->SetAuto(false); // nach Empfehlung JP
3966 } // macht die UI aber anders
3967 pIo->pAktColl = pColl;
3968 rSI.pFmt = pColl; // UEbersetzung WW->SW merken
3969 rSI.bImportSkipped = !bImport;
3971 // Set Based on style
3972 USHORT j = rSI.nBase;
3973 if (j != nThisStyle && j < cstd )
3975 SwWW8StyInf* pj = &pIo->pCollA[j];
3976 if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl)
3978 rSI.pFmt->SetDerivedFrom( pj->pFmt ); // ok, Based on eintragen
3979 rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
3980 rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
3981 rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
3982 rSI.n81Flags = pj->n81Flags;
3983 rSI.n81BiDiFlags = pj->n81BiDiFlags;
3984 rSI.nOutlineLevel = pj->nOutlineLevel;
3985 rSI.bParaAutoBefore = pj->bParaAutoBefore;
3986 rSI.bParaAutoAfter = pj->bParaAutoAfter;
3988 if (pj->pWWFly)
3989 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly);
3992 else if( pIo->mbNewDoc && bStyExist )
3993 rSI.pFmt->SetDerivedFrom(0);
3995 rSI.nFollow = nNextStyle; // Follow merken
3997 pStyRule = 0; // falls noetig, neu anlegen
3998 bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
3999 bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
4000 pIo->SetNAktColl( nThisStyle );
4001 pIo->bStyNormal = nThisStyle == 0;
4002 return bOldNoImp;
4005 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
4007 // Alle moeglichen Attribut-Flags zuruecksetzen,
4008 // da es in Styles keine Attr-Enden gibt
4010 pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol
4011 = pIo->bSpec = pIo->bObj = pIo->bSymbol = false;
4012 pIo->nCharFmt = -1;
4014 // If Style basiert auf Nichts oder Basis ignoriert
4015 if ((rSI.nBase >= cstd || pIo->pCollA[rSI.nBase].bImportSkipped) && rSI.bColl)
4017 //! Char-Styles funktionieren aus
4018 // unerfindlichen Gruenden nicht
4019 // -> dann evtl. harte WW-Defaults
4020 // reinsetzen
4021 Set1StyleDefaults();
4024 pStyRule = 0; // zur Sicherheit
4025 pIo->bStyNormal = false;
4026 pIo->SetNAktColl( 0 );
4027 pIo->bNoAttrImport = bOldNoImp;
4028 // rasch nochmal die Listen-Merk-Felder zuruecksetzen,
4029 // fuer den Fall dass sie beim einlesen des Styles verwendet wurden
4030 pIo->nLFOPosition = USHRT_MAX;
4031 pIo->nListLevel = WW8ListManager::nMaxLevel;
4034 void WW8RStyle::Import1Style( USHORT nNr )
4036 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4038 if( rSI.bImported || !rSI.bValid )
4039 return;
4041 rSI.bImported = true; // jetzt schon Flag setzen
4042 // verhindert endlose Rekursion
4044 // gueltig und nicht NIL und noch nicht Importiert
4046 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4047 Import1Style( rSI.nBase );
4049 pStStrm->Seek( rSI.nFilePos );
4051 short nSkip, cbStd;
4052 String sName;
4054 WW8_STD* pStd = Read1Style( nSkip, &sName, &cbStd );// lies Style
4056 if (pStd)
4057 rSI.SetOrgWWIdent( sName, pStd->sti );
4059 // either no Name or unused Slot or unknown Style
4061 if ( !pStd || (0 == sName.Len()) || ((1 != pStd->sgc) && (2 != pStd->sgc)) )
4063 pStStrm->SeekRel( nSkip );
4064 return;
4067 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(pStd->sti), nNr, pStd->istdNext);
4069 // falls etwas falsch interpretiert wird, gehts danach wieder richtig
4070 long nPos = pStStrm->Tell();
4072 //Variable parts of the STD start at even byte offsets, but "inside
4073 //the STD", which I take to meaning even in relation to the starting
4074 //position of the STD, which matches findings in #89439#, generally it
4075 //doesn't matter as the STSHI starts off nearly always on an even
4076 //offset
4078 //Import of the Style Contents
4079 ImportGrupx(nSkip, pStd->sgc == 1, rSI.nFilePos & 1);
4081 PostStyle(rSI, bOldNoImp);
4083 pStStrm->Seek( nPos+nSkip );
4084 delete pStd;
4087 void WW8RStyle::RecursiveReg(USHORT nNr)
4089 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4090 if( rSI.bImported || !rSI.bValid )
4091 return;
4093 rSI.bImported = true;
4095 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4096 RecursiveReg(rSI.nBase);
4098 pIo->RegisterNumFmtOnStyle(nNr);
4103 After all styles are imported then we can recursively apply numbering
4104 styles to them, and change their tab stop settings if they turned out
4105 to have special first line indentation.
4107 void WW8RStyle::PostProcessStyles()
4109 USHORT i;
4111 Clear all imported flags so that we can recursively apply numbering
4112 formats and use it to mark handled ones
4114 for (i=0; i < cstd; ++i)
4115 pIo->pCollA[i].bImported = false;
4118 Register the num formats and tabstop changes on the styles recursively.
4122 In the same loop apply the tabstop changes required because we need to
4123 change their location if theres a special indentation for the first line,
4124 By avoiding making use of each styles margins during reading of their
4125 tabstops we don't get problems with doubly adjusting tabstops that
4126 are inheritied.
4128 for (i=0; i < cstd; ++i)
4130 if (pIo->pCollA[i].bValid)
4132 RecursiveReg(i);
4137 void WW8RStyle::ScanStyles() // untersucht Style-Abhaengigkeiten
4138 { // und ermittelt die Filepos fuer jeden Style
4140 WW8_FC nStyleStart = rFib.fcStshf;
4141 pStStrm->Seek( nStyleStart );
4143 for (USHORT i = 0; i < cstd; ++i)
4145 short nSkip;
4146 SwWW8StyInf &rSI = pIo->pCollA[i];
4148 rSI.nFilePos = pStStrm->Tell(); // merke FilePos
4149 WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD
4150 rSI.bValid = (0 != pStd);
4151 if (rSI.bValid)
4153 rSI.nBase = pStd->istdBase; // merke Basis
4154 rSI.bColl = ( pStd->sgc == 1 ); // Para-Style
4156 else
4157 rSI = SwWW8StyInf();
4159 delete pStd;
4160 pStStrm->SeekRel( nSkip ); // ueberlese Namen und Sprms
4164 std::vector<BYTE> ChpxToSprms(const Word2CHPX &rChpx)
4166 std::vector<BYTE> aRet;
4168 aRet.push_back(60);
4169 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBold) );
4171 aRet.push_back(61);
4172 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalic) );
4174 aRet.push_back(62);
4175 aRet.push_back( static_cast< BYTE >(128 + rChpx.fStrike) );
4177 aRet.push_back(63);
4178 aRet.push_back( static_cast< BYTE >(128 + rChpx.fOutline) );
4180 aRet.push_back(65);
4181 aRet.push_back( static_cast< BYTE >(128 + rChpx.fSmallCaps) );
4183 aRet.push_back(66);
4184 aRet.push_back( static_cast< BYTE >(128 + rChpx.fCaps) );
4186 aRet.push_back(67);
4187 aRet.push_back( static_cast< BYTE >(128 + rChpx.fVanish) );
4189 if (rChpx.fsFtc)
4191 aRet.push_back(68);
4192 SVBT16 a;
4193 ShortToSVBT16(rChpx.ftc, a);
4194 aRet.push_back(a[1]);
4195 aRet.push_back(a[0]);
4198 if (rChpx.fsKul)
4200 aRet.push_back(69);
4201 aRet.push_back(rChpx.kul);
4204 if (rChpx.fsLid)
4206 aRet.push_back(72);
4207 SVBT16 a;
4208 ShortToSVBT16(rChpx.lid, a);
4209 aRet.push_back(a[1]);
4210 aRet.push_back(a[0]);
4213 if (rChpx.fsIco)
4215 aRet.push_back(73);
4216 aRet.push_back(rChpx.ico);
4219 if (rChpx.fsHps)
4221 aRet.push_back(74);
4223 SVBT16 a;
4224 ShortToSVBT16(rChpx.hps, a);
4225 aRet.push_back(a[0]);
4226 // aRet.push_back(a[1]);
4229 if (rChpx.fsPos)
4231 aRet.push_back(76);
4232 aRet.push_back(rChpx.hpsPos);
4235 aRet.push_back(80);
4236 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBoldBi) );
4238 aRet.push_back(81);
4239 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalicBi) );
4241 if (rChpx.fsFtcBi)
4243 aRet.push_back(82);
4244 SVBT16 a;
4245 ShortToSVBT16(rChpx.fsFtcBi, a);
4246 aRet.push_back(a[1]);
4247 aRet.push_back(a[0]);
4250 if (rChpx.fsLidBi)
4252 aRet.push_back(83);
4253 SVBT16 a;
4254 ShortToSVBT16(rChpx.lidBi, a);
4255 aRet.push_back(a[1]);
4256 aRet.push_back(a[0]);
4259 if (rChpx.fsIcoBi)
4261 aRet.push_back(84);
4262 aRet.push_back(rChpx.icoBi);
4265 if (rChpx.fsHpsBi)
4267 aRet.push_back(85);
4268 SVBT16 a;
4269 ShortToSVBT16(rChpx.hpsBi, a);
4270 aRet.push_back(a[1]);
4271 aRet.push_back(a[0]);
4274 return aRet;
4277 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4279 Word2CHPX aChpx;
4281 if (!nSize)
4282 return aChpx;
4284 rSt.Seek(nOffset);
4286 sal_uInt8 nCount=0;
4288 while (1)
4290 sal_uInt8 nFlags8;
4291 rSt >> nFlags8;
4292 nCount++;
4294 aChpx.fBold = nFlags8 & 0x01;
4295 aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4296 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4297 aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4298 aChpx.fFldVanish = (nFlags8 & 0x10) >> 4;
4299 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4300 aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4301 aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4303 if (nCount >= nSize) break;
4304 rSt >> nFlags8;
4305 nCount++;
4307 aChpx.fRMark = nFlags8 & 0x01;
4308 aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4309 aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4310 aChpx.fObj = (nFlags8 & 0x08) >> 3;
4311 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4312 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4313 aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4314 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4316 if (nCount >= nSize) break;
4317 rSt >> nFlags8;
4318 nCount++;
4320 aChpx.fsIco = nFlags8 & 0x01;
4321 aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4322 aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4323 aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4324 aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4325 aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4326 aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4327 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4329 if (nCount >= nSize) break;
4330 rSt >> nFlags8;
4331 nCount++;
4333 aChpx.fsFtcBi = nFlags8 & 0x01;
4334 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4335 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4337 if (nCount >= nSize) break;
4338 rSt >> aChpx.ftc;
4339 nCount+=2;
4341 if (nCount >= nSize) break;
4342 rSt >> aChpx.hps;
4343 nCount+=2;
4345 if (nCount >= nSize) break;
4346 rSt >> nFlags8;
4347 nCount++;
4349 aChpx.qpsSpace = nFlags8 & 0x3F;
4350 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4351 aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4353 if (nCount >= nSize) break;
4354 rSt >> nFlags8;
4355 nCount++;
4357 aChpx.ico = nFlags8 & 0x1F;
4358 aChpx.kul = (nFlags8 & 0xE0) >> 5;
4360 if (nCount >= nSize) break;
4361 rSt >> aChpx.hpsPos;
4362 nCount++;
4364 if (nCount >= nSize) break;
4365 rSt >> aChpx.icoBi;
4366 nCount++;
4368 if (nCount >= nSize) break;
4369 rSt >> aChpx.lid;
4370 nCount+=2;
4372 if (nCount >= nSize) break;
4373 rSt >> aChpx.ftcBi;
4374 nCount+=2;
4376 if (nCount >= nSize) break;
4377 rSt >> aChpx.hpsBi;
4378 nCount+=2;
4380 if (nCount >= nSize) break;
4381 rSt >> aChpx.lidBi;
4382 nCount+=2;
4384 if (nCount >= nSize) break;
4385 rSt >> aChpx.fcPic;
4386 nCount+=4;
4388 break;
4391 rSt.SeekRel(nSize-nCount);
4392 return aChpx;
4395 namespace
4397 struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4400 void WW8RStyle::ImportOldFormatStyles()
4402 for (sal_uInt16 i=0; i < cstd; ++i)
4404 pIo->pCollA[i].bColl = true;
4405 //every chain must end eventually at the null style (style code 222)
4406 pIo->pCollA[i].nBase = 222;
4409 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4410 pIo->pWwFib->chseTables);
4412 sal_uInt16 cstcStd;
4413 rSt >> cstcStd;
4415 sal_uInt16 cbName;
4416 rSt >> cbName;
4417 sal_uInt16 nByteCount = 2;
4418 USHORT stcp=0;
4419 while (nByteCount < cbName)
4421 sal_uInt8 nCount;
4422 rSt >> nCount;
4423 nByteCount++;
4425 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4426 SwWW8StyInf &rSI = pIo->pCollA[stc];
4427 if (nCount != 0xFF) // undefined style
4429 String sName;
4430 if (nCount == 0) // inbuilt style
4432 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4433 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4434 sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4435 else
4436 sName = String(CREATE_CONST_ASC("Unknown"));
4438 else // user style
4440 ByteString aTmp;
4441 nByteCount = static_cast< sal_uInt16 >(nByteCount + SafeReadString(aTmp, nCount, rSt));
4442 sName = String(aTmp, eStructChrSet);
4444 rSI.SetOrgWWIdent(sName, stc);
4445 rSI.bImported = true;
4447 else
4449 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4450 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4452 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4453 rSI.SetOrgWWIdent(sName, stc);
4456 stcp++;
4459 USHORT nStyles=stcp;
4461 std::vector<pxoffset> aCHPXOffsets(stcp);
4462 sal_uInt16 cbChpx;
4463 rSt >> cbChpx;
4464 nByteCount = 2;
4465 stcp=0;
4466 std::vector< std::vector<BYTE> > aConvertedChpx;
4467 while (nByteCount < cbChpx)
4469 sal_uInt8 cb;
4470 rSt >> cb;
4471 nByteCount++;
4473 aCHPXOffsets[stcp].mnSize = 0;
4475 if (cb != 0xFF)
4477 sal_uInt8 nRemainder = cb;
4479 aCHPXOffsets[stcp].mnOffset = rSt.Tell();
4480 aCHPXOffsets[stcp].mnSize = nRemainder;
4482 Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset,
4483 aCHPXOffsets[stcp].mnSize);
4484 aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4486 nByteCount += nRemainder;
4488 else
4489 aConvertedChpx.push_back( std::vector<BYTE>() );
4491 stcp++;
4492 if (stcp == nStyles)
4494 rSt.SeekRel(cbChpx-nByteCount);
4495 nByteCount += cbChpx-nByteCount;
4499 std::vector<pxoffset> aPAPXOffsets(stcp);
4500 sal_uInt16 cbPapx;
4501 rSt >> cbPapx;
4502 nByteCount = 2;
4503 stcp=0;
4504 while (nByteCount < cbPapx)
4506 sal_uInt8 cb;
4507 rSt >> cb;
4508 nByteCount++;
4510 aPAPXOffsets[stcp].mnSize = 0;
4512 if (cb != 0xFF)
4514 sal_uInt8 stc2;
4515 rSt >> stc2;
4516 rSt.SeekRel(6);
4517 nByteCount+=7;
4518 sal_uInt8 nRemainder = cb-7;
4520 aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4521 aPAPXOffsets[stcp].mnSize = nRemainder;
4523 rSt.SeekRel(nRemainder);
4524 nByteCount += nRemainder;
4527 stcp++;
4529 if (stcp == nStyles)
4531 rSt.SeekRel(cbPapx-nByteCount);
4532 nByteCount += cbPapx-nByteCount;
4536 sal_uInt16 iMac;
4537 rSt >> iMac;
4539 if (iMac > nStyles) iMac = nStyles;
4541 for (stcp = 0; stcp < iMac; ++stcp)
4543 sal_uInt8 stcNext, stcBase;
4544 rSt >> stcNext;
4545 rSt >> stcBase;
4547 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4550 #i64557# style based on itself
4551 every chain must end eventually at the null style (style code 222)
4553 if (stc == stcBase)
4554 stcBase = 222;
4556 SwWW8StyInf &rSI = pIo->pCollA[stc];
4557 rSI.nBase = stcBase;
4559 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4561 if (eSti == ww::stiNil)
4562 continue;
4564 rSI.bValid = true;
4566 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4567 pIo->pCollA[stc].bColl = false;
4569 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4571 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4572 true);
4574 if (aConvertedChpx[stcp].size() > 0)
4575 ImportSprms(&(aConvertedChpx[stcp][0]),
4576 static_cast< short >(aConvertedChpx[stcp].size()),
4577 false);
4579 PostStyle(rSI, bOldNoImp);
4583 void WW8RStyle::ImportNewFormatStyles()
4585 ScanStyles(); // Scanne Based On
4587 for (USHORT i = 0; i < cstd; ++i) // import Styles
4588 if (pIo->pCollA[i].bValid)
4589 Import1Style( i );
4592 void WW8RStyle::ImportStyles()
4594 if (ww::eWW2 == pIo->pWwFib->GetFIBVersion())
4595 ImportOldFormatStyles();
4596 else
4597 ImportNewFormatStyles();
4600 void WW8RStyle::Import()
4602 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4603 pIo->pStandardFmtColl =
4604 pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
4606 if( pIo->nIniFlags & WW8FL_NO_STYLES )
4607 return;
4609 ImportStyles();
4611 for (USHORT i = 0; i < cstd; ++i)
4613 // Follow chain
4614 SwWW8StyInf* pi = &pIo->pCollA[i];
4615 USHORT j = pi->nFollow;
4616 if( j < cstd )
4618 SwWW8StyInf* pj = &pIo->pCollA[j];
4619 if ( j != i // sinnvoller Index ?
4620 && pi->pFmt // Format ok ?
4621 && pj->pFmt // Derived-Format ok ?
4622 && pi->bColl // geht nur bei Absatz-Vorlagen (WW)
4623 && pj->bColl ){ // beides gleicher Typ ?
4624 ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl(
4625 *(SwTxtFmtColl*)pj->pFmt ); // ok, eintragen
4629 // Die Sonderbehandlung zur Setzen der
4630 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt
4631 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der
4632 // WW-UI nicht zu veraendern, so dass das nicht stoert.
4633 // Der Mechanismus waere folgender:
4634 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4636 // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht
4638 if( pIo->pCollA[0].pFmt && pIo->pCollA[0].bColl && pIo->pCollA[0].bValid )
4639 pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->pCollA[0].pFmt;
4640 else
4641 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4644 // set Hyphenation flag on BASIC para-style
4645 if (pIo->mbNewDoc && pIo->pStandardFmtColl)
4647 if (pIo->pWDop->fAutoHyphen
4648 && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(
4649 RES_PARATR_HYPHENZONE, false) )
4651 SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4652 aAttr.GetMinLead() = 2;
4653 aAttr.GetMinTrail() = 2;
4654 aAttr.GetMaxHyphens() = 0;
4656 pIo->pStandardFmtColl->SetFmtAttr( aAttr );
4660 Word defaults to ltr not from environment like writer. Regardless of
4661 the page/sections rtl setting the standard style lack of rtl still
4662 means ltr
4664 if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR,
4665 false))
4667 pIo->pStandardFmtColl->SetFmtAttr(
4668 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4672 // wir sind jetzt nicht mehr beim Style einlesen:
4673 pIo->pAktColl = 0;
4676 CharSet SwWW8StyInf::GetCharSet() const
4678 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4679 return eRTLFontSrcCharSet;
4680 return eLTRFontSrcCharSet;
4683 /* vi:set tabstop=4 shiftwidth=4 expandtab: */