merge the formfield patch from ooo-build
[ooovba.git] / sw / source / filter / ww8 / ww8par2.cxx
blob2f5db05f5028361ca33724766bb8f2b5cf3a3c4d
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.DeleteRange( *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.DeleteRange( *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) ||
2386 (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used
2387 eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2389 nDefaultSwCols = nMinCols; // da Zellen einfuegen billiger ist als Mergen
2390 if( nDefaultSwCols == 0 )
2391 bOk = false;
2392 pActBand = pFirstBand;
2393 nAktBandRow = 0;
2394 ASSERT( pActBand, "pActBand ist 0" );
2397 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt)
2399 SwFrmFmt* pApply = pFrmFmt;
2400 if (!pApply )
2401 pApply = pTable->GetFrmFmt();
2402 ASSERT(pApply,"No frame");
2403 pApply->SetFmtAttr(aItemSet);
2404 if (pFrmFmt)
2406 SwFmtFrmSize aSize = pFrmFmt->GetFrmSize();
2407 aSize.SetHeightSizeType(ATT_MIN_SIZE);
2408 aSize.SetHeight(MINLAY);
2409 pFrmFmt->SetFmtAttr(aSize);
2410 pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL));
2414 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2415 const SwNode &rNode)
2417 ASSERT(!maSegments.empty(),
2418 "should not be possible, must be at least one segment");
2419 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2420 maSegments.back().maStart = SwNodeIndex(rNode);
2423 void WW8TabDesc::CreateSwTable()
2425 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
2427 // if there is already some content on the Node append new node to ensure
2428 // that this content remains ABOVE the table
2429 SwPosition* pPoint = pIo->pPaM->GetPoint();
2430 bool bInsNode = pPoint->nContent.GetIndex() ? true : false;
2431 bool bSetMinHeight = false;
2434 #i8062#
2435 Set fly anchor to its anchor pos, so that if a table starts immediately
2436 at this position a new node will be inserted before inserting the table.
2438 if (!bInsNode && pIo->pFmtOfJustInsertedApo)
2440 const SwPosition* pAPos =
2441 pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor();
2442 if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2444 bInsNode = true;
2445 bSetMinHeight = true;
2447 SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround());
2448 aSur.SetAnchorOnly(true);
2449 pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur);
2453 if (bSetMinHeight == true)
2455 // minimize Fontsize to minimize height growth of the header/footer
2456 // set font size to 1 point to minimize y-growth of Hd/Ft
2457 SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2458 pIo->NewAttr( aSz );
2459 pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2462 if (bInsNode)
2463 pIo->AppendTxtNode(*pPoint);
2465 pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() );
2467 // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist
2468 // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen
2469 // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender,
2470 // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen
2471 pTable = pIo->rDoc.InsertTable(
2472 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2473 *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, FALSE, TRUE );
2475 ASSERT(pTable && pTable->GetFrmFmt(), "insert table failed");
2476 if (!pTable || !pTable->GetFrmFmt())
2477 return;
2479 SwTableNode* pTableNode = pTable->GetTableNode();
2480 ASSERT(pTableNode, "no table node!");
2481 if (pTableNode)
2483 pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(),
2484 *pTableNode);
2487 // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits
2488 // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile
2489 // hinter der Tabelle rutschen, wo er nichts zu suchen hat. -> loeschen
2490 // und spaeter an das Tabellenformat setzen
2491 if (SwTxtNode* pNd = pIo->rDoc.GetNodes()[pTmpPos->nNode]->GetTxtNode())
2493 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2495 SfxPoolItem *pSetAttr = 0;
2496 const SfxPoolItem* pItem;
2497 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2499 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem );
2500 pNd->ResetAttr( RES_BREAK );
2503 // evtl den PageDesc/Break jetzt an der Tabelle setzen
2504 if (pSetAttr)
2506 aItemSet.Put(*pSetAttr);
2507 delete pSetAttr;
2512 // Gesamtbreite der Tabelle
2513 if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2515 pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2516 aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2519 SvxFrameDirectionItem aDirection(
2520 bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2521 pTable->GetFrmFmt()->SetFmtAttr(aDirection);
2523 if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2525 if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt &&
2526 GetMinLeft())
2528 //If we are inside a frame and we have a border, the frames
2529 //placement does not consider the tables border, which word
2530 //displays outside the frame, so adjust here.
2531 SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient());
2532 sal_Int16 eHori = aHori.GetHoriOrient();
2533 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2534 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2536 //With multiple table, use last table settings. Perhaps
2537 //the maximum is what word does ?
2538 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft());
2539 aHori.SetHoriOrient(text::HoriOrientation::NONE);
2540 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori);
2543 else
2545 //If bApo is set, then this table is being placed in a floating
2546 //frame, and the frame matches the left and right *lines* of the
2547 //table, so the space to the left of the table isn't to be used
2548 //inside the frame, in word the dialog involved greys out the
2549 //ability to set the margin.
2550 SvxLRSpaceItem aL( RES_LR_SPACE );
2551 // set right to original DxaLeft (i28656)
2553 long nLeft = 0;
2554 if (!bIsBiDi)
2555 nLeft = GetMinLeft();
2556 else
2558 if (nPreferredWidth)
2559 nLeft = pIo->maSectionManager.GetTextAreaWidth() - nPreferredWidth - nOrgDxaLeft;
2560 else
2561 nLeft = -GetMinLeft();
2564 aL.SetLeft(nLeft);
2566 aItemSet.Put(aL);
2570 mpOldRedlineStack = pIo->mpRedlineStack;
2571 pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc);
2574 void WW8TabDesc::UseSwTable()
2576 // globale Varis initialisieren
2577 pTabLines = &pTable->GetTabLines();
2578 nAktRow = nAktCol = nAktBandRow = 0;
2580 pTblNd = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]->
2581 GetSttNd()->FindTableNode();
2582 ASSERT( pTblNd, "wo ist mein TabellenNode" );
2584 // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value
2585 if ( nRowsToRepeat == static_cast<USHORT>(nRows) )
2586 nRowsToRepeat = 1;
2587 // <--
2589 pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2590 // ggfs. Zusatz-Zellen einfuegen u.dgl.
2591 AdjustNewBand();
2593 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2594 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false);
2596 // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten...
2597 SetPamInCell(nAktCol, true);
2598 aDup.Insert(*pIo->pPaM->GetPoint());
2600 pIo->bWasTabRowEnd = false;
2601 pIo->bWasTabCellEnd = false;
2604 void WW8TabDesc::MergeCells()
2606 short nRow;
2608 for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2611 // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen
2613 if( pActBand->pTCs )
2615 for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2616 for( short i = 0; i < pActBand->nWwCols; i++ )
2618 WW8SelBoxInfoPtr pActMGroup = 0;
2620 // ggfs. eine neue Merge-Gruppe beginnen
2622 ASSERT(nRow < pTabLines->Count(),
2623 "Too few lines, table ended early");
2624 if (nRow >= pTabLines->Count())
2625 return;
2626 pTabLine = (*pTabLines)[ nRow ];
2627 pTabBoxes = &pTabLine->GetTabBoxes();
2629 USHORT nCol = pActBand->nTransCell[ i ];
2630 if (!pActBand->bExist[i]) //#113434#
2631 continue;
2632 ASSERT(nCol < pTabBoxes->Count(),
2633 "Too few columns, table ended early");
2634 if (nCol >= pTabBoxes->Count())
2635 return;
2636 pTabBox = (*pTabBoxes)[nCol];
2637 WW8_TCell& rCell = pActBand->pTCs[ i ];
2638 // ist dies die obere, linke-Zelle einer Merge-Gruppe ?
2640 bool bMerge = false;
2641 if ( rCell.bVertRestart && !rCell.bMerged )
2642 bMerge = true;
2643 else if (rCell.bFirstMerged && pActBand->bExist[i])
2645 //#91211# Some tests to avoid merging cells
2646 //which previously were declared invalid because
2647 //of sharing the exact same dimensions as their
2648 //previous cell
2650 //If theres anything underneath/above we're ok.
2651 if (rCell.bVertMerge || rCell.bVertRestart)
2652 bMerge = true;
2653 else
2655 //If its a hori merge only, and the only things in
2656 //it are invalid cells then its already taken care
2657 //of, so don't merge.
2658 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2659 if (pActBand->pTCs[ i2 ].bMerged &&
2660 !pActBand->pTCs[ i2 ].bFirstMerged )
2662 if (pActBand->bExist[i2])
2664 bMerge = true;
2665 break;
2668 else
2669 break;
2674 if (bMerge)
2676 short nX1 = pActBand->nCenter[ i ];
2677 short nWidth = pActBand->nWidth[ i ];
2679 // 0. falls noetig das Array fuer die Merge-Gruppen
2680 // anlegen
2681 if( !pMergeGroups )
2682 pMergeGroups = new WW8MergeGroups;
2684 // 2. aktuelle Merge-Gruppe anlegen
2685 pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2687 // --> OD 2005-02-04 #118544# - determine size of new
2688 // merge group before inserted the new merge group.
2689 // Needed to correctly locked previously created merge groups.
2690 // Gesamtbreite ermitteln und zuweisen
2691 short nSizCell = pActBand->nWidth[ i ];
2692 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2693 if (pActBand->pTCs[ i2 ].bMerged &&
2694 !pActBand->pTCs[ i2 ].bFirstMerged )
2696 nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2698 else
2699 break;
2700 pActMGroup->nGroupWidth = nSizCell;
2701 // <--
2703 // --> OD 2005-02-03 #118544# - locked previously
2704 // created merge groups, after determining the size
2705 // for the new merge group.
2706 // 1. ggfs. alte Mergegruppe(n) schliessen, die
2707 // den von unserer neuen Gruppe betroffenen
2708 // X-Bereich ueberdecken
2709 short nMGrIdx;
2710 while ( FindMergeGroup( nX1, pActMGroup->nGroupWidth,
2711 false, nMGrIdx ) )
2713 (*pMergeGroups)[ nMGrIdx ]->bGroupLocked = true;
2715 // <--
2717 // 3. und in Gruppen-Array eintragen
2718 pMergeGroups->Insert(pActMGroup, pMergeGroups->Count());
2721 // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies
2722 // kann eine soeben angelegte, oder eine andere Gruppe
2723 // sein)
2724 UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2730 //There is a limbo area in word at the end of the row marker
2731 //where properties can live in word, there is no location in
2732 //writer equivalent, so try and park the cursor in the best
2733 //match, see #i23022#/#i18644#
2734 void WW8TabDesc::ParkPaM()
2736 SwTableBox *pTabBox2 = 0;
2737 short nRow = nAktRow + 1;
2738 if (nRow < pTabLines->Count())
2740 if (SwTableLine *pLine = (*pTabLines)[nRow])
2742 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2743 pTabBox2 = rBoxes.Count() ? rBoxes[0] : 0;
2747 if (!pTabBox2 || !pTabBox2->GetSttNd())
2749 MoveOutsideTable();
2750 return;
2753 if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1)
2755 pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1;
2756 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2757 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2761 void WW8TabDesc::MoveOutsideTable()
2763 ASSERT(pTmpPos && pIo, "I've forgotten where the table is anchored");
2764 if (pTmpPos && pIo)
2765 *pIo->pPaM->GetPoint() = *pTmpPos;
2768 void WW8TabDesc::FinishSwTable()
2770 pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint());
2771 delete pIo->mpRedlineStack;
2772 pIo->mpRedlineStack = mpOldRedlineStack;
2773 mpOldRedlineStack = 0;
2775 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2776 pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false);
2778 MoveOutsideTable();
2779 delete pTmpPos, pTmpPos = 0;
2781 aDup.Insert(*pIo->pPaM->GetPoint());
2783 pIo->bWasTabRowEnd = false;
2784 pIo->bWasTabCellEnd = false;
2786 pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM);
2788 MergeCells();
2790 // falls noetig, zu mergende Zellen gruppenweise zusammenfassen
2791 if( pMergeGroups )
2793 // bearbeite alle Merge-Gruppen nacheinander
2794 WW8SelBoxInfo* pActMGroup;
2795 USHORT nActBoxCount;
2797 for (USHORT iGr = 0; iGr < pMergeGroups->Count(); ++iGr)
2799 pActMGroup = (*pMergeGroups)[ iGr ];
2800 nActBoxCount = pActMGroup->Count();
2802 if( ( 1 < nActBoxCount ) && pActMGroup && (*pActMGroup)[ 0 ] )
2804 const USHORT nRowSpan = pActMGroup->Count();
2805 for (USHORT n = 0; n < nRowSpan; ++n)
2807 SwTableBox* pCurrentBox = (*pActMGroup)[n];
2808 const long nRowSpanSet = n == 0 ?
2809 nRowSpan :
2810 ((-1) * (nRowSpan - n));
2811 pCurrentBox->setRowSpan( nRowSpanSet );
2815 pIo->pFmtOfJustInsertedApo = 0;
2816 DELETEZ( pMergeGroups );
2821 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1
2823 // Parameter: nXcenter = Mittenposition der anfragenden Box
2824 // nWidth = Breite der anfragenden Box
2825 // bExact = Flag, ob Box in dieser Gruppe passen muss,
2826 // oder diese nur zu tangieren braucht
2828 bool WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact,
2829 short& nMGrIdx)
2831 nMGrIdx = -1;
2832 if( pMergeGroups )
2834 // noch als gueltig angesehener Bereich in der Naehe der Grenzen
2835 const short nToleranz = 4;
2836 // die aktuell untersuchte Gruppe
2837 WW8SelBoxInfoPtr pActGroup;
2838 // Boxgrenzen
2839 short nX2 = nX1 + nWidth;
2840 // ungefaehre Gruppengrenzen
2841 short nGrX1;
2842 short nGrX2;
2844 // --> OD 2005-02-04 #118544# - improvement: search backwards
2845 //for ( USHORT iGr = 0; iGr < pMergeGroups->Count(); iGr++ )
2846 for ( short iGr = pMergeGroups->Count() - 1; iGr >= 0; --iGr )
2848 // die aktuell untersuchte Gruppe
2849 pActGroup = (*pMergeGroups)[ iGr ];
2850 if (!pActGroup->bGroupLocked)
2852 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin
2853 nGrX1 = pActGroup->nGroupXStart - nToleranz;
2854 nGrX2 = pActGroup->nGroupXStart
2855 +pActGroup->nGroupWidth + nToleranz;
2857 // Falls Box reinpasst, melde auf jeden Fall den Erfolg
2859 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2861 nMGrIdx = iGr; break;
2864 // hat die Box Bereiche mit der Gruppe gemeinsam?
2866 if( !bExact )
2868 // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen
2869 if( ( ( nX1 > nGrX1 )
2870 && ( nX1 < nGrX2 - 2*nToleranz ) )
2871 || ( ( nX2 > nGrX1 + 2*nToleranz )
2872 && ( nX2 < nGrX2 ) )
2873 // oder nX1 und nX2 die Gruppe umfassen
2874 || ( ( nX1 <=nGrX1 )
2875 && ( nX2 >=nGrX2 ) ) )
2877 nMGrIdx = iGr; break;
2883 return ( -1 < nMGrIdx );
2886 bool WW8TabDesc::IsValidCell(short nCol) const
2888 return pActBand->bExist[nCol] && (USHORT)nAktRow < pTabLines->Count();
2891 bool WW8TabDesc::InFirstParaInCell() const
2893 //e.g. #i19718#
2894 if (!pTabBox || !pTabBox->GetSttNd())
2896 ASSERT(false, "Problem with table");
2897 return false;
2900 if (!IsValidCell(GetAktCol()))
2901 return false;
2903 if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2904 return true;
2906 return false;
2909 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2911 ASSERT(pActBand, "Impossible");
2912 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2914 pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(),
2915 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2919 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2921 ASSERT(pActBand, "Impossible");
2922 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2923 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE);
2926 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2928 ASSERT( pActBand, "pActBand ist 0" );
2930 USHORT nCol = pActBand->nTransCell[nWwCol];
2932 if ((USHORT)nAktRow >= pTabLines->Count())
2934 ASSERT(!this, "Actual row bigger than expected." );
2935 if (bPam)
2936 MoveOutsideTable();
2937 return false;
2940 pTabLine = (*pTabLines)[nAktRow];
2941 pTabBoxes = &pTabLine->GetTabBoxes();
2943 if (nCol >= pTabBoxes->Count())
2945 if (bPam)
2947 // The first paragraph in a cell with upper autospacing has upper
2948 // spacing set to 0
2949 if (
2950 pIo->bParaAutoBefore && pIo->bFirstPara &&
2951 !pIo->pWDop->fDontUseHTMLAutoSpacing
2954 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2957 // The last paragraph in a cell with lower autospacing has lower
2958 // spacing set to 0
2959 if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2960 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2962 ParkPaM();
2964 return false;
2966 pTabBox = (*pTabBoxes)[nCol];
2967 if( !pTabBox->GetSttNd() )
2969 ASSERT(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2970 if (bPam)
2971 MoveOutsideTable();
2972 return false;
2974 if (bPam)
2976 pAktWWCell = &pActBand->pTCs[ nWwCol ];
2978 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2979 if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2980 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2982 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2983 if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2984 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2986 //We need to set the pPaM on the first cell, invalid
2987 //or not so that we can collect paragraph proproties over
2988 //all the cells, but in that case on the valid cell we do not
2989 //want to reset the fmt properties
2990 if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1)
2992 pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1;
2993 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2994 // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die
2995 // zum Randausgleich eingefuegt werden, sonst der Style
2996 // nicht gesetzt wird.
2997 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2998 // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind,
2999 // und nur dazu dienen, zerfranste Aussehen der WW-Tabelle
3000 // nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel()
3001 // verwendet zu werden.
3004 // Better to turn Snap to Grid off for all paragraphs in tables
3005 if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode())
3007 const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID);
3008 SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm);
3010 if(rSnapToGrid.GetValue())
3012 SvxParaGridItem aGridItem( rSnapToGrid );
3013 aGridItem.SetValue(false);
3015 SwPosition* pGridPos = pIo->pPaM->GetPoint();
3017 xub_StrLen nEnd = pGridPos->nContent.GetIndex();
3018 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3019 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem);
3020 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd);
3021 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
3025 StartMiserableHackForUnsupportedDirection(nWwCol);
3027 return true;
3030 void WW8TabDesc::InsertCells( short nIns )
3032 pTabLine = (*pTabLines)[nAktRow];
3033 pTabBoxes = &pTabLine->GetTabBoxes();
3034 pTabBox = (*pTabBoxes)[0];
3036 pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(),
3037 (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->Count(), nIns );
3038 // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben.
3039 // hier kann man auch noch optimieren, um FrmFmts zu sparen
3042 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3044 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3045 return; // kuenstlich erzeugte Zellen -> Kein Rand
3048 SvxBoxItem aFmtBox( RES_BOX );
3049 if (pActBand->pTCs) // neither Cell Border nor Default Border defined ?
3051 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3052 if (pIo->IsBorder(pT->rgbrc))
3053 pIo->SetBorder(aFmtBox, pT->rgbrc);
3056 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
3058 aFmtBox.SetDistance(
3059 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
3060 BOX_LINE_TOP);
3062 else
3063 aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP);
3064 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
3066 aFmtBox.SetDistance(
3067 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
3068 BOX_LINE_BOTTOM);
3070 else
3071 aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM);
3073 // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen
3074 // Tabellenzelle und -Inhalt
3075 short nLeftDist =
3076 pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
3077 short nRightDist =
3078 pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
3079 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
3081 aFmtBox.SetDistance(
3082 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
3083 BOX_LINE_LEFT);
3085 else
3086 aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT);
3087 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
3089 aFmtBox.SetDistance(
3090 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
3091 BOX_LINE_RIGHT);
3093 else
3094 aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT);
3096 pBox->GetFrmFmt()->SetFmtAttr(aFmtBox);
3099 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3101 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3102 return; // kuenstlich erzeugte Zellen -> Keine Farbe
3104 bool bFound=false;
3105 if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3107 Color aColor(pActBand->pNewSHDs[nWwIdx]);
3108 if (aColor.GetColor() == 0x00333333)
3109 pIo->maTracer.Log(sw::log::eAutoColorBg);
3110 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND));
3111 bFound = true;
3114 //If there was no new shades, or no new shade setting
3115 if (pActBand->pSHDs && !bFound)
3117 WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3118 if (!rSHD.GetValue()) // auto
3119 return;
3121 SwWW8Shade aSh( pIo->bVer67, rSHD );
3122 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3126 SvxFrameDirection MakeDirection(sal_uInt16 nCode, BOOL bIsBiDi)
3128 SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3129 // 1: Asian layout with rotated CJK characters
3130 // 5: Asian layout
3131 // 3: Western layout rotated by 90 degrees
3132 // 4: Western layout
3133 switch (nCode)
3135 default:
3136 ASSERT(eDir == 4, "unknown direction code, maybe its a bitfield");
3137 case 3:
3138 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3139 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3140 // <--
3141 break;
3142 case 5:
3143 eDir = FRMDIR_VERT_TOP_RIGHT;
3144 break;
3145 case 1:
3146 eDir = FRMDIR_VERT_TOP_RIGHT;
3147 break;
3148 case 4:
3149 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3150 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3151 // <--
3152 break;
3154 return eDir;
3157 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3159 if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3160 return;
3161 SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3162 pBox->GetFrmFmt()->SetFmtAttr(aItem);
3165 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3167 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3168 return;
3170 sal_Int16 eVertOri=text::VertOrientation::TOP;
3172 if( pActBand->pTCs )
3174 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3175 switch (pT->nVertAlign)
3177 case 0:
3178 default:
3179 eVertOri = text::VertOrientation::TOP;
3180 break;
3181 case 1:
3182 eVertOri = text::VertOrientation::CENTER;
3183 break;
3184 case 2:
3185 eVertOri = text::VertOrientation::BOTTOM;
3186 break;
3190 pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) );
3193 void WW8TabDesc::AdjustNewBand()
3195 if( pActBand->nSwCols > nDefaultSwCols ) // Zellen splitten
3196 InsertCells( pActBand->nSwCols - nDefaultSwCols );
3198 SetPamInCell( 0, false);
3199 ASSERT( pTabBoxes && pTabBoxes->Count() == (USHORT)pActBand->nSwCols,
3200 "Falsche Spaltenzahl in Tabelle" )
3202 if( bClaimLineFmt )
3204 pTabLine->ClaimFrmFmt(); // noetig wg. Zeilenhoehe
3205 SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3207 if (pActBand->nLineHeight == 0) // 0 = Auto
3208 aF.SetHeightSizeType( ATT_VAR_SIZE );
3209 else
3211 if (pActBand->nLineHeight < 0) // Pos = min, Neg = exakt
3213 aF.SetHeightSizeType(ATT_FIX_SIZE);
3214 pActBand->nLineHeight = -pActBand->nLineHeight;
3216 if (pActBand->nLineHeight < MINLAY) // nicht erlaubte Zeilenhoehe
3217 pActBand->nLineHeight = MINLAY;
3219 aF.SetHeight(pActBand->nLineHeight);// Min- / Exakt-Hoehe setzen
3221 pTabLine->GetFrmFmt()->SetFmtAttr(aF);
3224 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3225 //we can split the row
3226 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3227 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3228 // Word versions >= 2002.
3229 bool bSetCantSplit = pActBand->bCantSplit;
3230 if(bSetCantSplit)
3231 bSetCantSplit = pActBand->bCantSplit90;
3233 pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit));
3235 short i; // SW-Index
3236 short j; // WW-Index
3237 short nW; // Breite
3238 SwFmtFrmSize aFS( ATT_FIX_SIZE );
3239 j = pActBand->bLEmptyCol ? -1 : 0;
3241 for( i = 0; i < pActBand->nSwCols; i++ )
3243 // setze Zellenbreite
3244 if( j < 0 )
3245 nW = pActBand->nCenter[0] - nMinLeft;
3246 else
3248 //Set j to first non invalid cell
3249 while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3250 j++;
3252 if( j < pActBand->nWwCols )
3253 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3254 else
3255 nW = nMaxRight - pActBand->nCenter[j];
3256 pActBand->nWidth[ j ] = nW;
3259 SwTableBox* pBox = (*pTabBoxes)[i];
3260 // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter
3261 // verringern
3262 pBox->ClaimFrmFmt();
3264 SetTabBorders(pBox, j);
3266 // #i18128# word has only one line between adjoining vertical cells
3267 // we have to mimick this in the filter by picking the larger of the
3268 // sides and using that one on one side of the line (right)
3269 SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX));
3270 const SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT);
3271 int nCurrentRightLineWidth = 0;
3272 if(pLeftLine)
3273 nCurrentRightLineWidth = pLeftLine->GetInWidth() + pLeftLine->GetOutWidth() + pLeftLine->GetDistance();
3275 if (i != 0)
3277 SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3278 SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX));
3279 const SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT);
3280 int nOldBoxRightLineWidth = 0;
3281 if(pRightLine)
3282 nOldBoxRightLineWidth = pRightLine->GetInWidth() + pRightLine->GetOutWidth() + pRightLine->GetDistance();
3284 if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3285 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT);
3287 aOldBox.SetLine(0, BOX_LINE_RIGHT);
3288 pBox2->GetFrmFmt()->SetFmtAttr(aOldBox);
3291 pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox);
3293 SetTabVertAlign(pBox, j);
3294 SetTabDirection(pBox, j);
3295 if( pActBand->pSHDs || pActBand->pNewSHDs)
3296 SetTabShades(pBox, j);
3297 j++;
3299 aFS.SetWidth( nW );
3300 pBox->GetFrmFmt()->SetFmtAttr( aFS );
3302 // ueberspringe nicht existente Zellen
3303 while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3305 pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3306 j++;
3311 void WW8TabDesc::TableCellEnd()
3313 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
3315 EndMiserableHackForUnsupportedDirection(nAktCol);
3317 // neue Zeile
3318 if( pIo->bWasTabRowEnd )
3320 // bWasTabRowEnd will be deactivated in
3321 // SwWW8ImplReader::ProcessSpecial()
3323 USHORT iCol = GetLogicalWWCol();
3324 if (iCol < aNumRuleNames.size())
3326 aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3327 aNumRuleNames.end());
3330 nAktCol = 0;
3331 nAktRow++;
3332 nAktBandRow++;
3333 ASSERT( pActBand , "pActBand ist 0" );
3334 if( pActBand )
3336 if( nAktRow >= nRows ) // am Tabellenende gibt's nichts sinnvolles
3337 return; // mehr zu tun
3339 bool bNewBand = nAktBandRow >= pActBand->nRows;
3340 if( bNewBand )
3341 { // neues Band noetig ?
3342 pActBand = pActBand->pNextBand; //
3343 nAktBandRow = 0;
3344 ASSERT( pActBand, "pActBand ist 0" );
3345 AdjustNewBand();
3347 else
3349 SwTableBox* pBox = (*pTabBoxes)[0];
3350 SwSelBoxes aBoxes;
3351 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) );
3355 else
3356 { // neue Spalte ( Zelle )
3357 nAktCol++;
3359 SetPamInCell(nAktCol, true);
3361 // finish Annotated Level Numbering ?
3362 if (pIo->bAnl && !pIo->bAktAND_fNumberAcross)
3363 pIo->StopAllAnl(IsValidCell(nAktCol));
3366 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen
3367 SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell,
3368 WW8SelBoxInfo* pActGroup,
3369 SwTableBox* pActBox,
3370 USHORT nCol )
3372 // Rueckgabewert defaulten
3373 SwTableBox* pResult = 0;
3375 // pruefen, ob die Box zu mergen ist
3376 // --> OD 2005-02-04 #118544# - If cell is the first one to be merged,
3377 // a new merge group has to be provided.
3378 // E.g., it could be that a cell is the first one to be merged, but no
3379 // new merge group is provided, because the potential other cell to be merged
3380 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3381 if ( pActBand->bExist[ nCol ] &&
3382 ( ( rCell.bFirstMerged && pActGroup ) ||
3383 rCell.bMerged ||
3384 rCell.bVertMerge ||
3385 rCell.bVertRestart ) )
3386 // <--
3388 // passende Merge-Gruppe ermitteln
3389 WW8SelBoxInfo* pTheMergeGroup = 0;
3390 if( pActGroup )
3391 // Gruppe uebernehmen
3392 pTheMergeGroup = pActGroup;
3393 else
3395 // Gruppe finden
3396 short nMGrIdx;
3397 if( FindMergeGroup( pActBand->nCenter[ nCol ],
3398 pActBand->nWidth[ nCol ], true, nMGrIdx ) )
3399 pTheMergeGroup = (*pMergeGroups)[ nMGrIdx ];
3401 if( pTheMergeGroup )
3403 // aktuelle Box der Merge-Gruppe hinzufuegen
3404 pTheMergeGroup->Insert( pActBox, pTheMergeGroup->Count() );
3406 // Target-Box zurueckmelden
3407 pResult = (*pTheMergeGroup)[ 0 ];
3410 return pResult;
3414 USHORT WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3416 USHORT nCol = 0;
3417 if( pActBand && pActBand->pTCs)
3419 for( USHORT iCol = 1; iCol <= nAktCol; ++iCol )
3421 if( !pActBand->pTCs[ iCol-1 ].bMerged )
3422 ++nCol;
3425 return nCol;
3428 // find name of numrule valid for current WW-COL
3429 const String& WW8TabDesc::GetNumRuleName() const
3431 USHORT nCol = GetLogicalWWCol();
3432 if (nCol < aNumRuleNames.size())
3433 return aNumRuleNames[nCol];
3434 else
3435 return aEmptyStr;
3438 void WW8TabDesc::SetNumRuleName( const String& rName )
3440 USHORT nCol = GetLogicalWWCol();
3441 for (USHORT nSize = static_cast< USHORT >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3442 aNumRuleNames.push_back(aEmptyStr);
3443 aNumRuleNames[nCol] = rName;
3446 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp)
3448 // Entering a table so make sure the the FirstPara flag gets set
3449 bFirstPara = true;
3450 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3451 // Fussnote
3452 if (bReadNoTbl)
3453 return false;
3455 if (pTableDesc)
3456 maTableStack.push(pTableDesc);
3458 // --> OD 2005-01-27 #i33818# - determine absolute position object attributes,
3459 // if possible. It's needed for nested tables.
3460 WW8FlyPara* pTableWFlyPara( 0L );
3461 WW8SwFlyPara* pTableSFlyPara( 0L );
3462 // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame
3463 // only at-character, if absolute position object attributes are available.
3464 // Thus, default anchor type is as-character anchored.
3465 RndStdIds eAnchor( FLY_IN_CNTNT );
3466 // <--
3467 if ( nInTable )
3469 WW8_TablePos* pNestedTabPos( 0L );
3470 WW8_TablePos aNestedTabPos;
3471 WW8PLCFxSave1 aSave;
3472 pPlcxMan->GetPap()->Save( aSave );
3473 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
3474 WW8_CP nMyStartCp = nStartCp;
3475 if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) &&
3476 ParseTabPos( &aNestedTabPos, pPap ) )
3478 pNestedTabPos = &aNestedTabPos;
3480 pPlcxMan->GetPap()->Restore( aSave );
3481 if ( pNestedTabPos )
3483 ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos );
3484 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3485 if ( pTableWFlyPara )
3487 // --> OD 2007-07-03 #148498#
3488 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3489 // containing WW8 page top margin.
3490 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara,
3491 maSectionManager.GetWWPageTopMargin(),
3492 maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(),
3493 nIniFlyDx, nIniFlyDy);
3494 // <--
3495 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly
3496 // frame at-character
3497 eAnchor = FLY_AUTO_CNTNT;
3498 // <--
3502 // <--
3504 pTableDesc = new WW8TabDesc( this, nStartCp );
3506 if( pTableDesc->Ok() )
3508 int nNewInTable = nInTable + 1;
3509 if (InEqualApo(nNewInTable))
3511 ASSERT(pSFlyPara->pFlyFmt,
3512 "how could we be in a local apo and have no apo");
3515 if ( eAnchor == FLY_AUTO_CNTNT && !maTableStack.empty() && !InEqualApo(nNewInTable) )
3517 pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint());
3518 SfxItemSet aItemSet(rDoc.GetAttrPool(),
3519 RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3520 // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for
3521 // the nested table at-character.
3522 // --> OD 2005-03-21 #i45301#
3523 SwFmtAnchor aAnchor( eAnchor );
3524 aAnchor.SetAnchor( pTableDesc->pParentPos );
3525 aItemSet.Put( aAnchor );
3526 pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor,
3527 pTableDesc->pParentPos, &aItemSet);
3528 ASSERT( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor,
3529 "Not the anchor type requested!" );
3530 // <--
3531 MoveInsideFly(pTableDesc->pFlyFmt);
3533 pTableDesc->CreateSwTable();
3534 if (pTableDesc->pFlyFmt)
3536 pTableDesc->SetSizePosition(pTableDesc->pFlyFmt);
3537 // --> OD 2005-01-26 #i33818# - Use absolute position object
3538 // attributes, if existing, and apply them to the created Writer fly
3539 // frame.
3540 if ( pTableWFlyPara && pTableSFlyPara )
3542 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3543 SwFmtAnchor aAnchor( FLY_AUTO_CNTNT );
3544 aAnchor.SetAnchor( pTableDesc->pParentPos );
3545 aFlySet.Put( aAnchor );
3546 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet );
3548 else
3550 SwFmtHoriOrient aHori =
3551 pTableDesc->pTable->GetFrmFmt()->GetHoriOrient();
3552 pTableDesc->pFlyFmt->SetFmtAttr(aHori);
3553 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) );
3555 // <--
3556 // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave
3557 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3558 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( TRUE ) );
3559 // <--
3561 else
3562 pTableDesc->SetSizePosition(0);
3563 pTableDesc->UseSwTable();
3565 else
3566 PopTableDesc();
3568 // --> OD 2005-01-28 #i33818#
3569 delete pTableWFlyPara;
3570 delete pTableSFlyPara;
3571 // <--
3573 bool bSuccess = (0 != pTableDesc);
3574 if (bSuccess)
3576 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3577 static_cast<sal_Int32>(maTableStack.size())));
3579 return bSuccess;
3582 bool lcl_PamContainsFly(SwPaM & rPam)
3584 bool bResult = false;
3585 SwNodeRange aRg( rPam.Start()->nNode, rPam.End()->nNode );
3586 SwDoc * pDoc = rPam.GetDoc();
3588 sal_uInt16 n = 0;
3589 SwSpzFrmFmts * pSpzFmts = pDoc->GetSpzFrmFmts();
3590 sal_uInt16 nCount = pSpzFmts->Count();
3591 while (!bResult && n < nCount)
3593 SwFrmFmt* pFly = (*pSpzFmts)[n];
3594 const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
3596 switch (pAnchor->GetAnchorId())
3598 case FLY_AT_CNTNT:
3599 case FLY_AUTO_CNTNT:
3601 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
3603 if (pAPos != NULL &&
3604 aRg.aStart <= pAPos->nNode &&
3605 pAPos->nNode <= aRg.aEnd)
3607 bResult = true;
3610 break;
3611 default:
3612 break;
3615 ++n;
3618 return bResult;
3621 void SwWW8ImplReader::TabCellEnd()
3623 if (nInTable && pTableDesc)
3625 pTableDesc->TableCellEnd();
3628 bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3629 bReadTable = false;
3630 mpTableEndPaM.reset();
3633 void SwWW8ImplReader::Read_TabCellEnd( USHORT, const BYTE* pData, short nLen)
3635 if( ( nLen > 0 ) && ( *pData == 1 ) )
3636 bWasTabCellEnd = true;
3639 void SwWW8ImplReader::Read_TabRowEnd( USHORT, const BYTE* pData, short nLen ) // Sprm25
3641 if( ( nLen > 0 ) && ( *pData == 1 ) )
3642 bWasTabRowEnd = true;
3645 void SwWW8ImplReader::PopTableDesc()
3647 if (pTableDesc && pTableDesc->pFlyFmt)
3649 MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos);
3652 delete pTableDesc;
3653 if (maTableStack.empty())
3654 pTableDesc = 0;
3655 else
3657 pTableDesc = maTableStack.top();
3658 maTableStack.pop();
3662 void SwWW8ImplReader::StopTable()
3664 maTracer.LeaveEnvironment(sw::log::eTable);
3666 ASSERT(pTableDesc, "Panic, stop table with no table!");
3667 if (!pTableDesc)
3668 return;
3670 // We are leaving a table so make sure the next paragraph doesn't think
3671 // it's the first paragraph
3672 bFirstPara = false;
3674 pTableDesc->FinishSwTable();
3675 PopTableDesc();
3677 if (!maTableStack.empty())
3679 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3680 static_cast<sal_Int32>(maTableStack.size())));
3683 bReadTable = true;
3684 // --> OD 2009-04-16 #i101116#
3685 // Keep PaM on table end only for nested tables
3686 if ( nInTable > 1 )
3688 mpTableEndPaM.reset(new SwPaM(*pPaM));
3690 // <--
3693 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen
3694 // gebraucht.
3695 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle
3696 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand.
3697 short SwWW8ImplReader::GetTableLeft()
3699 return (pTableDesc) ? pTableDesc->GetMinLeft() : 0;
3702 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3704 if( !pTableDesc )
3705 return false;
3707 const WW8_TCell* pCell = pTableDesc->GetAktWWCell();
3709 return !pTableDesc->IsValidCell( pTableDesc->GetAktCol() )
3710 || ( pCell
3711 && ( !pCell->bFirstMerged
3712 && ( pCell->bMerged
3713 || ( pCell->bVertMerge
3714 && !pCell->bVertRestart
3721 USHORT SwWW8ImplReader::StyleUsingLFO( USHORT nLFOIndex ) const
3723 USHORT nRes = USHRT_MAX;
3724 if( pCollA )
3726 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3727 if( pCollA[ nI ].bValid
3728 && (nLFOIndex == pCollA[ nI ].nLFOIndex) )
3729 nRes = nI;
3731 return nRes;
3734 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const
3736 SwFmt* pRet = 0;
3737 if( pCollA )
3739 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3740 if( pCollA[ nI ].bValid
3741 && (rName.Equals( pCollA[ nI ].GetOrgWWName())) )
3743 pRet = pCollA[ nI ].pFmt;
3744 break;
3747 return pRet;
3750 //-----------------------------------------
3751 // class WW8RStyle
3752 //-----------------------------------------
3754 const BYTE* WW8RStyle::HasParaSprm( USHORT nId ) const
3756 if( !pParaSprms || !nSprmsLen )
3757 return 0;
3759 const BYTE* pSprms = pParaSprms;
3760 USHORT i, x;
3762 for( i=0; i < nSprmsLen; )
3764 USHORT nAktId = maSprmParser.GetSprmId(pSprms);
3765 // Sprm found ?
3766 if( nAktId == nId )
3767 return pSprms + maSprmParser.DistanceToData(nId);
3769 x = maSprmParser.GetSprmSize(nAktId, pSprms);
3770 i = i + x;
3771 pSprms += x;
3773 return 0; // Sprm not found
3776 void WW8RStyle::ImportSprms(BYTE *pSprms, short nLen, bool bPap)
3778 if (!nLen)
3779 return;
3781 if( bPap )
3783 pParaSprms = pSprms; // fuer HasParaSprms()
3784 nSprmsLen = nLen;
3787 while ( nLen > 0 )
3789 USHORT nL1 = pIo->ImportSprm(pSprms);
3790 nLen = nLen - nL1;
3791 pSprms += nL1;
3794 pParaSprms = 0;
3795 nSprmsLen = 0;
3798 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3800 if (!nLen)
3801 return;
3803 BYTE *pSprms = new BYTE[nLen];
3805 pStStrm->Seek(nPosFc);
3806 pStStrm->Read(pSprms, nLen);
3808 ImportSprms(pSprms, nLen, bPap);
3810 delete[] pSprms;
3813 static inline short WW8SkipOdd(SvStream* pSt )
3815 if ( pSt->Tell() & 0x1 )
3817 UINT8 c;
3818 pSt->Read( &c, 1 );
3819 return 1;
3821 return 0;
3824 static inline short WW8SkipEven(SvStream* pSt )
3826 if (!(pSt->Tell() & 0x1))
3828 UINT8 c;
3829 pSt->Read( &c, 1 );
3830 return 1;
3832 return 0;
3835 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3837 INT16 cbUPX;
3839 if( 0 < nLen ) // Empty ?
3841 if (bOdd)
3842 nLen = nLen - WW8SkipEven( pStStrm );
3843 else
3844 nLen = nLen - WW8SkipOdd( pStStrm );
3846 *pStStrm >> cbUPX;
3848 nLen-=2;
3850 if ( cbUPX > nLen )
3851 cbUPX = nLen; // !cbUPX auf nLen verkleinert!
3853 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3855 if( bPAP )
3857 UINT16 id;
3858 *pStStrm >> id;
3860 cbUPX-= 2;
3861 nLen-= 2;
3864 if( 0 < cbUPX )
3866 sal_Size nPos = pStStrm->Tell(); // falls etwas falsch interpretiert
3867 // wird, gehts danach wieder richtig
3868 ImportSprms( nPos, cbUPX, bPAP );
3870 if ( pStStrm->Tell() != nPos + cbUPX )
3871 pStStrm->Seek( nPos+cbUPX );
3873 nLen = nLen - cbUPX;
3877 return nLen;
3880 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3882 if( nLen <= 0 )
3883 return;
3884 if (bOdd)
3885 nLen = nLen - WW8SkipEven( pStStrm );
3886 else
3887 nLen = nLen - WW8SkipOdd( pStStrm );
3889 if( bPara ) // Grupx.Papx
3890 nLen = ImportUPX(nLen, true, bOdd);
3891 ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3894 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3895 : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()),
3896 pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0)
3898 pIo->pCollA = new SwWW8StyInf[ cstd ]; // Style-UEbersetzung WW->SW
3899 pIo->nColls = cstd;
3902 void WW8RStyle::Set1StyleDefaults()
3904 if (!bCJKFontChanged) // Style no CJK Font? set the default
3905 pIo->SetNewFontAttr(ftcStandardChpCJKStsh, true, RES_CHRATR_CJK_FONT);
3907 // see i25247
3908 const WW8_FFN* pF = pIo->pFonts->GetFont(3);
3909 if (pF)
3911 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(pF->chs);
3912 if ((ftcStandardChpCTLStsh == 0) && (eEnc == RTL_TEXTENCODING_MS_1255))
3913 ftcStandardChpCTLStsh = 3;
3916 if (ftcStandardChpCJKStsh == 0)
3917 ftcStandardChpCJKStsh = 2;
3919 if (!bCTLFontChanged) // Style no CTL Font? set the default
3920 pIo->SetNewFontAttr(ftcStandardChpCTLStsh, true, RES_CHRATR_CTL_FONT);
3922 //#88976# western 2nd to make western charset conversion the default
3923 if (!bFontChanged) // Style has no Font? set the default,
3925 pIo->SetNewFontAttr(ftcStandardChpStsh, true, RES_CHRATR_FONT);
3926 /* removed by a patch from cmc for #i52786#
3927 if (pIo->bVer67)
3928 SetStyleCharSet(pIo->pCollA[pIo->nAktColl]);
3932 if( !pIo->bNoAttrImport )
3934 // Style has no text color set, winword default is auto
3935 if ( !bTxtColChanged )
3936 pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3938 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3939 if( !bFSizeChanged )
3941 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3942 pIo->pAktColl->SetFmtAttr(aAttr);
3943 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3944 pIo->pAktColl->SetFmtAttr(aAttr);
3947 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3948 if( !bFCTLSizeChanged )
3950 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3951 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3952 pIo->pAktColl->SetFmtAttr(aAttr);
3955 if( pIo->pWDop->fWidowControl && !bWidowsChanged ) // Widows ?
3957 pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3958 pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3963 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3965 SwFmt* pColl;
3966 bool bStyExist;
3967 if (rSI.bColl)
3969 // Para-Style
3970 sw::util::ParaStyleMapper::StyleResult aResult =
3971 pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3972 pColl = aResult.first;
3973 bStyExist = aResult.second;
3975 else
3977 // Char-Style
3978 sw::util::CharStyleMapper::StyleResult aResult =
3979 pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3980 pColl = aResult.first;
3981 bStyExist = aResult.second;
3984 bool bImport = !bStyExist || pIo->mbNewDoc; // Inhalte Importieren ?
3985 bool bOldNoImp = pIo->bNoAttrImport;
3986 rSI.bImportSkipped = !bImport;
3988 if( !bImport )
3989 pIo->bNoAttrImport = true;
3990 else
3992 if (bStyExist)
3994 // --> OD 2007-01-25 #i73790# - method renamed
3995 pColl->ResetAllFmtAttr();
3996 // <--
3998 pColl->SetAuto(false); // nach Empfehlung JP
3999 } // macht die UI aber anders
4000 pIo->pAktColl = pColl;
4001 rSI.pFmt = pColl; // UEbersetzung WW->SW merken
4002 rSI.bImportSkipped = !bImport;
4004 // Set Based on style
4005 USHORT j = rSI.nBase;
4006 if (j != nThisStyle && j < cstd )
4008 SwWW8StyInf* pj = &pIo->pCollA[j];
4009 if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl)
4011 rSI.pFmt->SetDerivedFrom( pj->pFmt ); // ok, Based on eintragen
4012 rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
4013 rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
4014 rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
4015 rSI.n81Flags = pj->n81Flags;
4016 rSI.n81BiDiFlags = pj->n81BiDiFlags;
4017 rSI.nOutlineLevel = pj->nOutlineLevel;
4018 rSI.bParaAutoBefore = pj->bParaAutoBefore;
4019 rSI.bParaAutoAfter = pj->bParaAutoAfter;
4021 if (pj->pWWFly)
4022 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly);
4025 else if( pIo->mbNewDoc && bStyExist )
4026 rSI.pFmt->SetDerivedFrom(0);
4028 rSI.nFollow = nNextStyle; // Follow merken
4030 pStyRule = 0; // falls noetig, neu anlegen
4031 bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
4032 bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
4033 pIo->SetNAktColl( nThisStyle );
4034 pIo->bStyNormal = nThisStyle == 0;
4035 return bOldNoImp;
4038 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
4040 // Alle moeglichen Attribut-Flags zuruecksetzen,
4041 // da es in Styles keine Attr-Enden gibt
4043 pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol
4044 = pIo->bSpec = pIo->bObj = pIo->bSymbol = false;
4045 pIo->nCharFmt = -1;
4047 // If Style basiert auf Nichts oder Basis ignoriert
4048 if ((rSI.nBase >= cstd || pIo->pCollA[rSI.nBase].bImportSkipped) && rSI.bColl)
4050 //! Char-Styles funktionieren aus
4051 // unerfindlichen Gruenden nicht
4052 // -> dann evtl. harte WW-Defaults
4053 // reinsetzen
4054 Set1StyleDefaults();
4057 pStyRule = 0; // zur Sicherheit
4058 pIo->bStyNormal = false;
4059 pIo->SetNAktColl( 0 );
4060 pIo->bNoAttrImport = bOldNoImp;
4061 // rasch nochmal die Listen-Merk-Felder zuruecksetzen,
4062 // fuer den Fall dass sie beim einlesen des Styles verwendet wurden
4063 pIo->nLFOPosition = USHRT_MAX;
4064 pIo->nListLevel = WW8ListManager::nMaxLevel;
4067 void WW8RStyle::Import1Style( USHORT nNr )
4069 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4071 if( rSI.bImported || !rSI.bValid )
4072 return;
4074 rSI.bImported = true; // jetzt schon Flag setzen
4075 // verhindert endlose Rekursion
4077 // gueltig und nicht NIL und noch nicht Importiert
4079 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4080 Import1Style( rSI.nBase );
4082 pStStrm->Seek( rSI.nFilePos );
4084 short nSkip, cbStd;
4085 String sName;
4087 WW8_STD* pStd = Read1Style( nSkip, &sName, &cbStd );// lies Style
4089 if (pStd)
4090 rSI.SetOrgWWIdent( sName, pStd->sti );
4092 // either no Name or unused Slot or unknown Style
4094 if ( !pStd || (0 == sName.Len()) || ((1 != pStd->sgc) && (2 != pStd->sgc)) )
4096 pStStrm->SeekRel( nSkip );
4097 return;
4100 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(pStd->sti), nNr, pStd->istdNext);
4102 // falls etwas falsch interpretiert wird, gehts danach wieder richtig
4103 long nPos = pStStrm->Tell();
4105 //Variable parts of the STD start at even byte offsets, but "inside
4106 //the STD", which I take to meaning even in relation to the starting
4107 //position of the STD, which matches findings in #89439#, generally it
4108 //doesn't matter as the STSHI starts off nearly always on an even
4109 //offset
4111 //Import of the Style Contents
4112 ImportGrupx(nSkip, pStd->sgc == 1, rSI.nFilePos & 1);
4114 PostStyle(rSI, bOldNoImp);
4116 pStStrm->Seek( nPos+nSkip );
4117 delete pStd;
4120 void WW8RStyle::RecursiveReg(USHORT nNr)
4122 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4123 if( rSI.bImported || !rSI.bValid )
4124 return;
4126 rSI.bImported = true;
4128 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4129 RecursiveReg(rSI.nBase);
4131 pIo->RegisterNumFmtOnStyle(nNr);
4136 After all styles are imported then we can recursively apply numbering
4137 styles to them, and change their tab stop settings if they turned out
4138 to have special first line indentation.
4140 void WW8RStyle::PostProcessStyles()
4142 USHORT i;
4144 Clear all imported flags so that we can recursively apply numbering
4145 formats and use it to mark handled ones
4147 for (i=0; i < cstd; ++i)
4148 pIo->pCollA[i].bImported = false;
4151 Register the num formats and tabstop changes on the styles recursively.
4155 In the same loop apply the tabstop changes required because we need to
4156 change their location if theres a special indentation for the first line,
4157 By avoiding making use of each styles margins during reading of their
4158 tabstops we don't get problems with doubly adjusting tabstops that
4159 are inheritied.
4161 for (i=0; i < cstd; ++i)
4163 if (pIo->pCollA[i].bValid)
4165 RecursiveReg(i);
4170 void WW8RStyle::ScanStyles() // untersucht Style-Abhaengigkeiten
4171 { // und ermittelt die Filepos fuer jeden Style
4173 WW8_FC nStyleStart = rFib.fcStshf;
4174 pStStrm->Seek( nStyleStart );
4176 for (USHORT i = 0; i < cstd; ++i)
4178 short nSkip;
4179 SwWW8StyInf &rSI = pIo->pCollA[i];
4181 rSI.nFilePos = pStStrm->Tell(); // merke FilePos
4182 WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD
4183 rSI.bValid = (0 != pStd);
4184 if (rSI.bValid)
4186 rSI.nBase = pStd->istdBase; // merke Basis
4187 rSI.bColl = ( pStd->sgc == 1 ); // Para-Style
4189 else
4190 rSI = SwWW8StyInf();
4192 delete pStd;
4193 pStStrm->SeekRel( nSkip ); // ueberlese Namen und Sprms
4197 std::vector<BYTE> ChpxToSprms(const Word2CHPX &rChpx)
4199 std::vector<BYTE> aRet;
4201 aRet.push_back(60);
4202 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBold) );
4204 aRet.push_back(61);
4205 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalic) );
4207 aRet.push_back(62);
4208 aRet.push_back( static_cast< BYTE >(128 + rChpx.fStrike) );
4210 aRet.push_back(63);
4211 aRet.push_back( static_cast< BYTE >(128 + rChpx.fOutline) );
4213 aRet.push_back(65);
4214 aRet.push_back( static_cast< BYTE >(128 + rChpx.fSmallCaps) );
4216 aRet.push_back(66);
4217 aRet.push_back( static_cast< BYTE >(128 + rChpx.fCaps) );
4219 aRet.push_back(67);
4220 aRet.push_back( static_cast< BYTE >(128 + rChpx.fVanish) );
4222 if (rChpx.fsFtc)
4224 aRet.push_back(68);
4225 SVBT16 a;
4226 ShortToSVBT16(rChpx.ftc, a);
4227 aRet.push_back(a[1]);
4228 aRet.push_back(a[0]);
4231 if (rChpx.fsKul)
4233 aRet.push_back(69);
4234 aRet.push_back(rChpx.kul);
4237 if (rChpx.fsLid)
4239 aRet.push_back(72);
4240 SVBT16 a;
4241 ShortToSVBT16(rChpx.lid, a);
4242 aRet.push_back(a[1]);
4243 aRet.push_back(a[0]);
4246 if (rChpx.fsIco)
4248 aRet.push_back(73);
4249 aRet.push_back(rChpx.ico);
4252 if (rChpx.fsHps)
4254 aRet.push_back(74);
4256 SVBT16 a;
4257 ShortToSVBT16(rChpx.hps, a);
4258 aRet.push_back(a[0]);
4259 // aRet.push_back(a[1]);
4262 if (rChpx.fsPos)
4264 aRet.push_back(76);
4265 aRet.push_back(rChpx.hpsPos);
4268 aRet.push_back(80);
4269 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBoldBi) );
4271 aRet.push_back(81);
4272 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalicBi) );
4274 if (rChpx.fsFtcBi)
4276 aRet.push_back(82);
4277 SVBT16 a;
4278 ShortToSVBT16(rChpx.fsFtcBi, a);
4279 aRet.push_back(a[1]);
4280 aRet.push_back(a[0]);
4283 if (rChpx.fsLidBi)
4285 aRet.push_back(83);
4286 SVBT16 a;
4287 ShortToSVBT16(rChpx.lidBi, a);
4288 aRet.push_back(a[1]);
4289 aRet.push_back(a[0]);
4292 if (rChpx.fsIcoBi)
4294 aRet.push_back(84);
4295 aRet.push_back(rChpx.icoBi);
4298 if (rChpx.fsHpsBi)
4300 aRet.push_back(85);
4301 SVBT16 a;
4302 ShortToSVBT16(rChpx.hpsBi, a);
4303 aRet.push_back(a[1]);
4304 aRet.push_back(a[0]);
4307 return aRet;
4310 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4312 Word2CHPX aChpx;
4314 if (!nSize)
4315 return aChpx;
4317 rSt.Seek(nOffset);
4319 sal_uInt8 nCount=0;
4321 while (1)
4323 sal_uInt8 nFlags8;
4324 rSt >> nFlags8;
4325 nCount++;
4327 aChpx.fBold = nFlags8 & 0x01;
4328 aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4329 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4330 aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4331 aChpx.fFldVanish = (nFlags8 & 0x10) >> 4;
4332 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4333 aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4334 aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4336 if (nCount >= nSize) break;
4337 rSt >> nFlags8;
4338 nCount++;
4340 aChpx.fRMark = nFlags8 & 0x01;
4341 aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4342 aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4343 aChpx.fObj = (nFlags8 & 0x08) >> 3;
4344 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4345 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4346 aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4347 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4349 if (nCount >= nSize) break;
4350 rSt >> nFlags8;
4351 nCount++;
4353 aChpx.fsIco = nFlags8 & 0x01;
4354 aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4355 aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4356 aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4357 aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4358 aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4359 aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4360 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4362 if (nCount >= nSize) break;
4363 rSt >> nFlags8;
4364 nCount++;
4366 aChpx.fsFtcBi = nFlags8 & 0x01;
4367 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4368 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4370 if (nCount >= nSize) break;
4371 rSt >> aChpx.ftc;
4372 nCount+=2;
4374 if (nCount >= nSize) break;
4375 rSt >> aChpx.hps;
4376 nCount+=2;
4378 if (nCount >= nSize) break;
4379 rSt >> nFlags8;
4380 nCount++;
4382 aChpx.qpsSpace = nFlags8 & 0x3F;
4383 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4384 aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4386 if (nCount >= nSize) break;
4387 rSt >> nFlags8;
4388 nCount++;
4390 aChpx.ico = nFlags8 & 0x1F;
4391 aChpx.kul = (nFlags8 & 0xE0) >> 5;
4393 if (nCount >= nSize) break;
4394 rSt >> aChpx.hpsPos;
4395 nCount++;
4397 if (nCount >= nSize) break;
4398 rSt >> aChpx.icoBi;
4399 nCount++;
4401 if (nCount >= nSize) break;
4402 rSt >> aChpx.lid;
4403 nCount+=2;
4405 if (nCount >= nSize) break;
4406 rSt >> aChpx.ftcBi;
4407 nCount+=2;
4409 if (nCount >= nSize) break;
4410 rSt >> aChpx.hpsBi;
4411 nCount+=2;
4413 if (nCount >= nSize) break;
4414 rSt >> aChpx.lidBi;
4415 nCount+=2;
4417 if (nCount >= nSize) break;
4418 rSt >> aChpx.fcPic;
4419 nCount+=4;
4421 break;
4424 rSt.SeekRel(nSize-nCount);
4425 return aChpx;
4428 namespace
4430 struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4433 void WW8RStyle::ImportOldFormatStyles()
4435 for (sal_uInt16 i=0; i < cstd; ++i)
4437 pIo->pCollA[i].bColl = true;
4438 //every chain must end eventually at the null style (style code 222)
4439 pIo->pCollA[i].nBase = 222;
4442 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4443 pIo->pWwFib->chseTables);
4445 sal_uInt16 cstcStd;
4446 rSt >> cstcStd;
4448 sal_uInt16 cbName;
4449 rSt >> cbName;
4450 sal_uInt16 nByteCount = 2;
4451 USHORT stcp=0;
4452 while (nByteCount < cbName)
4454 sal_uInt8 nCount;
4455 rSt >> nCount;
4456 nByteCount++;
4458 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4459 SwWW8StyInf &rSI = pIo->pCollA[stc];
4460 if (nCount != 0xFF) // undefined style
4462 String sName;
4463 if (nCount == 0) // inbuilt style
4465 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4466 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4467 sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4468 else
4469 sName = String(CREATE_CONST_ASC("Unknown"));
4471 else // user style
4473 ByteString aTmp;
4474 nByteCount = static_cast< sal_uInt16 >(nByteCount + SafeReadString(aTmp, nCount, rSt));
4475 sName = String(aTmp, eStructChrSet);
4477 rSI.SetOrgWWIdent(sName, stc);
4478 rSI.bImported = true;
4480 else
4482 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4483 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4485 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4486 rSI.SetOrgWWIdent(sName, stc);
4489 stcp++;
4492 USHORT nStyles=stcp;
4494 std::vector<pxoffset> aCHPXOffsets(stcp);
4495 sal_uInt16 cbChpx;
4496 rSt >> cbChpx;
4497 nByteCount = 2;
4498 stcp=0;
4499 std::vector< std::vector<BYTE> > aConvertedChpx;
4500 while (nByteCount < cbChpx)
4502 sal_uInt8 cb;
4503 rSt >> cb;
4504 nByteCount++;
4506 aCHPXOffsets[stcp].mnSize = 0;
4508 if (cb != 0xFF)
4510 sal_uInt8 nRemainder = cb;
4512 aCHPXOffsets[stcp].mnOffset = rSt.Tell();
4513 aCHPXOffsets[stcp].mnSize = nRemainder;
4515 Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset,
4516 aCHPXOffsets[stcp].mnSize);
4517 aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4519 nByteCount += nRemainder;
4521 else
4522 aConvertedChpx.push_back( std::vector<BYTE>() );
4524 stcp++;
4525 if (stcp == nStyles)
4527 rSt.SeekRel(cbChpx-nByteCount);
4528 nByteCount += cbChpx-nByteCount;
4532 std::vector<pxoffset> aPAPXOffsets(stcp);
4533 sal_uInt16 cbPapx;
4534 rSt >> cbPapx;
4535 nByteCount = 2;
4536 stcp=0;
4537 while (nByteCount < cbPapx)
4539 sal_uInt8 cb;
4540 rSt >> cb;
4541 nByteCount++;
4543 aPAPXOffsets[stcp].mnSize = 0;
4545 if (cb != 0xFF)
4547 sal_uInt8 stc2;
4548 rSt >> stc2;
4549 rSt.SeekRel(6);
4550 nByteCount+=7;
4551 sal_uInt8 nRemainder = cb-7;
4553 aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4554 aPAPXOffsets[stcp].mnSize = nRemainder;
4556 rSt.SeekRel(nRemainder);
4557 nByteCount += nRemainder;
4560 stcp++;
4562 if (stcp == nStyles)
4564 rSt.SeekRel(cbPapx-nByteCount);
4565 nByteCount += cbPapx-nByteCount;
4569 sal_uInt16 iMac;
4570 rSt >> iMac;
4572 if (iMac > nStyles) iMac = nStyles;
4574 for (stcp = 0; stcp < iMac; ++stcp)
4576 sal_uInt8 stcNext, stcBase;
4577 rSt >> stcNext;
4578 rSt >> stcBase;
4580 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4583 #i64557# style based on itself
4584 every chain must end eventually at the null style (style code 222)
4586 if (stc == stcBase)
4587 stcBase = 222;
4589 SwWW8StyInf &rSI = pIo->pCollA[stc];
4590 rSI.nBase = stcBase;
4592 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4594 if (eSti == ww::stiNil)
4595 continue;
4597 rSI.bValid = true;
4599 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4600 pIo->pCollA[stc].bColl = false;
4602 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4604 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4605 true);
4607 if (aConvertedChpx[stcp].size() > 0)
4608 ImportSprms(&(aConvertedChpx[stcp][0]),
4609 static_cast< short >(aConvertedChpx[stcp].size()),
4610 false);
4612 PostStyle(rSI, bOldNoImp);
4616 void WW8RStyle::ImportNewFormatStyles()
4618 ScanStyles(); // Scanne Based On
4620 for (USHORT i = 0; i < cstd; ++i) // import Styles
4621 if (pIo->pCollA[i].bValid)
4622 Import1Style( i );
4625 void WW8RStyle::ImportStyles()
4627 if (ww::eWW2 == pIo->pWwFib->GetFIBVersion())
4628 ImportOldFormatStyles();
4629 else
4630 ImportNewFormatStyles();
4633 void WW8RStyle::Import()
4635 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4636 pIo->pStandardFmtColl =
4637 pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
4639 if( pIo->nIniFlags & WW8FL_NO_STYLES )
4640 return;
4642 ImportStyles();
4644 for (USHORT i = 0; i < cstd; ++i)
4646 // Follow chain
4647 SwWW8StyInf* pi = &pIo->pCollA[i];
4648 USHORT j = pi->nFollow;
4649 if( j < cstd )
4651 SwWW8StyInf* pj = &pIo->pCollA[j];
4652 if ( j != i // sinnvoller Index ?
4653 && pi->pFmt // Format ok ?
4654 && pj->pFmt // Derived-Format ok ?
4655 && pi->bColl // geht nur bei Absatz-Vorlagen (WW)
4656 && pj->bColl ){ // beides gleicher Typ ?
4657 ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl(
4658 *(SwTxtFmtColl*)pj->pFmt ); // ok, eintragen
4662 // Die Sonderbehandlung zur Setzen der
4663 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt
4664 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der
4665 // WW-UI nicht zu veraendern, so dass das nicht stoert.
4666 // Der Mechanismus waere folgender:
4667 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4669 // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht
4671 if( pIo->pCollA[0].pFmt && pIo->pCollA[0].bColl && pIo->pCollA[0].bValid )
4672 pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->pCollA[0].pFmt;
4673 else
4674 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4677 // set Hyphenation flag on BASIC para-style
4678 if (pIo->mbNewDoc && pIo->pStandardFmtColl)
4680 if (pIo->pWDop->fAutoHyphen
4681 && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(
4682 RES_PARATR_HYPHENZONE, false) )
4684 SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4685 aAttr.GetMinLead() = 2;
4686 aAttr.GetMinTrail() = 2;
4687 aAttr.GetMaxHyphens() = 0;
4689 pIo->pStandardFmtColl->SetFmtAttr( aAttr );
4693 Word defaults to ltr not from environment like writer. Regardless of
4694 the page/sections rtl setting the standard style lack of rtl still
4695 means ltr
4697 if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR,
4698 false))
4700 pIo->pStandardFmtColl->SetFmtAttr(
4701 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4705 // wir sind jetzt nicht mehr beim Style einlesen:
4706 pIo->pAktColl = 0;
4709 CharSet SwWW8StyInf::GetCharSet() const
4711 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4712 return eRTLFontSrcCharSet;
4713 return eLTRFontSrcCharSet;
4716 CharSet SwWW8StyInf::GetCJKCharSet() const
4718 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4719 return eRTLFontSrcCharSet;
4720 return eCJKFontSrcCharSet;
4723 /* vi:set tabstop=4 shiftwidth=4 expandtab: */