cmcfixes76: #i113073# redundant dereferences
[LibreOffice.git] / sw / source / filter / ww8 / ww8par2.cxx
blobf848b6332c38d85361d73e752aa5cefec1f1c811
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
32 #include <tools/solar.h>
33 #include <vcl/vclenum.hxx>
34 #include <vcl/font.hxx>
35 #include <hintids.hxx>
36 #include <editeng/colritem.hxx>
37 #include <editeng/orphitem.hxx>
38 #include <editeng/widwitem.hxx>
39 #include <editeng/brshitem.hxx>
40 #include <editeng/boxitem.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/fhgtitem.hxx>
43 #include <editeng/fhgtitem.hxx>
44 #include <editeng/hyznitem.hxx>
45 #include <editeng/frmdiritem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/charrotateitem.hxx>
48 #include <editeng/pgrditem.hxx>
49 #include <msfilter.hxx>
50 #include <pam.hxx> // fuer SwPam
51 #include <doc.hxx>
52 #include <docary.hxx>
53 #include <ndtxt.hxx> // class SwTxtNode
54 #include <paratr.hxx> // SwNumRuleItem
55 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD
56 #include <swtable.hxx> // class SwTableLines, ...
57 #include <tblsel.hxx> // class _SwSelBox
58 #include <mdiexp.hxx>
59 #include <fmtpdsc.hxx>
60 #include <txtftn.hxx>
61 #include <frmfmt.hxx>
62 #include <ftnidx.hxx>
63 #include <fmtftn.hxx>
64 #include <charfmt.hxx>
65 #include <SwStyleNameMapper.hxx>
66 #include <fltshell.hxx> // fuer den Attribut Stack
67 #include <fmtanchr.hxx>
68 #include <fmtrowsplt.hxx>
69 // --> OD 2005-01-27 #i33818#
70 #include <fmtfollowtextflow.hxx>
71 // <--
72 #include <numrule.hxx>
73 # include "../inc/wwstyles.hxx"
74 # include "writerhelper.hxx"
75 #include "ww8struc.hxx" // struct TC
76 #include "ww8par.hxx"
77 #include "ww8par2.hxx"
79 #include <frmatr.hxx>
81 #include <iostream>
83 #define MAX_COL 64 // WW6-Beschreibung: 32, WW6-UI: 31 & WW8-UI: 63!
85 using namespace ::com::sun::star;
88 class WW8SelBoxInfo: public SwSelBoxes_SAR
90 private:
91 WW8SelBoxInfo(const WW8SelBoxInfo&);
92 WW8SelBoxInfo& operator=(const WW8SelBoxInfo&);
93 public:
94 short nGroupXStart;
95 short nGroupWidth;
96 bool bGroupLocked;
98 WW8SelBoxInfo(short nXCenter, short nWidth)
99 : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
103 typedef WW8SelBoxInfo* WW8SelBoxInfoPtr;
105 SV_DECL_PTRARR_DEL(WW8MergeGroups, WW8SelBoxInfoPtr, 16,16)
106 SV_IMPL_PTRARR(WW8MergeGroups, WW8SelBoxInfoPtr)
108 struct WW8TabBandDesc
110 WW8TabBandDesc* pNextBand;
111 short nGapHalf;
112 short mnDefaultLeft;
113 short mnDefaultTop;
114 short mnDefaultRight;
115 short mnDefaultBottom;
116 bool mbHasSpacing;
117 short nLineHeight;
118 short nRows;
119 sal_uInt16 maDirections[MAX_COL + 1];
120 short nCenter[MAX_COL + 1]; // X-Rand aller Zellen dieses Bandes
121 short nWidth[MAX_COL + 1]; // Laenge aller Zellen dieses Bandes
122 short nWwCols; // BYTE wuerde reichen, alignment -> short
123 short nSwCols; // SW: so viele Spalten fuer den Writer
124 bool bLEmptyCol; // SW: Links eine leere Zusatz-Spalte
125 bool bREmptyCol; // SW: dito rechts
126 bool bCantSplit;
127 bool bCantSplit90;
128 WW8_TCell* pTCs;
129 BYTE nOverrideSpacing[MAX_COL + 1];
130 short nOverrideValues[MAX_COL + 1][4];
131 WW8_SHD* pSHDs;
132 sal_uInt32* pNewSHDs;
133 WW8_BRC aDefBrcs[6];
136 // nur fuer WW6-7: diese Zelle hat WW-Flag bMerged (horizontal) gesetzt
137 //bool bWWMergedVer6[MAX_COL];
140 bool bExist[MAX_COL]; // Existiert diese Zelle ?
141 UINT8 nTransCell[MAX_COL + 2]; // UEbersetzung WW-Index -> SW-Index
143 WW8TabBandDesc();
144 WW8TabBandDesc(WW8TabBandDesc& rBand); // tief kopieren
145 ~WW8TabBandDesc();
146 static void setcelldefaults(WW8_TCell *pCells, short nCells);
147 void ReadDef(bool bVer67, const BYTE* pS);
148 void ProcessDirection(const BYTE* pParams);
149 void ProcessSprmTSetBRC(bool bVer67, const BYTE* pParamsTSetBRC);
150 void ProcessSprmTTableBorders(bool bVer67, const BYTE* pParams);
151 void ProcessSprmTDxaCol(const BYTE* pParamsTDxaCol);
152 void ProcessSprmTDelete(const BYTE* pParamsTDelete);
153 void ProcessSprmTInsert(const BYTE* pParamsTInsert);
154 void ProcessSpacing(const BYTE* pParamsTInsert);
155 void ProcessSpecificSpacing(const BYTE* pParamsTInsert);
156 void ReadShd(const BYTE* pS );
157 void ReadNewShd(const BYTE* pS, bool bVer67);
159 enum wwDIR {wwTOP = 0, wwLEFT = 1, wwBOTTOM = 2, wwRIGHT = 3};
162 WW8TabBandDesc::WW8TabBandDesc()
164 memset(this, 0, sizeof(*this));
165 for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i)
166 maDirections[i] = 4;
169 WW8TabBandDesc::~WW8TabBandDesc()
171 delete[] pTCs;
172 delete[] pSHDs;
173 delete[] pNewSHDs;
176 class WW8TabDesc
178 std::vector<String> aNumRuleNames;
179 sw::util::RedlineStack *mpOldRedlineStack;
181 SwWW8ImplReader* pIo;
183 WW8TabBandDesc* pFirstBand;
184 WW8TabBandDesc* pActBand;
186 SwPosition* pTmpPos;
188 SwTableNode* pTblNd; // Tabellen-Node
189 const SwTableLines* pTabLines; // Zeilen-Array davon
190 SwTableLine* pTabLine; // akt. Zeile
191 SwTableBoxes* pTabBoxes; // Boxen-Array in akt. Zeile
192 SwTableBox* pTabBox; // akt. Zelle
194 WW8MergeGroups* pMergeGroups; // Listen aller zu verknuepfenden Zellen
196 WW8_TCell* pAktWWCell;
198 short nRows;
199 short nDefaultSwCols;
200 short nBands;
201 short nMinLeft;
202 short nConvertedLeft;
203 short nMaxRight;
204 short nSwWidth;
205 short nPreferredWidth;
206 short nOrgDxaLeft;
208 bool bOk;
209 bool bClaimLineFmt;
210 sal_Int16 eOri;
211 bool bIsBiDi;
212 // 2. allgemeine Verwaltungsinfo
213 short nAktRow;
214 short nAktBandRow; // SW: in dieser Zeile des akt. Bandes bin ich
215 // 3. Verwaltungsinfo fuer Writer
216 short nAktCol;
218 USHORT nRowsToRepeat;
220 // 4. Methoden
222 USHORT GetLogicalWWCol() const;
223 void SetTabBorders( SwTableBox* pBox, short nIdx );
224 void SetTabShades( SwTableBox* pBox, short nWwIdx );
225 void SetTabVertAlign( SwTableBox* pBox, short nWwIdx );
226 void SetTabDirection( SwTableBox* pBox, short nWwIdx );
227 void CalcDefaults();
228 bool SetPamInCell(short nWwCol, bool bPam);
229 void InsertCells( short nIns );
230 void AdjustNewBand();
232 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw.
233 // -1 Details siehe bei der Implementierung
234 bool FindMergeGroup(short nX1, short nWidth, bool bExact, short& nMGrIdx);
236 // einzelne Box ggfs. in eine Merge-Gruppe aufnehmen
237 // (die Merge-Gruppen werden dann spaeter auf einen Schlag abgearbeitet)
238 SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
239 WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, USHORT nCol );
240 void StartMiserableHackForUnsupportedDirection(short nWwCol);
241 void EndMiserableHackForUnsupportedDirection(short nWwCol);
242 //No copying
243 WW8TabDesc(const WW8TabDesc&);
244 WW8TabDesc &operator=(const WW8TabDesc&);
245 public:
246 const SwTable* pTable; // Tabelle
247 SwPosition* pParentPos;
248 SwFlyFrmFmt* pFlyFmt;
249 SfxItemSet aItemSet;
250 bool IsValidCell(short nCol) const;
251 bool InFirstParaInCell() const;
253 WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp );
254 bool Ok() const { return bOk; }
255 void CreateSwTable();
256 void UseSwTable();
257 void SetSizePosition(SwFrmFmt* pFrmFmt);
258 void TableCellEnd();
259 void MoveOutsideTable();
260 void ParkPaM();
261 void FinishSwTable();
262 void MergeCells();
263 short GetMinLeft() const { return nConvertedLeft; }
264 ~WW8TabDesc();
265 SwPosition *GetPos() { return pTmpPos; }
267 const WW8_TCell* GetAktWWCell() const { return pAktWWCell; }
268 short GetAktCol() const { return nAktCol; }
269 // find name of numrule valid for current WW-COL
270 const String& GetNumRuleName() const;
271 void SetNumRuleName( const String& rName );
273 sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; }
276 void sw::util::RedlineStack::close( const SwPosition& rPos,
277 RedlineType_t eType, WW8TabDesc* pTabDesc )
279 // If the redline type is not found in the redline stack, we have to check if there has been
280 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
281 if( !close( rPos, eType ) )
283 if( pTabDesc && pTabDesc->getOldRedlineStack() )
285 #ifdef DBG_UTIL
286 ASSERT( pTabDesc->getOldRedlineStack()->close(rPos, eType), "close without open!");
287 #else
288 pTabDesc->getOldRedlineStack()->close( rPos, eType );
289 #endif
295 void wwSectionManager::SetCurrentSectionHasFootnote()
297 ASSERT(!maSegments.empty(),
298 "should not be possible, must be at least one segment");
299 if (!maSegments.empty())
300 maSegments.back().mbHasFootnote = true;
303 bool wwSectionManager::CurrentSectionIsVertical() const
305 ASSERT(!maSegments.empty(),
306 "should not be possible, must be at least one segment");
307 if (!maSegments.empty())
308 return maSegments.back().IsVertical();
309 return false;
312 bool wwSectionManager::CurrentSectionIsProtected() const
314 ASSERT(!maSegments.empty(),
315 "should not be possible, must be at least one segment");
316 if (!maSegments.empty())
317 return SectionIsProtected(maSegments.back());
318 return false;
321 sal_uInt32 wwSectionManager::GetPageLeft() const
323 return !maSegments.empty() ? maSegments.back().nPgLeft : 0;
326 sal_uInt32 wwSectionManager::GetPageRight() const
328 return !maSegments.empty() ? maSegments.back().nPgRight : 0;
331 sal_uInt32 wwSectionManager::GetPageWidth() const
333 return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
336 sal_uInt32 wwSectionManager::GetTextAreaWidth() const
338 return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
341 // --> OD 2007-07-03 #148498#
342 sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
344 return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
346 // <--
348 sal_uInt16 SwWW8ImplReader::End_Ftn()
351 #84095#
352 Ignoring Footnote outside of the normal Text. People will put footnotes
353 into field results and field commands.
355 if (bIgnoreText ||
356 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
358 return 0;
361 ASSERT(!maFtnStack.empty(), "footnote end without start");
362 if (maFtnStack.empty())
363 return 0;
365 bool bFtEdOk = false;
366 const FtnDescriptor &rDesc = maFtnStack.back();
368 //Get the footnote character and remove it from the txtnode. We'll
369 //replace it with the footnote
370 SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode();
371 xub_StrLen nPos = pPaM->GetPoint()->nContent.GetIndex();
373 String sChar;
374 SwTxtAttr* pFN = 0;
375 //There should have been a footnote char, we will replace this.
376 if (pTxt && nPos)
378 sChar.Append(pTxt->GetTxt().GetChar(--nPos));
379 pPaM->SetMark();
380 pPaM->GetMark()->nContent--;
381 rDoc.DeleteRange( *pPaM );
382 pPaM->DeleteMark();
383 SwFmtFtn aFtn(rDesc.meType == MAN_EDN);
384 pFN = pTxt->InsertItem(aFtn, nPos, nPos);
386 ASSERT(pFN, "Probleme beim Anlegen des Fussnoten-Textes");
387 if (pFN)
390 SwPosition aTmpPos( *pPaM->GetPoint() ); // merke alte Cursorposition
391 WW8PLCFxSaveAll aSave;
392 pPlcxMan->SaveAllPLCFx( aSave );
393 WW8PLCFMan* pOldPlcxMan = pPlcxMan;
395 const SwNodeIndex* pSttIdx = ((SwTxtFtn*)pFN)->GetStartNode();
396 ASSERT(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes");
398 ((SwTxtFtn*)pFN)->SetSeqNo( rDoc.GetFtnIdxs().Count() );
400 bool bOld = bFtnEdn;
401 bFtnEdn = true;
403 // read content of Ft-/End-Note
404 Read_HdFtFtnText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
405 bFtEdOk = true;
406 bFtnEdn = bOld;
408 ASSERT(sChar.Len()==1 && ((rDesc.mbAutoNum == (sChar.GetChar(0) == 2))),
409 "footnote autonumbering must be 0x02, and everthing else must not be");
411 // If no automatic numbering use the following char from the main text
412 // as the footnote number
413 if (!rDesc.mbAutoNum)
414 ((SwTxtFtn*)pFN)->SetNumber(0, &sChar);
417 Delete the footnote char from the footnote if its at the beginning
418 as usual. Might not be if the user has already deleted it, e.g.
419 #i14737#
421 SwNodeIndex& rNIdx = pPaM->GetPoint()->nNode;
422 rNIdx = pSttIdx->GetIndex() + 1;
423 SwTxtNode* pTNd = rNIdx.GetNode().GetTxtNode();
424 if (pTNd && pTNd->GetTxt().Len() && sChar.Len())
426 if (pTNd->GetTxt().GetChar(0) == sChar.GetChar(0))
428 pPaM->GetPoint()->nContent.Assign( pTNd, 0 );
429 pPaM->SetMark();
430 // Strip out tabs we may have inserted on export #i24762#
431 if (pTNd->GetTxt().GetChar(1) == 0x09)
432 pPaM->GetMark()->nContent++;
433 pPaM->GetMark()->nContent++;
434 pReffingStck->Delete(*pPaM);
435 rDoc.DeleteRange( *pPaM );
436 pPaM->DeleteMark();
440 *pPaM->GetPoint() = aTmpPos; // restore Cursor
442 pPlcxMan = pOldPlcxMan; // Restore attributes
443 pPlcxMan->RestoreAllPLCFx( aSave );
446 if (bFtEdOk)
447 maSectionManager.SetCurrentSectionHasFootnote();
449 maFtnStack.pop_back();
450 return 0;
453 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult* pRes)
456 #84095#
457 Ignoring Footnote outside of the normal Text. People will put footnotes
458 into field results and field commands.
460 if (bIgnoreText ||
461 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
463 return 0;
466 FtnDescriptor aDesc;
467 aDesc.mbAutoNum = true;
468 if (eEDN == pRes->nSprmId)
470 aDesc.meType = MAN_EDN;
471 if (pPlcxMan->GetEdn())
472 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetEdn()->GetData();
474 else
476 aDesc.meType = MAN_FTN;
477 if (pPlcxMan->GetFtn())
478 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetFtn()->GetData();
481 aDesc.mnStartCp = pRes->nCp2OrIdx;
482 aDesc.mnLen = pRes->nMemLen;
484 maFtnStack.push_back(aDesc);
486 return 0;
489 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp,
490 int nLevel) const
492 WW8PLCFxDesc aRes;
493 aRes.pMemPos = 0;
494 aRes.nEndPos = rStartCp;
496 while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
498 if (pPap->Where() != WW8_CP_MAX)
500 const BYTE* pB = pPap->HasSprm(TabRowSprm(nLevel));
501 if (pB && *pB == 1)
503 const BYTE *pLevel = 0;
504 if (0 != (pLevel = pPap->HasSprm(0x6649)))
506 if (nLevel + 1 == *pLevel)
507 return true;
509 else
511 ASSERT(!nLevel || pLevel, "sublevel without level sprm");
512 return true; // RowEnd found
517 aRes.nStartPos = aRes.nEndPos;
518 aRes.pMemPos = 0;
519 //Seek to our next block of properties
520 if (!(pPap->SeekPos(aRes.nStartPos)))
522 aRes.nEndPos = WW8_CP_MAX;
523 pPap->SetDirty(true);
525 pPap->GetSprms(&aRes);
526 pPap->SetDirty(false);
527 //Update our aRes to get the new starting point of the next properties
528 rStartCp = aRes.nEndPos;
531 return false;
534 ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
535 const WW8_TablePos *pTabPos)
537 const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0;
538 ApoTestResults aRet;
539 // Frame in Style Definition (word appears to ignore them if inside an
540 // text autoshape, e.g. #94418#)
541 if (!bTxbxFlySection)
542 aRet.mpStyleApo = StyleExists(nAktColl) ? pCollA[nAktColl].pWWFly : 0;
545 #i1140#
546 If I have a table and apply a style to one of its frames that should cause
547 a paragraph that its applied to it to only exist as a seperate floating
548 frame, then the behavour depends on which cell that it has been applied
549 to. If its the first cell of a row then the whole table row jumps into the
550 new frame, if its not then then the paragraph attributes are applied
551 "except" for the floating frame stuff. i.e. its ignored. So if theres a
552 table, and we're not in the first cell then we ignore the fact that the
553 paragraph style wants to be in a different frame.
555 This sort of mindbending inconsistency is surely why frames are deprecated
556 in word 97 onwards and hidden away from the user
559 #i1532# & #i5379#
560 If we are already a table in a frame then we must grab the para properties
561 to see if we are still in that frame.
564 aRet.mpSprm37 = pPlcxMan->HasParaSprm( bVer67 ? 37 : 0x2423 );
565 aRet.mpSprm29 = pPlcxMan->HasParaSprm( bVer67 ? 29 : 0x261B );
567 // Is there some frame data here
568 bool bNowApo = aRet.HasFrame() || pTopLevelTable;
569 if (bNowApo)
571 if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos))
572 delete pTest;
573 else
574 bNowApo = false;
577 bool bTestAllowed = !bTxbxFlySection && !bTableRowEnd;
578 if (bTestAllowed)
580 //Test is allowed if there is no table.
581 //Otherwise only allowed if we are in the
582 //first paragraph of the first cell of a row.
583 //(And only if the row we are inside is at the
584 //same level as the previous row, think tables
585 //in tables)
586 if (nCellLevel == nInTable)
589 if (!nInTable)
590 bTestAllowed = true;
591 else
593 if (!pTableDesc)
595 ASSERT(pTableDesc, "What!");
596 bTestAllowed = false;
598 else
600 // --> OD 2005-02-01 #i39468#
601 // If current cell isn't valid, the test is allowed.
602 // The cell isn't valid, if e.g. there is a new row
603 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
604 bTestAllowed =
605 pTableDesc->GetAktCol() == 0 &&
606 ( !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) ||
607 pTableDesc->InFirstParaInCell() );
608 // <--
614 if (!bTestAllowed)
615 return aRet;
617 aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start
618 aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end
620 //If it happens that we are in a table, then if its not the first cell
621 //then any attributes that might otherwise cause the contents to jump
622 //into another frame don't matter, a table row sticks together as one
623 //unit no matter what else happens. So if we are not in a table at
624 //all, or if we are in the first cell then test that the last frame
625 //data is the same as the current one
626 if (bNowApo && InEqualApo(nCellLevel))
628 // two bordering eachother
629 if (!TestSameApo(aRet, pTabPos))
630 aRet.mbStopApo = aRet.mbStartApo = true;
633 return aRet;
635 //---------------------------------------------------------------------
636 // Hilfroutinen fuer Kapitelnummerierung und Aufzaehlung / Gliederung
637 //---------------------------------------------------------------------
639 static void SetBaseAnlv(SwNumFmt &rNum, WW8_ANLV &rAV, BYTE nSwLevel )
641 static SvxExtNumType eNumA[8] = { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
642 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N, SVX_NUM_ARABIC,
643 SVX_NUM_ARABIC, SVX_NUM_ARABIC };
645 static SvxAdjust eAdjA[4] = { SVX_ADJUST_LEFT,
646 SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT };
647 // eigentlich folgende 2, aber Writer-UI bietet es nicht an
648 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE };
650 rNum.SetNumberingType( static_cast< sal_Int16 >(( SVBT8ToByte( rAV.nfc ) < 8 ) ?
651 eNumA[SVBT8ToByte( rAV.nfc ) ] : SVX_NUM_NUMBER_NONE) );
652 if ((SVBT8ToByte(rAV.aBits1 ) & 0x4) >> 2)
653 rNum.SetIncludeUpperLevels(nSwLevel + 1);
654 rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) );
655 // rNum.eNumAdjust = eAdjA[rAV.jc];
656 rNum.SetNumAdjust( eAdjA[SVBT8ToByte( rAV.aBits1 ) & 0x3] );
658 rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) );
659 INT16 nIndent = Abs((INT16)SVBT16ToShort( rAV.dxaIndent ));
660 if( SVBT8ToByte( rAV.aBits1 ) & 0x08 ) //fHang
662 rNum.SetFirstLineOffset( -nIndent );
663 rNum.SetLSpace( nIndent );
664 rNum.SetAbsLSpace( nIndent );
666 else
667 rNum.SetCharTextDistance( nIndent ); // Breite der Nummer fehlt
669 if( SVBT8ToByte( rAV.nfc ) == 5 || SVBT8ToByte( rAV.nfc ) == 7 )
671 String sP( rNum.GetSuffix() );
672 sP.Insert( '.', 0 );
673 rNum.SetSuffix( sP ); // Ordinalzahlen
677 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt &rNum, WW8_ANLV &rAV,
678 const BYTE* pTxt, bool bOutline)
680 bool bInsert = false; // Default
681 CharSet eCharSet = eStructCharSet;
683 const WW8_FFN* pF = pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo
684 bool bListSymbol = pF && ( pF->chs == 2 ); // Symbol/WingDings/...
686 String sTxt;
687 if (bVer67)
689 sTxt = String( (sal_Char*)pTxt, SVBT8ToByte( rAV.cbTextBefore )
690 + SVBT8ToByte( rAV.cbTextAfter ), eCharSet );
692 else
694 for(xub_StrLen i = SVBT8ToByte(rAV.cbTextBefore);
695 i < SVBT8ToByte(rAV.cbTextAfter); ++i, pTxt += 2)
697 sTxt.Append(SVBT16ToShort(*(SVBT16*)pTxt));
701 if( bOutline )
702 { // Gliederung
703 if( !rNum.GetIncludeUpperLevels() // es sind <= 1 Nummern anzuzeigen
704 || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ){ // oder dieser Level hat keine
705 // eigenen Ziffern
706 bInsert = true; // -> dann uebernehme Zeichen
708 // replace by simple Bullet ?
709 if( bListSymbol )
710 //JP 14.08.96: cBulletChar benutzen, damit auf dem MAC
711 // richtig gemappt wird
712 sTxt.Fill( SVBT8ToByte( rAV.cbTextBefore )
713 + SVBT8ToByte( rAV.cbTextAfter ), cBulletChar );
716 else
717 { // Nummerierung / Aufzaehlung
718 bInsert = true;
719 // if( SVBT16ToShort( rAV.ftc ) == 1
720 // || SVBT16ToShort( rAV.ftc ) == 3 ){ // Symbol / WingDings
721 if( bListSymbol )
723 FontFamily eFamily;
724 String aName;
725 FontPitch ePitch;
727 if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName,
728 ePitch, eCharSet ) ){
729 // USHORT nSiz = ( SVBT16ToShort( rAV.hps ) ) ?
730 // SVBT16ToShort( rAV.hps ) : 24; // Groesse in 1/2 Pt
731 // darf nach JP nicht gesetzt werden, da immer die Size
732 // genommen wird, die am ZeilenAnfang benutzt wird
733 Font aFont;
734 aFont.SetName( aName );
735 aFont.SetFamily( eFamily );
736 // aFont.SetPitch( ePitch ); // darf nach JP nicht
737 aFont.SetCharSet( eCharSet );
738 rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
739 // if( rAV.ico ) // geht in UI und SWG-Writer/Reader nicht
740 // aFont.SetColor( Color( GetCol( rAV.ico ) ) );
741 rNum.SetBulletFont( &aFont );
743 // take only the very first character
744 if( rAV.cbTextBefore || rAV.cbTextAfter)
745 rNum.SetBulletChar( sTxt.GetChar( 0 ) );
746 else
747 rNum.SetBulletChar( 0x2190 );
751 if( bInsert )
753 if( rAV.cbTextBefore )
755 String sP( sTxt.Copy( 0, SVBT8ToByte( rAV.cbTextBefore ) ) );
756 rNum.SetPrefix( sP );
758 if( SVBT8ToByte( rAV.cbTextAfter ) )
760 String sP( rNum.GetSuffix() );
761 sP.Insert( sTxt.Copy( SVBT8ToByte( rAV.cbTextBefore ),
762 SVBT8ToByte( rAV.cbTextAfter ) ) );
763 rNum.SetSuffix( sP );
765 // Die Zeichen vor und hinter mehreren Ziffern koennen leider nicht uebernommen
766 // werden, da sie der Writer ganz anders behandelt und das Ergebnis i.A.
767 // schlechter als ohne waere.
771 // SetAnld bekommt einen WW-ANLD-Descriptor und einen Level und modifiziert
772 // die durch pNumR anggebeben NumRules. Wird benutzt fuer alles ausser
773 // Gliederung im Text
774 void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD* pAD, BYTE nSwLevel,
775 bool bOutLine)
777 SwNumFmt aNF;
778 if (pAD)
779 { // Es gibt einen Anld-Sprm
780 bAktAND_fNumberAcross = 0 != SVBT8ToByte( pAD->fNumberAcross );
781 WW8_ANLV &rAV = pAD->eAnlv;
782 SetBaseAnlv(aNF, rAV, nSwLevel); // Setze Basis-Format
783 SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine );// und Rest
785 pNumR->Set(nSwLevel, aNF);
788 //-------------------------------------------------------
789 // Kapitelnummerierung und Kapitelbullets
790 //-------------------------------------------------------
791 // Kapitelnummerierung findet in Styledefinionen statt. Sprm 13 gibt den Level
792 // an, Sprm 12 den Inhalt
794 SwNumRule* SwWW8ImplReader::GetStyRule()
796 if( pStyles->pStyRule ) // Bullet-Style bereits vorhanden
797 return pStyles->pStyRule;
799 const String aBaseName(CREATE_CONST_ASC( "WW8StyleNum" ));
800 const String aName( rDoc.GetUniqueNumRuleName( &aBaseName, false) );
802 // --> OD 2008-06-04 #i86652#
803 // USHORT nRul = rDoc.MakeNumRule( aName );
804 USHORT nRul = rDoc.MakeNumRule( aName, 0, FALSE,
805 SvxNumberFormat::LABEL_ALIGNMENT );
806 // <--
807 pStyles->pStyRule = rDoc.GetNumRuleTbl()[nRul];
808 // Auto == false-> Nummerierungsvorlage
809 pStyles->pStyRule->SetAutoRule(false);
811 return pStyles->pStyRule;
814 // Sprm 13
815 void SwWW8ImplReader::Read_ANLevelNo( USHORT, const BYTE* pData, short nLen )
817 nSwNumLevel = 0xff; // Default: ungueltig
819 if( nLen <= 0 )
820 return;
822 // StyleDef ?
823 if( pAktColl )
825 // nur fuer SwTxtFmtColl, nicht CharFmt
826 // WW: 0 = no Numbering
827 SwWW8StyInf * pColl = GetStyle(nAktColl);
828 if (pColl != NULL && pColl->bColl && *pData)
830 // Bereich WW:1..9 -> SW:0..8 keine Aufzaehlung / Nummerierung
832 if (*pData <= MAXLEVEL && *pData <= 9)
834 nSwNumLevel = *pData - 1;
835 if (!bNoAttrImport)
836 //((SwTxtFmtColl*)pAktColl)->SetOutlineLevel( nSwNumLevel ); //#outline level,zhaojianwei
837 ((SwTxtFmtColl*)pAktColl)->AssignToListLevelOfOutlineStyle( nSwNumLevel ); //<-end,zhaojianwei
838 // Bei WW-NoNumbering koennte auch NO_NUMBERING gesetzt
839 // werden. ( Bei normaler Nummerierung muss NO_NUM gesetzt
840 // werden: NO_NUM : Nummerierungs-Pause,
841 // NO_NUMBERING : ueberhaupt keine Nummerierung )
844 else if( *pData == 10 || *pData == 11 )
846 // Typ merken, der Rest geschieht bei Sprm 12
847 pStyles->nWwNumLevel = *pData;
851 else
853 //Not StyleDef
854 if (!bAnl)
855 StartAnl(pData); // Anfang der Gliederung / Aufzaehlung
856 NextAnlLine(pData);
860 void SwWW8ImplReader::Read_ANLevelDesc( USHORT, const BYTE* pData, short nLen ) // Sprm 12
863 SwWW8StyInf * pStyInf = GetStyle(nAktColl);
864 if( !pAktColl || nLen <= 0 // nur bei Styledef
865 || (pStyInf && !pStyInf->bColl) // CharFmt -> ignorieren
866 || ( nIniFlags & WW8FL_NO_OUTLINE ) ){
867 nSwNumLevel = 0xff;
868 return;
872 if( nSwNumLevel <= MAXLEVEL // Bereich WW:1..9 -> SW:0..8
873 && nSwNumLevel <= 9 ){ // keine Aufzaehlung / Nummerierung
875 // Falls bereits direkt oder durch
876 // Vererbung NumruleItems gesetzt sind,
877 // dann jetzt ausschalten #56163
878 pAktColl->SetFmtAttr( SwNumRuleItem() );
880 String aName(CREATE_CONST_ASC( "Outline" ));
881 // --> OD 2008-02-11 #newlistlevelattrs#
882 SwNumRule aNR( rDoc.GetUniqueNumRuleName( &aName ),
883 SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
884 OUTLINE_RULE );
885 // <--
886 aNR = *rDoc.GetOutlineNumRule();
888 SetAnld(&aNR, (WW8_ANLD*)pData, nSwNumLevel, true);
890 // fehlende Level muessen nicht aufgefuellt werden
892 rDoc.SetOutlineNumRule( aNR );
893 }else if( pStyles->nWwNumLevel == 10 || pStyles->nWwNumLevel == 11 ){
894 SwNumRule* pNR = GetStyRule();
895 SetAnld(pNR, (WW8_ANLD*)pData, 0, false);
896 pAktColl->SetFmtAttr( SwNumRuleItem( pNR->GetName() ) );
898 SwWW8StyInf * pStyInf = GetStyle(nAktColl);
899 if (pStyInf != NULL)
900 pStyInf->bHasStyNumRule = true;
904 //-----------------------------------------
905 // Nummerierung / Aufzaehlung
906 //-----------------------------------------
908 // SetNumOlst() traegt die Numrules fuer diese Zeile ins SwNumFmt ein
909 // ( nur fuer Gliederungen im Text; Aufzaehlungen / Nummerierungen laufen
910 // ueber ANLDs )
911 // dabei wird die Info aus dem OLST geholt und nicht aus dem ANLD ( s.u. )
912 void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, BYTE nSwLevel)
914 SwNumFmt aNF;
915 WW8_ANLV &rAV = pO->rganlv[nSwLevel];
916 SetBaseAnlv(aNF, rAV, nSwLevel);
917 // ... und then the Strings
918 int nTxtOfs = 0;
919 BYTE i;
920 WW8_ANLV* pAV1; // search String-Positions
921 for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
923 nTxtOfs += SVBT8ToByte(pAV1->cbTextBefore)
924 + SVBT8ToByte(pAV1->cbTextAfter);
927 if (!bVer67)
928 nTxtOfs *= 2;
929 SetAnlvStrings(aNF, rAV, pO->rgch + nTxtOfs, true); // und rein
930 pNumR->Set(nSwLevel, aNF);
933 // der OLST kommt am Anfang jeder Section, die Gliederungen enthaelt. Die ANLDs,
934 // die an jeder Gliederungszeile haengen, enthalten nur Stuss, also werden die
935 // OLSTs waehrend der Section gemerkt, damit die Informationen beim Auftreten
936 // von Gliederungsabsaetzen zugreifbar ist.
937 void SwWW8ImplReader::Read_OLST( USHORT, const BYTE* pData, short nLen )
939 if (nLen <= 0)
941 delete pNumOlst, pNumOlst = 0;
942 return;
944 if (pNumOlst)
945 delete pNumOlst; // nur sicherheitshalber
946 pNumOlst = new WW8_OLST;
947 if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) ) // auffuellen, falls zu kurz
948 memset( pNumOlst, 0, sizeof( *pNumOlst ) );
949 *pNumOlst = *(WW8_OLST*)pData;
952 WW8LvlType GetNumType(BYTE nWwLevelNo)
954 WW8LvlType nRet = WW8_None;
955 if( nWwLevelNo == 12 )
956 nRet = WW8_Pause;
957 else if( nWwLevelNo == 10 )
958 nRet = WW8_Numbering;
959 else if( nWwLevelNo == 11 )
960 nRet = WW8_Sequence;
961 else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
962 nRet = WW8_Outline;
963 return nRet;
966 SwNumRule *ANLDRuleMap::GetNumRule(BYTE nNumType)
968 return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule);
971 void ANLDRuleMap::SetNumRule(SwNumRule *pRule, BYTE nNumType)
973 if (WW8_Numbering == nNumType)
974 mpNumberingNumRule = pRule;
975 else
976 mpOutlineNumRule = pRule;
980 // StartAnl wird am Anfang eines Zeilenbereichs gerufen,
981 // der Gliederung / Nummerierung / Aufzaehlung enthaelt
982 void SwWW8ImplReader::StartAnl(const BYTE* pSprm13)
984 bAktAND_fNumberAcross = false;
986 BYTE nT = static_cast< BYTE >(GetNumType(*pSprm13));
987 if (nT == WW8_Pause || nT == WW8_None)
988 return;
990 nWwNumType = nT;
991 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
993 // check for COL numbering:
994 const BYTE* pS12 = 0;// sprmAnld
995 String sNumRule;
997 if (pTableDesc)
999 sNumRule = pTableDesc->GetNumRuleName();
1000 if (sNumRule.Len())
1002 pNumRule = rDoc.FindNumRulePtr(sNumRule);
1003 if (!pNumRule)
1004 sNumRule.Erase();
1005 else
1007 // this is ROW numbering ?
1008 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1009 if (pS12 && 0 != SVBT8ToByte(((WW8_ANLD*)pS12)->fNumberAcross))
1010 sNumRule.Erase();
1015 SwWW8StyInf * pStyInf = GetStyle(nAktColl);
1016 if (!sNumRule.Len() && pStyInf->bHasStyNumRule)
1018 sNumRule = pStyInf->pFmt->GetNumRule().GetValue();
1019 pNumRule = rDoc.FindNumRulePtr(sNumRule);
1020 if (!pNumRule)
1021 sNumRule.Erase();
1024 if (!sNumRule.Len())
1026 if (!pNumRule)
1028 // --> OD 2008-06-04 #i86652#
1029 // pNumRule = rDoc.GetNumRuleTbl()[rDoc.MakeNumRule(sNumRule)];
1030 pNumRule = rDoc.GetNumRuleTbl()[
1031 rDoc.MakeNumRule( sNumRule, 0, FALSE,
1032 SvxNumberFormat::LABEL_ALIGNMENT ) ];
1033 // <--
1035 if (pTableDesc)
1037 if (!pS12)
1038 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
1039 if (!pS12 || !SVBT8ToByte( ((WW8_ANLD*)pS12)->fNumberAcross))
1040 pTableDesc->SetNumRuleName(pNumRule->GetName());
1044 bAnl = true;
1046 // NumRules ueber Stack setzen
1047 pCtrlStck->NewAttr(*pPaM->GetPoint(),
1048 SfxStringItem(RES_FLTR_NUMRULE, pNumRule->GetName()));
1050 maANLDRules.SetNumRule(pNumRule, nWwNumType);
1053 // NextAnlLine() wird fuer jede Zeile einer
1054 // Gliederung / Nummerierung / Aufzaehlung einmal gerufen
1055 void SwWW8ImplReader::NextAnlLine(const BYTE* pSprm13)
1057 if (!bAnl)
1058 return;
1060 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
1062 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
1063 // sdw3
1065 // WW:10 = Nummerierung -> SW:0 & WW:11 = Auffzaehlung -> SW:0
1066 if (*pSprm13 == 10 || *pSprm13 == 11)
1068 nSwNumLevel = 0;
1069 if (!pNumRule->GetNumFmt(nSwNumLevel))
1071 // noch nicht definiert
1072 // sprmAnld o. 0
1073 const BYTE* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1074 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1077 else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // Bereich WW:1..9 -> SW:0..8
1079 nSwNumLevel = *pSprm13 - 1; // Gliederung
1080 // noch nicht definiert
1081 if (!pNumRule->GetNumFmt(nSwNumLevel))
1083 if (pNumOlst) // es gab ein OLST
1085 //Assure upper levels are set, #i9556#
1086 for (BYTE nI = 0; nI < nSwNumLevel; ++nI)
1088 if (!pNumRule->GetNumFmt(nI))
1089 SetNumOlst(pNumRule, pNumOlst, nI);
1092 SetNumOlst(pNumRule, pNumOlst , nSwNumLevel);
1094 else // kein Olst, nimm Anld
1096 // sprmAnld
1097 const BYTE* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1098 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1102 else
1103 nSwNumLevel = 0xff; // keine Nummer
1105 SwTxtNode* pNd = pPaM->GetNode()->GetTxtNode();
1106 if (nSwNumLevel < MAXLEVEL)
1107 pNd->SetAttrListLevel( nSwNumLevel );
1108 else
1110 pNd->SetAttrListLevel(0);
1111 pNd->SetCountedInList( false );
1115 void SwWW8ImplReader::StopAllAnl(bool bGoBack)
1117 //Of course we're not restarting, but we'll make use of our knowledge
1118 //of the implementation to do it.
1119 StopAnlToRestart(WW8_None, bGoBack);
1122 void SwWW8ImplReader::StopAnlToRestart(BYTE nNewType, bool bGoBack)
1124 if (bGoBack)
1126 SwPosition aTmpPos(*pPaM->GetPoint());
1127 pPaM->Move(fnMoveBackward, fnGoCntnt);
1128 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1129 *pPaM->GetPoint() = aTmpPos;
1131 else
1132 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1134 maANLDRules.mpNumberingNumRule = 0;
1136 #i18816#
1137 my take on this problem is that moving either way from an outline to a
1138 numbering doesn't halt the outline, while the numbering is always halted
1140 bool bNumberingNotStopOutline =
1141 (((nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1142 ((nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1143 if (!bNumberingNotStopOutline)
1144 maANLDRules.mpOutlineNumRule = 0;
1146 nSwNumLevel = 0xff;
1147 nWwNumType = WW8_None;
1148 bAnl = false;
1151 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand )
1153 *this = rBand;
1154 if( rBand.pTCs )
1156 pTCs = new WW8_TCell[nWwCols];
1157 memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1159 if( rBand.pSHDs )
1161 pSHDs = new WW8_SHD[nWwCols];
1162 memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1164 if( rBand.pNewSHDs )
1166 pNewSHDs = new sal_uInt32[nWwCols];
1167 memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32));
1169 memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1172 // ReadDef liest die Zellenpositionen und ggfs die Umrandungen eines Bandes ein
1173 void WW8TabBandDesc::ReadDef(bool bVer67, const BYTE* pS)
1175 if (!bVer67)
1176 pS++;
1178 short nLen = (INT16)SVBT16ToShort( pS - 2 ); // nicht schoen
1180 BYTE nCols = *pS; // Anzahl der Zellen
1181 short nOldCols = nWwCols;
1183 if( nCols > MAX_COL )
1184 return;
1186 nWwCols = nCols;
1188 const BYTE* pT = &pS[1];
1189 nLen --;
1190 int i;
1191 for(i=0; i<=nCols; i++, pT+=2 )
1192 nCenter[i] = (INT16)SVBT16ToShort( pT ); // X-Raender
1193 nLen -= 2 * ( nCols + 1 );
1194 if( nCols != nOldCols ) // andere Spaltenzahl
1196 delete[] pTCs, pTCs = 0;
1197 delete[] pSHDs, pSHDs = 0;
1198 delete[] pNewSHDs, pNewSHDs = 0;
1201 short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // wirklich abgespeichert
1203 if (!pTCs && nCols)
1205 // lege leere TCs an
1206 pTCs = new WW8_TCell[nCols];
1207 setcelldefaults(pTCs,nCols);
1210 short nColsToRead = nFileCols;
1211 if (nColsToRead > nCols)
1212 nColsToRead = nCols;
1214 if( nColsToRead )
1216 // lies TCs ein
1219 Achtung: ab Ver8 ist ein reserve-ushort je TC eingefuegt und auch
1220 der Border-Code ist doppelt so gross, daher ist hier
1221 kein simples kopieren moeglich,
1222 d.h.: pTCs[i] = *pTc; geht leider nicht.
1224 Vorteil: Arbeitstruktur ist jetzt viel bequemer zu handhaben!
1226 WW8_TCell* pAktTC = pTCs;
1227 if( bVer67 )
1229 WW8_TCellVer6* pTc = (WW8_TCellVer6*)pT;
1230 for(i=0; i<nColsToRead; i++, ++pAktTC,++pTc)
1232 if( i < nColsToRead )
1233 { // TC aus File ?
1234 BYTE aBits1 = SVBT8ToByte( pTc->aBits1Ver6 );
1235 pAktTC->bFirstMerged = ( ( aBits1 & 0x01 ) != 0 );
1236 pAktTC->bMerged = ( ( aBits1 & 0x02 ) != 0 );
1237 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1238 pTc->rgbrcVer6[ WW8_TOP ].aBits1, sizeof( SVBT16 ) );
1239 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1240 pTc->rgbrcVer6[ WW8_LEFT ].aBits1, sizeof( SVBT16 ) );
1241 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1242 pTc->rgbrcVer6[ WW8_BOT ].aBits1, sizeof( SVBT16 ) );
1243 memcpy( pAktTC->rgbrc[ WW8_RIGHT ].aBits1,
1244 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1245 if( ( pAktTC->bMerged )
1246 && ( i > 0 ) )
1248 // Cell gemerged -> merken
1249 //bWWMergedVer6[i] = true;
1250 memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1,
1251 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1252 // right Border in vorige Zelle uebernehmen
1253 // Hier darf bExist nicht auf false gesetzt werden, da WW
1254 // in den Textboxen diese Zellen nicht mitzaehlt....
1259 else
1261 WW8_TCellVer8* pTc = (WW8_TCellVer8*)pT;
1262 for (int k = 0; k < nColsToRead; ++k, ++pAktTC, ++pTc )
1264 UINT16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 );
1265 pAktTC->bFirstMerged = ( ( aBits1 & 0x0001 ) != 0 );
1266 pAktTC->bMerged = ( ( aBits1 & 0x0002 ) != 0 );
1267 pAktTC->bVertical = ( ( aBits1 & 0x0004 ) != 0 );
1268 pAktTC->bBackward = ( ( aBits1 & 0x0008 ) != 0 );
1269 pAktTC->bRotateFont = ( ( aBits1 & 0x0010 ) != 0 );
1270 pAktTC->bVertMerge = ( ( aBits1 & 0x0020 ) != 0 );
1271 pAktTC->bVertRestart = ( ( aBits1 & 0x0040 ) != 0 );
1272 pAktTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 );
1273 // am Rande: im aBits1 verstecken sich noch 7 Reserve-Bits,
1274 // anschliessend folgen noch 16 weitere Reserve-Bits
1276 // In Version 8 koennen wir alle Bordercodes auf einmal kopieren!
1277 memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) );
1281 // #i25071 In '97 text direction appears to be only set using TC properties
1282 // not with sprmTTextFlow so we need to cycle through the maDirections and
1283 // double check any non-default directions
1284 for (int k = 0; k < nCols; ++k)
1286 if(maDirections[k] == 4)
1288 if(pTCs[k].bVertical)
1290 if(pTCs[k].bBackward)
1291 maDirections[k] = 3;
1292 else
1293 maDirections[k] = 1;
1302 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const BYTE* pParamsTSetBRC)
1304 if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
1306 BYTE nitcFirst= pParamsTSetBRC[0];// first col to be changed
1307 BYTE nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1
1308 BYTE nFlag = *(pParamsTSetBRC+2);
1310 if (nitcFirst >= nWwCols)
1311 return;
1313 if (nitcLim > nWwCols)
1314 nitcLim = nWwCols;
1316 bool bChangeRight = (nFlag & 0x08) ? true : false;
1317 bool bChangeBottom = (nFlag & 0x04) ? true : false;
1318 bool bChangeLeft = (nFlag & 0x02) ? true : false;
1319 bool bChangeTop = (nFlag & 0x01) ? true : false;
1321 WW8_TCell* pAktTC = pTCs + nitcFirst;
1322 if( bVer67 )
1324 WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3);
1326 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1328 if( bChangeTop )
1329 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1330 pBRC->aBits1,
1331 sizeof( SVBT16 ) );
1332 if( bChangeLeft )
1333 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1334 pBRC->aBits1,
1335 sizeof( SVBT16 ) );
1336 if( bChangeBottom )
1337 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1338 pBRC->aBits1,
1339 sizeof( SVBT16 ) );
1340 if( bChangeRight )
1341 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1342 pBRC->aBits1,
1343 sizeof( SVBT16 ) );
1346 else
1348 WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3);
1350 for( int i = nitcFirst; i < nitcLim; i++, ++pAktTC )
1352 if( bChangeTop )
1353 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1354 pBRC->aBits1,
1355 sizeof( WW8_BRC ) );
1356 if( bChangeLeft )
1357 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1358 pBRC->aBits1,
1359 sizeof( WW8_BRC ) );
1360 if( bChangeBottom )
1361 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1362 pBRC->aBits1,
1363 sizeof( WW8_BRC ) );
1364 if( bChangeRight )
1365 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1366 pBRC->aBits1,
1367 sizeof( WW8_BRC ) );
1376 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const BYTE* pParams)
1378 // sprmTTableBorders
1379 if( bVer67 )
1381 for( int i = 0; i < 6; ++i )
1383 aDefBrcs[i].aBits1[0] = pParams[ 2*i ];
1384 aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ];
1387 else // aDefBrcs = *(BRC(*)[6])pS;
1388 memcpy( aDefBrcs, pParams, 24 );
1391 void WW8TabBandDesc::ProcessSprmTDxaCol(const BYTE* pParamsTDxaCol)
1393 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1394 // whose index is within a certain range to be a certain value.
1396 if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s)
1398 BYTE nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1399 BYTE nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1
1400 short nDxaCol = (INT16)SVBT16ToShort( pParamsTDxaCol + 2 );
1401 short nOrgWidth;
1402 short nDelta;
1404 for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1406 nOrgWidth = nCenter[i+1] - nCenter[i];
1407 nDelta = nDxaCol - nOrgWidth;
1408 for( int j = i+1; j <= nWwCols; j++ )
1410 nCenter[j] = nCenter[j] + nDelta;
1416 void WW8TabBandDesc::ProcessSprmTInsert(const BYTE* pParamsTInsert)
1418 if( nWwCols && pParamsTInsert ) // set one or more cell length(s)
1420 BYTE nitcInsert = pParamsTInsert[0]; // position at which to insert
1421 if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index
1422 return;
1423 BYTE nctc = pParamsTInsert[1]; // number of cells
1424 USHORT ndxaCol = SVBT16ToShort( pParamsTInsert+2 );
1426 short nNewWwCols;
1427 if (nitcInsert > nWwCols)
1429 nNewWwCols = nitcInsert+nctc;
1430 //if new count would be outside max possible count, clip it, and calc a new replacement
1431 //legal nctc
1432 if (nNewWwCols > MAX_COL)
1434 nNewWwCols = MAX_COL;
1435 nctc = ::sal::static_int_cast<BYTE>(nNewWwCols-nitcInsert);
1438 else
1440 nNewWwCols = nWwCols+nctc;
1441 //if new count would be outside max possible count, clip it, and calc a new replacement
1442 //legal nctc
1443 if (nNewWwCols > MAX_COL)
1445 nNewWwCols = MAX_COL;
1446 nctc = ::sal::static_int_cast<BYTE>(nNewWwCols-nWwCols);
1450 WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1451 setcelldefaults(pTC2s, nNewWwCols);
1453 if (pTCs)
1455 memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1456 delete[] pTCs;
1458 pTCs = pTC2s;
1460 //If we have to move some cells
1461 if (nitcInsert <= nWwCols)
1463 // adjust the left x-position of the dummy at the very end
1464 nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1465 for( int i = nWwCols-1; i >= nitcInsert; i--)
1467 // adjust the left x-position
1468 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1470 // adjust the cell's borders
1471 pTCs[i + nctc] = pTCs[i];
1475 //if itcMac is larger than full size, fill in missing ones first
1476 for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1477 nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1479 //now add in our new cells
1480 for( int j = 0;j < nctc; j++)
1481 nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1483 nWwCols = nNewWwCols;
1487 void WW8TabBandDesc::ProcessDirection(const BYTE* pParams)
1489 sal_uInt8 nStartCell = *pParams++;
1490 sal_uInt8 nEndCell = *pParams++;
1491 sal_uInt16 nCode = SVBT16ToShort(pParams);
1493 ASSERT(nStartCell < nEndCell, "not as I thought");
1494 ASSERT(nEndCell < MAX_COL + 1, "not as I thought");
1495 if (nStartCell > MAX_COL)
1496 return;
1497 if (nEndCell > MAX_COL + 1)
1498 nEndCell = MAX_COL + 1;
1500 for (;nStartCell < nEndCell; ++nStartCell)
1501 maDirections[nStartCell] = nCode;
1504 void WW8TabBandDesc::ProcessSpacing(const BYTE* pParams)
1506 BYTE nLen = pParams ? *(pParams - 1) : 0;
1507 ASSERT(nLen == 6, "Unexpected spacing len");
1508 if (nLen != 6)
1509 return;
1510 mbHasSpacing=true;
1511 #ifdef DBG_UTIL
1512 BYTE nWhichCell = *pParams;
1513 ASSERT(nWhichCell == 0, "Expected cell to be 0!");
1514 #endif
1515 ++pParams; //Skip which cell
1516 ++pParams; //unknown byte
1518 BYTE nSideBits = *pParams++;
1519 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1520 ++pParams; //unknown byte
1521 USHORT nValue = SVBT16ToShort( pParams );
1522 for (int i = wwTOP; i <= wwRIGHT; i++)
1524 switch (nSideBits & (1 << i))
1526 case 1 << wwTOP:
1527 mnDefaultTop = nValue;
1528 break;
1529 case 1 << wwLEFT:
1530 mnDefaultLeft = nValue;
1531 break;
1532 case 1 << wwBOTTOM:
1533 mnDefaultBottom = nValue;
1534 break;
1535 case 1 << wwRIGHT:
1536 mnDefaultRight = nValue;
1537 break;
1538 case 0:
1539 break;
1540 default:
1541 ASSERT(!this, "Impossible");
1542 break;
1547 void WW8TabBandDesc::ProcessSpecificSpacing(const BYTE* pParams)
1549 BYTE nLen = pParams ? *(pParams - 1) : 0;
1550 ASSERT(nLen == 6, "Unexpected spacing len");
1551 if (nLen != 6)
1552 return;
1553 BYTE nWhichCell = *pParams++;
1554 ASSERT(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1555 if (nWhichCell >= MAX_COL + 1)
1556 return;
1558 ++pParams; //unknown byte
1559 BYTE nSideBits = *pParams++;
1560 ASSERT(nSideBits < 0x10, "Unexpected value for nSideBits");
1561 nOverrideSpacing[nWhichCell] |= nSideBits;
1563 ASSERT(nOverrideSpacing[nWhichCell] < 0x10,
1564 "Unexpected value for nSideBits");
1565 #ifdef DBG_UTIL
1566 BYTE nUnknown2 = *pParams;
1567 ASSERT(nUnknown2 == 0x3, "Unexpected value for spacing2");
1568 #endif
1569 ++pParams;
1570 USHORT nValue = SVBT16ToShort( pParams );
1572 for (int i=0; i < 4; i++)
1574 if (nSideBits & (1 << i))
1575 nOverrideValues[nWhichCell][i] = nValue;
1579 void WW8TabBandDesc::ProcessSprmTDelete(const BYTE* pParamsTDelete)
1581 if( nWwCols && pParamsTDelete ) // set one or more cell length(s)
1583 BYTE nitcFirst= pParamsTDelete[0]; // first col to be deleted
1584 if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1585 return;
1586 BYTE nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1587 if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1588 return;
1591 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1592 * greater than or equal to itcLim to be moved
1594 int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1596 if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1598 WW8_TCell* pAktTC = pTCs + nitcFirst;
1599 int i = 0;
1600 while( i < nShlCnt )
1602 // adjust the left x-position
1603 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1605 // adjust the cell's borders
1606 *pAktTC = pTCs[ nitcLim + i];
1608 ++i;
1609 ++pAktTC;
1611 // adjust the left x-position of the dummy at the very end
1612 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1615 short nCellsDeleted = nitcLim - nitcFirst;
1616 //clip delete request to available number of cells
1617 if (nCellsDeleted > nWwCols)
1618 nCellsDeleted = nWwCols;
1619 nWwCols -= nCellsDeleted;
1623 // ReadShd liest ggfs die Hintergrundfarben einer Zeile ein.
1624 // Es muss vorher ReadDef aufgerufen worden sein
1625 void WW8TabBandDesc::ReadShd(const BYTE* pS )
1627 BYTE nLen = pS ? *(pS - 1) : 0;
1628 if( !nLen )
1629 return;
1631 if( !pSHDs )
1633 pSHDs = new WW8_SHD[nWwCols];
1634 memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) );
1637 short nAnz = nLen >> 1;
1638 if (nAnz > nWwCols)
1639 nAnz = nWwCols;
1641 SVBT16* pShd;
1642 int i;
1643 for(i=0, pShd = (SVBT16*)pS; i<nAnz; i++, pShd++ )
1644 pSHDs[i].SetWWValue( *pShd );
1647 void WW8TabBandDesc::ReadNewShd(const BYTE* pS, bool bVer67)
1649 BYTE nLen = pS ? *(pS - 1) : 0;
1650 if (!nLen)
1651 return;
1653 if (!pNewSHDs)
1654 pNewSHDs = new sal_uInt32[nWwCols];
1656 short nAnz = nLen / 10; //10 bytes each
1657 if (nAnz > nWwCols)
1658 nAnz = nWwCols;
1660 int i=0;
1661 while (i < nAnz)
1662 pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1664 while (i < nWwCols)
1665 pNewSHDs[i++] = COL_AUTO;
1668 void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols)
1670 memset( pCells, 0, nCols * sizeof( WW8_TCell ) );
1673 const BYTE *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1675 const BYTE *pParams;
1676 if (bVer67)
1677 pParams = pPap->HasSprm(24);
1678 else
1680 if (0 == (pParams = pPap->HasSprm(0x244B)))
1681 pParams = pPap->HasSprm(0x2416);
1683 return pParams;
1686 enum wwTableSprm
1688 sprmNil,
1690 sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable,
1691 sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc,
1692 sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
1693 sprmTDxaGapHalf, sprmTTableBorders,
1695 sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing
1698 wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1700 switch (eVer)
1702 case ww::eWW8:
1703 switch (nId)
1705 case 0xF614:
1706 return sprmTTableWidth;
1707 case 0x7629:
1708 return sprmTTextFlow;
1709 case 0x3403:
1710 return sprmTFCantSplit;
1711 case 0x3404:
1712 return sprmTTableHeader;
1713 case 0x3466:
1714 return sprmTFCantSplit90;
1715 case 0x5400:
1716 return sprmTJc;
1717 case 0x560B:
1718 return sprmTFBiDi;
1719 case 0x5622:
1720 return sprmTDelete;
1721 case 0x7621:
1722 return sprmTInsert;
1723 case 0x7623:
1724 return sprmTDxaCol;
1725 case 0x9407:
1726 return sprmTDyaRowHeight;
1727 case 0x9601:
1728 return sprmTDxaLeft;
1729 case 0x9602:
1730 return sprmTDxaGapHalf;
1731 case 0xD605:
1732 return sprmTTableBorders;
1733 case 0xD608:
1734 return sprmTDefTable;
1735 case 0xD609:
1736 return sprmTDefTableShd;
1737 case 0xD612:
1738 return sprmTDefTableNewShd;
1739 case 0xD620:
1740 return sprmTSetBrc;
1741 case 0xD632:
1742 return sprmTSpacing;
1743 case 0xD634:
1744 return sprmTNewSpacing;
1746 break;
1747 case ww::eWW7:
1748 case ww::eWW6:
1749 switch (nId)
1751 case 182:
1752 return sprmTJc;
1753 case 183:
1754 return sprmTDxaLeft;
1755 case 184:
1756 return sprmTDxaGapHalf;
1757 case 186:
1758 return sprmTTableHeader;
1759 case 187:
1760 return sprmTTableBorders;
1761 case 189:
1762 return sprmTDyaRowHeight;
1763 case 190:
1764 return sprmTDefTable;
1765 case 191:
1766 return sprmTDefTableShd;
1767 case 193:
1768 return sprmTSetBrc;
1769 case 194:
1770 return sprmTInsert;
1771 case 195:
1772 return sprmTDelete;
1773 case 196:
1774 return sprmTDxaCol;
1776 break;
1777 case ww::eWW2:
1778 switch (nId)
1780 case 146:
1781 return sprmTJc;
1782 case 147:
1783 return sprmTDxaLeft;
1784 case 148:
1785 return sprmTDxaGapHalf;
1786 case 153:
1787 return sprmTDyaRowHeight;
1788 case 154:
1789 return sprmTDefTable;
1790 case 155:
1791 return sprmTDefTableShd;
1792 case 157:
1793 return sprmTSetBrc;
1794 case 158:
1795 return sprmTInsert;
1796 case 159:
1797 return sprmTDelete;
1798 case 160:
1799 return sprmTDxaCol;
1801 break;
1803 return sprmNil;
1806 WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
1807 mpOldRedlineStack(0),
1808 pIo(pIoClass),
1809 pFirstBand(0),
1810 pActBand(0),
1811 pTmpPos(0),
1812 pTblNd(0),
1813 pTabLines(0),
1814 pTabLine(0),
1815 pTabBoxes(0),
1816 pTabBox(0),
1817 pMergeGroups(0),
1818 pAktWWCell(0),
1819 nRows(0),
1820 nDefaultSwCols(0),
1821 nBands(0),
1822 nMinLeft(0),
1823 nConvertedLeft(0),
1824 nMaxRight(0),
1825 nSwWidth(0),
1826 nPreferredWidth(0),
1827 nOrgDxaLeft(0),
1828 bOk(true),
1829 bClaimLineFmt(false),
1830 eOri(text::HoriOrientation::NONE),
1831 bIsBiDi(false),
1832 nAktRow(0),
1833 nAktBandRow(0),
1834 nAktCol(0),
1835 nRowsToRepeat(0),
1836 pTable(0),
1837 pParentPos(0),
1838 pFlyFmt(0),
1839 aItemSet(pIo->rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1)
1841 pIo->bAktAND_fNumberAcross = false;
1843 static const sal_Int16 aOriArr[] =
1845 text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1848 bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion());
1849 WW8_TablePos aTabPos;
1851 WW8PLCFxSave1 aSave;
1852 pIo->pPlcxMan->GetPap()->Save( aSave );
1854 WW8PLCFx_Cp_FKP* pPap = pIo->pPlcxMan->GetPapPLCF();
1856 eOri = text::HoriOrientation::LEFT;
1858 WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1860 wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion());
1862 // process pPap until end of table found
1865 short nTabeDxaNew = SHRT_MAX;
1866 bool bTabRowJustRead = false;
1867 const BYTE* pShadeSprm = 0;
1868 const BYTE* pNewShadeSprm = 0;
1869 WW8_TablePos *pTabPos = 0;
1871 // Suche Ende einer TabZeile
1872 if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->nInTable)))
1874 bOk = false;
1875 break;
1878 // Get the SPRM chains:
1879 // first from PAP and then from PCD (of the Piece Table)
1880 WW8PLCFxDesc aDesc;
1881 pPap->GetSprms( &aDesc );
1882 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1884 const BYTE* pParams = aSprmIter.GetAktParams();
1885 for (int nLoop = 0; nLoop < 2; ++nLoop)
1887 bool bRepeatedSprm = false;
1888 while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams()))
1890 sal_uInt16 nId = aSprmIter.GetAktId();
1891 wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion());
1892 switch (eSprm)
1894 case sprmTTableWidth:
1896 const BYTE b0 = pParams[0];
1897 const BYTE b1 = pParams[1];
1898 const BYTE b2 = pParams[2];
1899 if (b0 == 3) // Twips
1900 nPreferredWidth = b2 * 0x100 + b1;
1902 break;
1903 case sprmTTextFlow:
1904 pNewBand->ProcessDirection(pParams);
1905 break;
1906 case sprmTFCantSplit:
1907 pNewBand->bCantSplit = *pParams;
1908 bClaimLineFmt = true;
1909 break;
1910 case sprmTFCantSplit90:
1911 pNewBand->bCantSplit90 = *pParams;
1912 bClaimLineFmt = true;
1913 break;
1914 case sprmTTableBorders:
1915 pNewBand->ProcessSprmTTableBorders(bOldVer, pParams);
1916 break;
1917 case sprmTTableHeader:
1918 if (!bRepeatedSprm)
1920 nRowsToRepeat++;
1921 bRepeatedSprm = true;
1923 break;
1924 case sprmTJc:
1925 // sprmTJc - Justification Code
1926 if (nRows == 0)
1927 eOri = aOriArr[*pParams & 0x3];
1928 break;
1929 case sprmTFBiDi:
1930 bIsBiDi = SVBT16ToShort(pParams) ? true : false;
1931 break;
1932 case sprmTDxaGapHalf:
1933 pNewBand->nGapHalf = (INT16)SVBT16ToShort( pParams );
1934 break;
1935 case sprmTDyaRowHeight:
1936 pNewBand->nLineHeight = (INT16)SVBT16ToShort( pParams );
1937 bClaimLineFmt = true;
1938 break;
1939 case sprmTDefTable:
1940 pNewBand->ReadDef(bOldVer, pParams);
1941 bTabRowJustRead = true;
1942 break;
1943 case sprmTDefTableShd:
1944 pShadeSprm = pParams;
1945 break;
1946 case sprmTDefTableNewShd:
1947 pNewShadeSprm = pParams;
1948 break;
1949 case sprmTDxaLeft:
1950 // our Writer cannot shift single table lines
1951 // horizontally so we have to find the smallest
1952 // parameter (meaning the left-most position) and then
1953 // shift the whole table to that margin (see below)
1955 short nDxaNew = (INT16)SVBT16ToShort( pParams );
1956 nOrgDxaLeft = nDxaNew;
1957 if( nDxaNew < nTabeDxaNew )
1958 nTabeDxaNew = nDxaNew;
1960 break;
1961 case sprmTSetBrc:
1962 pNewBand->ProcessSprmTSetBRC(bOldVer, pParams);
1963 break;
1964 case sprmTDxaCol:
1965 pNewBand->ProcessSprmTDxaCol(pParams);
1966 break;
1967 case sprmTInsert:
1968 pNewBand->ProcessSprmTInsert(pParams);
1969 break;
1970 case sprmTDelete:
1971 pNewBand->ProcessSprmTDelete(pParams);
1972 break;
1973 case sprmTNewSpacing:
1974 pNewBand->ProcessSpacing(pParams);
1975 break;
1976 case sprmTSpacing:
1977 pNewBand->ProcessSpecificSpacing(pParams);
1978 break;
1979 default:
1982 aSprmIter++;
1985 if( !nLoop )
1987 pPap->GetPCDSprms( aDesc );
1988 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1992 // #55171: WW-Tabellen koennen Fly-Wechsel beinhalten daher hier
1993 // Tabellen abbrechen und neu beginnen noch steht *pPap noch vor
1994 // TabRowEnd, daher kann TestApo() mit letztem Parameter false und
1995 // damit wirksam gerufen werden.
1997 if (bTabRowJustRead)
1999 if (pShadeSprm)
2000 pNewBand->ReadShd(pShadeSprm);
2001 if (pNewShadeSprm)
2002 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
2005 if( nTabeDxaNew < SHRT_MAX )
2007 short* pCenter = pNewBand->nCenter;
2008 short firstDxaCenter = *pCenter;
2009 for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
2011 // #i30298# Use sprmTDxaLeft to adjust the left indent
2012 // #i40461# Use dxaGapHalf during calculation
2013 *pCenter +=
2014 (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
2018 if (!pActBand)
2019 pActBand = pFirstBand = pNewBand;
2020 else
2022 pActBand->pNextBand = pNewBand;
2023 pActBand = pNewBand;
2025 nBands++;
2027 pNewBand = new WW8TabBandDesc;
2029 nRows++;
2030 pActBand->nRows++;
2032 //Seek our pap to its next block of properties
2033 WW8PLCFxDesc aRes;
2034 aRes.pMemPos = 0;
2035 aRes.nStartPos = nStartCp;
2037 if (!(pPap->SeekPos(aRes.nStartPos)))
2039 aRes.nEndPos = WW8_CP_MAX;
2040 pPap->SetDirty(true);
2042 pPap->GetSprms(&aRes);
2043 pPap->SetDirty(false);
2045 //Are we at the end of available properties
2046 if (
2047 !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
2048 aRes.nStartPos == WW8_CP_MAX
2051 bOk = false;
2052 break;
2055 //Are we still in a table cell
2056 pParams = HasTabCellSprm(pPap, bOldVer);
2057 const BYTE *pLevel = pPap->HasSprm(0x6649);
2058 // InTable
2059 if (!pParams || (1 != *pParams) ||
2060 (pLevel && (*pLevel <= pIo->nInTable)))
2062 break;
2065 //Get the end of row new table positioning data
2066 WW8_CP nMyStartCp=nStartCp;
2067 if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->nInTable))
2068 if (SwWW8ImplReader::ParseTabPos(&aTabPos, pPap))
2069 pTabPos = &aTabPos;
2071 //Move back to this cell
2072 aRes.pMemPos = 0;
2073 aRes.nStartPos = nStartCp;
2075 // #114237 PlcxMan currently points too far ahead so we need to bring
2076 // it back to where we are trying to make a table
2077 pIo->pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2078 if (!(pPap->SeekPos(aRes.nStartPos)))
2080 aRes.nEndPos = WW8_CP_MAX;
2081 pPap->SetDirty(true);
2083 pPap->GetSprms(&aRes);
2084 pPap->SetDirty(false);
2086 //Does this row match up with the last row closely enough to be
2087 //considered part of the same table
2088 ApoTestResults aApo = pIo->TestApo(pIo->nInTable + 1, false, pTabPos);
2091 ##513##, #79474# If this is not sufficent, then we should look at
2092 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2093 part of this table, but instead is an absolutely positioned table
2094 outside of this one
2096 if (aApo.mbStopApo)
2097 break;
2098 if (aApo.mbStartApo)
2100 //if there really is a fly here, and not a "null" fly then break.
2101 WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos);
2102 if (pNewFly)
2103 delete pNewFly;
2104 else
2105 break;
2108 nStartCp = aRes.nEndPos;
2110 while( 1 );
2112 if( bOk )
2114 if( pActBand->nRows > 1 )
2116 // Letztes Band hat mehr als 1 Zeile
2117 delete pNewBand;
2118 pNewBand = new WW8TabBandDesc( *pActBand ); // neues machen
2119 pActBand->nRows--; // wegen Sonderbehandlung Raender-Defaults
2120 pNewBand->nRows = 1;
2121 pActBand->pNextBand = pNewBand; // am Ende einschleifen
2122 nBands++;
2123 pNewBand = 0; // nicht loeschen
2125 CalcDefaults();
2127 delete pNewBand;
2129 pIo->pPlcxMan->GetPap()->Restore( aSave );
2132 WW8TabDesc::~WW8TabDesc()
2134 WW8TabBandDesc* pR = pFirstBand;
2135 while(pR)
2137 WW8TabBandDesc* pR2 = pR->pNextBand;
2138 delete pR;
2139 pR = pR2;
2142 delete pParentPos;
2143 delete pMergeGroups;
2146 void WW8TabDesc::CalcDefaults()
2148 short nMinCols = SHRT_MAX;
2149 WW8TabBandDesc* pR;
2151 nMinLeft = SHRT_MAX;
2152 nMaxRight = SHRT_MIN;
2155 #101175#
2156 If we are an honestly inline centered table, then the normal rules of
2157 engagement for left and right margins do not apply. The multiple rows are
2158 centered regardless of the actual placement of rows, so we cannot have
2159 mismatched rows as is possible in other configurations.
2161 e.g. change the example bugdoc in word from text wrapping of none (inline)
2162 to around (in frame (bApo)) and the table splits into two very disjoint
2163 rows as the beginning point of each row are very different
2165 if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER))
2167 for (pR = pFirstBand; pR; pR = pR->pNextBand)
2168 for( short i = pR->nWwCols; i >= 0; --i)
2169 pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2172 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2173 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2175 if( pR->nCenter[0] < nMinLeft )
2176 nMinLeft = pR->nCenter[0];
2178 for( short i = 0; i < pR->nWwCols; i++ )
2181 #74387# If the margins are so large as to make the displayable
2182 area inside them smaller than the minimum allowed then adjust the
2183 width to fit. But only do it if the two cells are not the exact
2184 same value, if they are then the cell does not really exist and will
2185 be blended together into the same cell through the use of the
2186 nTrans(late) array.
2187 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2189 int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2190 if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2192 pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
2196 if( pR->nCenter[pR->nWwCols] > nMaxRight )
2197 nMaxRight = pR->nCenter[pR->nWwCols];
2199 nSwWidth = nMaxRight - nMinLeft;
2201 // #109830# If the table is right aligned we need to align all rows to the
2202 // row that has the furthest right point
2204 if(eOri == text::HoriOrientation::RIGHT)
2206 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2208 int adjust = nMaxRight - pR->nCenter[pR->nWwCols];
2209 for( short i = 0; i < pR->nWwCols + 1; i++ )
2211 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2217 // 2. Durchlauf: Zahl der Writer-Spalten feststellen Die Zahl der Writer
2218 // Spalten kann um bis zu 2 hoeher sein als im WW, da der SW im Gegensatz
2219 // zu WW keine ausgefransten linken und rechten Raender kann und diese
2220 // durch leere Boxen aufgefuellt werden. Durch nichtexistente Zellen
2221 // koennen auch Zellen wegfallen
2223 // 3. Durchlauf: Wo noetig die Umrandungen durch die Defaults ersetzen
2224 nConvertedLeft = nMinLeft;
2226 short nLeftMaxThickness = 0, nRightMaxThickness=0;
2227 for( pR = pFirstBand ; pR; pR = pR->pNextBand )
2229 if( !pR->pTCs )
2231 pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2232 memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) );
2234 for (int k = 0; k < pR->nWwCols; ++k)
2236 WW8_TCell* pT = &pR->pTCs[k];
2237 int i, j;
2238 for( i = 0; i < 4; i ++ )
2240 if (pT->rgbrc[i].IsZeroed(pIo->bVer67))
2242 // if shadow is set, its invalid
2243 j = i;
2244 switch( i )
2246 case 0:
2247 // Aussen oben / Innen waagerecht
2248 j = (pR == pFirstBand) ? 0 : 4;
2249 break;
2250 case 1:
2251 // Aussen links / Innen senkrecht
2252 j = k ? 5 : 1;
2253 break;
2254 case 2:
2255 // Aussen unten / Innen waagerecht
2256 j = pR->pNextBand ? 4 : 2;
2257 break;
2258 case 3:
2259 // Aussen rechts/ Innen senkrecht
2260 j = (k == pR->nWwCols - 1) ? 3 : 5;
2261 break;
2263 // mangel mit Defaults ueber
2264 pT->rgbrc[i] = pR->aDefBrcs[j];
2269 Similiar to graphics and other elements word does not totally
2270 factor the width of the border into its calculations of size, we
2271 do so we must adjust out widths and other dimensions to fit. It
2272 appears that what occurs is that the last cell's right margin if
2273 the margin width that is not calculated into winwords table
2274 dimensions, so in that case increase the table to include the
2275 extra width of the right margin.
2277 if ( pIo->bVer67 ?
2278 !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20)
2279 : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000))
2281 short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2282 DetermineBorderProperties(pIo->bVer67);
2283 pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2284 if (nThickness > nRightMaxThickness)
2285 nRightMaxThickness = nThickness;
2289 The left space of the table is in nMinLeft, but again this
2290 does not consider the margin thickness to its left in the
2291 placement value, so get the thickness of the left border,
2292 half is placed to the left of the nominal left side, and
2293 half to the right.
2295 if ( pIo->bVer67 ?
2296 !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20)
2297 : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000))
2299 short nThickness = pR->pTCs[0].rgbrc[1].
2300 DetermineBorderProperties(pIo->bVer67);
2301 if (nThickness > nLeftMaxThickness)
2302 nLeftMaxThickness = nThickness;
2305 nSwWidth = nSwWidth + nRightMaxThickness;
2306 nMaxRight = nMaxRight + nRightMaxThickness;
2307 nConvertedLeft = nMinLeft-(nLeftMaxThickness/2);
2309 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2311 pR->nSwCols = pR->nWwCols;
2312 pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY;
2313 pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2315 short nAddCols = pR->bLEmptyCol + pR->bREmptyCol;
2316 USHORT i;
2317 USHORT j = ( pR->bLEmptyCol ) ? 1 : 0;
2318 for (i = 0; i < pR->nWwCols; ++i)
2320 pR->nTransCell[i] = (INT8)j;
2321 if ( pR->nCenter[i] < pR->nCenter[i+1] )
2323 pR->bExist[i] = true;
2324 j++;
2326 else
2328 pR->bExist[i] = false;
2329 nAddCols--;
2333 ASSERT(i,"no columns in row ?");
2336 #96345#
2337 If the last cell was "false" then there is no valid cell following it,
2338 so the default mapping forward wont't work. So map it (and
2339 contigious invalid cells backwards to the last valid cell instead.
2341 if (i && pR->bExist[i-1] == false)
2343 USHORT k=i-1;
2344 while (k && pR->bExist[k] == false)
2345 k--;
2346 for (USHORT n=k+1;n<i;n++)
2347 pR->nTransCell[n] = pR->nTransCell[k];
2350 pR->nTransCell[i++] = (INT8)(j++); // Wird u.a. wegen bREmptyCol um
2351 pR->nTransCell[i] = (INT8)j; // max. 2 ueberindiziert
2353 pR->nSwCols = pR->nSwCols + nAddCols;
2354 if( pR->nSwCols < nMinCols )
2355 nMinCols = pR->nSwCols;
2359 #i9718#
2360 Find the largest of the borders on cells that adjoin top bottom and remove
2361 the val from the top and put in on the bottom cell. I can't seem to make
2362 disjoint upper and lowers to see what happens there.
2365 /* #i29550# FME 2004-06-02 Removed this code because of the implementation
2366 of the collapsing table borders model. So this should not be necessary
2367 anymore. */
2369 /* for (pR = pFirstBand; pR; pR = pR->pNextBand)
2371 WW8TabBandDesc *pNext = pR->pNextBand;
2372 if (!pNext)
2373 break;
2375 for (int k = 0; k < pR->nWwCols; ++k)
2377 WW8_BRC &rAbove = pR->pTCs[k].rgbrc[WW8_BOT];
2378 short nAboveThick = rAbove.IsEmpty(pIo->bVer67) ?
2379 0 : rAbove.DetermineBorderProperties(pIo->bVer67);
2380 short nUpperLeft = pR->nCenter[k];
2381 short nUpperRight = pR->nCenter[k+1];
2383 for (int l = 0; l < pNext->nWwCols; ++l)
2385 short nLowerLeft = pNext->nCenter[l];
2386 short nLowerRight = pNext->nCenter[l+1];
2388 if ((nLowerLeft < nUpperLeft) || (nLowerRight > nUpperRight))
2389 continue;
2391 WW8_BRC &rBelow = pNext->pTCs[l].rgbrc[WW8_TOP];
2392 short nBelowThick = rBelow.IsEmpty(pIo->bVer67) ?
2393 0 : rBelow.DetermineBorderProperties(pIo->bVer67);
2394 if (nAboveThick > nBelowThick)
2395 rBelow = rAbove;
2398 rAbove = WW8_BRC();
2400 } */
2402 if ((nMinLeft && !bIsBiDi && text::HoriOrientation::LEFT == eOri) ||
2403 (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used
2404 eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2406 nDefaultSwCols = nMinCols; // da Zellen einfuegen billiger ist als Mergen
2407 if( nDefaultSwCols == 0 )
2408 bOk = false;
2409 pActBand = pFirstBand;
2410 nAktBandRow = 0;
2411 ASSERT( pActBand, "pActBand ist 0" );
2414 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt)
2416 SwFrmFmt* pApply = pFrmFmt;
2417 if (!pApply )
2418 pApply = pTable->GetFrmFmt();
2419 ASSERT(pApply,"No frame");
2420 pApply->SetFmtAttr(aItemSet);
2421 if (pFrmFmt)
2423 SwFmtFrmSize aSize = pFrmFmt->GetFrmSize();
2424 aSize.SetHeightSizeType(ATT_MIN_SIZE);
2425 aSize.SetHeight(MINLAY);
2426 pFrmFmt->SetFmtAttr(aSize);
2427 pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL));
2431 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2432 const SwNode &rNode)
2434 ASSERT(!maSegments.empty(),
2435 "should not be possible, must be at least one segment");
2436 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2437 maSegments.back().maStart = SwNodeIndex(rNode);
2440 void WW8TabDesc::CreateSwTable()
2442 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
2444 // if there is already some content on the Node append new node to ensure
2445 // that this content remains ABOVE the table
2446 SwPosition* pPoint = pIo->pPaM->GetPoint();
2447 bool bInsNode = pPoint->nContent.GetIndex() ? true : false;
2448 bool bSetMinHeight = false;
2451 #i8062#
2452 Set fly anchor to its anchor pos, so that if a table starts immediately
2453 at this position a new node will be inserted before inserting the table.
2455 if (!bInsNode && pIo->pFmtOfJustInsertedApo)
2457 const SwPosition* pAPos =
2458 pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor();
2459 if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2461 bInsNode = true;
2462 bSetMinHeight = true;
2464 SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround());
2465 aSur.SetAnchorOnly(true);
2466 pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur);
2470 if (bSetMinHeight == true)
2472 // minimize Fontsize to minimize height growth of the header/footer
2473 // set font size to 1 point to minimize y-growth of Hd/Ft
2474 SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2475 pIo->NewAttr( aSz );
2476 pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2479 if (bInsNode)
2480 pIo->AppendTxtNode(*pPoint);
2482 pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() );
2484 // Die Tabelle ist beim Einfuegen noch recht klein: Zahl der Spalten ist
2485 // die kleinste Spaltenanzahl des Originals, da Spalten einfuegen
2486 // schneller geht als Loeschen Zahl der Zeilen ist die Zahl der Baender,
2487 // da sich die (identischen) Zeilen eines Bandes prima duplizieren lassen
2488 pTable = pIo->rDoc.InsertTable(
2489 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2490 *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, FALSE, TRUE );
2492 ASSERT(pTable && pTable->GetFrmFmt(), "insert table failed");
2493 if (!pTable || !pTable->GetFrmFmt())
2494 return;
2496 SwTableNode* pTableNode = pTable->GetTableNode();
2497 ASSERT(pTableNode, "no table node!");
2498 if (pTableNode)
2500 pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(),
2501 *pTableNode);
2504 // Abfrage, ob im Node, in dem die Tabelle eingefuegt werden soll, bereits
2505 // ein Pagedesc steht. Dann wuerde der PageDesc in die naechste Zeile
2506 // hinter der Tabelle rutschen, wo er nichts zu suchen hat. -> loeschen
2507 // und spaeter an das Tabellenformat setzen
2508 if (SwTxtNode* pNd = pIo->rDoc.GetNodes()[pTmpPos->nNode]->GetTxtNode())
2510 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2512 SfxPoolItem *pSetAttr = 0;
2513 const SfxPoolItem* pItem;
2514 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2516 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem );
2517 pNd->ResetAttr( RES_BREAK );
2520 // evtl den PageDesc/Break jetzt an der Tabelle setzen
2521 if (pSetAttr)
2523 aItemSet.Put(*pSetAttr);
2524 delete pSetAttr;
2529 // Gesamtbreite der Tabelle
2530 if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2532 pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2533 aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2536 SvxFrameDirectionItem aDirection(
2537 bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2538 pTable->GetFrmFmt()->SetFmtAttr(aDirection);
2540 if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2542 if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt &&
2543 GetMinLeft())
2545 //If we are inside a frame and we have a border, the frames
2546 //placement does not consider the tables border, which word
2547 //displays outside the frame, so adjust here.
2548 SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient());
2549 sal_Int16 eHori = aHori.GetHoriOrient();
2550 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2551 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2553 //With multiple table, use last table settings. Perhaps
2554 //the maximum is what word does ?
2555 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft());
2556 aHori.SetHoriOrient(text::HoriOrientation::NONE);
2557 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori);
2560 else
2562 //If bApo is set, then this table is being placed in a floating
2563 //frame, and the frame matches the left and right *lines* of the
2564 //table, so the space to the left of the table isn't to be used
2565 //inside the frame, in word the dialog involved greys out the
2566 //ability to set the margin.
2567 SvxLRSpaceItem aL( RES_LR_SPACE );
2568 // set right to original DxaLeft (i28656)
2570 long nLeft = 0;
2571 if (!bIsBiDi)
2572 nLeft = GetMinLeft();
2573 else
2575 if (nPreferredWidth)
2576 nLeft = pIo->maSectionManager.GetTextAreaWidth() - nPreferredWidth - nOrgDxaLeft;
2577 else
2578 nLeft = -GetMinLeft();
2581 aL.SetLeft(nLeft);
2583 aItemSet.Put(aL);
2587 mpOldRedlineStack = pIo->mpRedlineStack;
2588 pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc);
2591 void WW8TabDesc::UseSwTable()
2593 // globale Varis initialisieren
2594 pTabLines = &pTable->GetTabLines();
2595 nAktRow = nAktCol = nAktBandRow = 0;
2597 pTblNd = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]->
2598 GetSttNd()->FindTableNode();
2599 ASSERT( pTblNd, "wo ist mein TabellenNode" );
2601 // --> mloiseleur 2007-10-10 #i69519# Restrict rows to repeat to a decent value
2602 if ( nRowsToRepeat == static_cast<USHORT>(nRows) )
2603 nRowsToRepeat = 1;
2604 // <--
2606 pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2607 // ggfs. Zusatz-Zellen einfuegen u.dgl.
2608 AdjustNewBand();
2610 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2611 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false);
2613 // jetzt den PaM korrekt setzen und ggfs. erste Mergegruppe vorbereiten...
2614 SetPamInCell(nAktCol, true);
2615 aDup.Insert(*pIo->pPaM->GetPoint());
2617 pIo->bWasTabRowEnd = false;
2618 pIo->bWasTabCellEnd = false;
2621 void WW8TabDesc::MergeCells()
2623 short nRow;
2625 for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2628 // ggfs. aktuelle Box in entsprechende Merge-Gruppe eintragen
2630 if( pActBand->pTCs )
2632 for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2633 for( short i = 0; i < pActBand->nWwCols; i++ )
2635 WW8SelBoxInfoPtr pActMGroup = 0;
2637 // ggfs. eine neue Merge-Gruppe beginnen
2639 ASSERT(nRow < pTabLines->Count(),
2640 "Too few lines, table ended early");
2641 if (nRow >= pTabLines->Count())
2642 return;
2643 pTabLine = (*pTabLines)[ nRow ];
2644 pTabBoxes = &pTabLine->GetTabBoxes();
2646 USHORT nCol = pActBand->nTransCell[ i ];
2647 if (!pActBand->bExist[i]) //#113434#
2648 continue;
2649 ASSERT(nCol < pTabBoxes->Count(),
2650 "Too few columns, table ended early");
2651 if (nCol >= pTabBoxes->Count())
2652 return;
2653 pTabBox = (*pTabBoxes)[nCol];
2654 WW8_TCell& rCell = pActBand->pTCs[ i ];
2655 // ist dies die obere, linke-Zelle einer Merge-Gruppe ?
2657 bool bMerge = false;
2658 if ( rCell.bVertRestart && !rCell.bMerged )
2659 bMerge = true;
2660 else if (rCell.bFirstMerged && pActBand->bExist[i])
2662 //#91211# Some tests to avoid merging cells
2663 //which previously were declared invalid because
2664 //of sharing the exact same dimensions as their
2665 //previous cell
2667 //If theres anything underneath/above we're ok.
2668 if (rCell.bVertMerge || rCell.bVertRestart)
2669 bMerge = true;
2670 else
2672 //If its a hori merge only, and the only things in
2673 //it are invalid cells then its already taken care
2674 //of, so don't merge.
2675 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2676 if (pActBand->pTCs[ i2 ].bMerged &&
2677 !pActBand->pTCs[ i2 ].bFirstMerged )
2679 if (pActBand->bExist[i2])
2681 bMerge = true;
2682 break;
2685 else
2686 break;
2691 if (bMerge)
2693 short nX1 = pActBand->nCenter[ i ];
2694 short nWidth = pActBand->nWidth[ i ];
2696 // 0. falls noetig das Array fuer die Merge-Gruppen
2697 // anlegen
2698 if( !pMergeGroups )
2699 pMergeGroups = new WW8MergeGroups;
2701 // 2. aktuelle Merge-Gruppe anlegen
2702 pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2704 // --> OD 2005-02-04 #118544# - determine size of new
2705 // merge group before inserted the new merge group.
2706 // Needed to correctly locked previously created merge groups.
2707 // Gesamtbreite ermitteln und zuweisen
2708 short nSizCell = pActBand->nWidth[ i ];
2709 for (USHORT i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2710 if (pActBand->pTCs[ i2 ].bMerged &&
2711 !pActBand->pTCs[ i2 ].bFirstMerged )
2713 nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2715 else
2716 break;
2717 pActMGroup->nGroupWidth = nSizCell;
2718 // <--
2720 // --> OD 2005-02-03 #118544# - locked previously
2721 // created merge groups, after determining the size
2722 // for the new merge group.
2723 // 1. ggfs. alte Mergegruppe(n) schliessen, die
2724 // den von unserer neuen Gruppe betroffenen
2725 // X-Bereich ueberdecken
2726 short nMGrIdx;
2727 while ( FindMergeGroup( nX1, pActMGroup->nGroupWidth,
2728 false, nMGrIdx ) )
2730 (*pMergeGroups)[ nMGrIdx ]->bGroupLocked = true;
2732 // <--
2734 // 3. und in Gruppen-Array eintragen
2735 pMergeGroups->Insert(pActMGroup, pMergeGroups->Count());
2738 // ggfs. akt. Box zu einer Merge-Gruppe hinzufuegen (dies
2739 // kann eine soeben angelegte, oder eine andere Gruppe
2740 // sein)
2741 UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2747 //There is a limbo area in word at the end of the row marker
2748 //where properties can live in word, there is no location in
2749 //writer equivalent, so try and park the cursor in the best
2750 //match, see #i23022#/#i18644#
2751 void WW8TabDesc::ParkPaM()
2753 SwTableBox *pTabBox2 = 0;
2754 short nRow = nAktRow + 1;
2755 if (nRow < pTabLines->Count())
2757 if (SwTableLine *pLine = (*pTabLines)[nRow])
2759 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2760 pTabBox2 = rBoxes.Count() ? rBoxes[0] : 0;
2764 if (!pTabBox2 || !pTabBox2->GetSttNd())
2766 MoveOutsideTable();
2767 return;
2770 if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1)
2772 pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1;
2773 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2774 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2778 void WW8TabDesc::MoveOutsideTable()
2780 ASSERT(pTmpPos && pIo, "I've forgotten where the table is anchored");
2781 if (pTmpPos && pIo)
2782 *pIo->pPaM->GetPoint() = *pTmpPos;
2785 void WW8TabDesc::FinishSwTable()
2787 pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint());
2788 delete pIo->mpRedlineStack;
2789 pIo->mpRedlineStack = mpOldRedlineStack;
2790 mpOldRedlineStack = 0;
2792 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2793 pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false);
2795 MoveOutsideTable();
2796 delete pTmpPos, pTmpPos = 0;
2798 aDup.Insert(*pIo->pPaM->GetPoint());
2800 pIo->bWasTabRowEnd = false;
2801 pIo->bWasTabCellEnd = false;
2803 pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM);
2805 MergeCells();
2807 // falls noetig, zu mergende Zellen gruppenweise zusammenfassen
2808 if( pMergeGroups )
2810 // bearbeite alle Merge-Gruppen nacheinander
2811 WW8SelBoxInfo* pActMGroup;
2812 USHORT nActBoxCount;
2814 for (USHORT iGr = 0; iGr < pMergeGroups->Count(); ++iGr)
2816 pActMGroup = (*pMergeGroups)[ iGr ];
2817 nActBoxCount = pActMGroup->Count();
2819 if( ( 1 < nActBoxCount ) && pActMGroup && (*pActMGroup)[ 0 ] )
2821 const USHORT nRowSpan = pActMGroup->Count();
2822 for (USHORT n = 0; n < nRowSpan; ++n)
2824 SwTableBox* pCurrentBox = (*pActMGroup)[n];
2825 const long nRowSpanSet = n == 0 ?
2826 nRowSpan :
2827 ((-1) * (nRowSpan - n));
2828 pCurrentBox->setRowSpan( nRowSpanSet );
2832 pIo->pFmtOfJustInsertedApo = 0;
2833 DELETEZ( pMergeGroups );
2838 // durchsucht pMergeGroups, meldet Index der ersten, passenden Gruppe bzw. -1
2840 // Parameter: nXcenter = Mittenposition der anfragenden Box
2841 // nWidth = Breite der anfragenden Box
2842 // bExact = Flag, ob Box in dieser Gruppe passen muss,
2843 // oder diese nur zu tangieren braucht
2845 bool WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact,
2846 short& nMGrIdx)
2848 nMGrIdx = -1;
2849 if( pMergeGroups )
2851 // noch als gueltig angesehener Bereich in der Naehe der Grenzen
2852 const short nToleranz = 4;
2853 // die aktuell untersuchte Gruppe
2854 WW8SelBoxInfoPtr pActGroup;
2855 // Boxgrenzen
2856 short nX2 = nX1 + nWidth;
2857 // ungefaehre Gruppengrenzen
2858 short nGrX1;
2859 short nGrX2;
2861 // --> OD 2005-02-04 #118544# - improvement: search backwards
2862 //for ( USHORT iGr = 0; iGr < pMergeGroups->Count(); iGr++ )
2863 for ( short iGr = pMergeGroups->Count() - 1; iGr >= 0; --iGr )
2865 // die aktuell untersuchte Gruppe
2866 pActGroup = (*pMergeGroups)[ iGr ];
2867 if (!pActGroup->bGroupLocked)
2869 // ungefaehre Gruppengrenzen mit Toleranz nach *aussen* hin
2870 nGrX1 = pActGroup->nGroupXStart - nToleranz;
2871 nGrX2 = pActGroup->nGroupXStart
2872 +pActGroup->nGroupWidth + nToleranz;
2874 // Falls Box reinpasst, melde auf jeden Fall den Erfolg
2876 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2878 nMGrIdx = iGr; break;
2881 // hat die Box Bereiche mit der Gruppe gemeinsam?
2883 if( !bExact )
2885 // melde Erfolg, wenn nX1 *oder* nX2 innerhalb der Gruppe liegen
2886 if( ( ( nX1 > nGrX1 )
2887 && ( nX1 < nGrX2 - 2*nToleranz ) )
2888 || ( ( nX2 > nGrX1 + 2*nToleranz )
2889 && ( nX2 < nGrX2 ) )
2890 // oder nX1 und nX2 die Gruppe umfassen
2891 || ( ( nX1 <=nGrX1 )
2892 && ( nX2 >=nGrX2 ) ) )
2894 nMGrIdx = iGr; break;
2900 return ( -1 < nMGrIdx );
2903 bool WW8TabDesc::IsValidCell(short nCol) const
2905 return pActBand->bExist[nCol] && (USHORT)nAktRow < pTabLines->Count();
2908 bool WW8TabDesc::InFirstParaInCell() const
2910 //e.g. #i19718#
2911 if (!pTabBox || !pTabBox->GetSttNd())
2913 ASSERT(false, "Problem with table");
2914 return false;
2917 if (!IsValidCell(GetAktCol()))
2918 return false;
2920 if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2921 return true;
2923 return false;
2926 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2928 ASSERT(pActBand, "Impossible");
2929 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2931 pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(),
2932 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2936 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2938 ASSERT(pActBand, "Impossible");
2939 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2940 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE);
2943 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2945 ASSERT( pActBand, "pActBand ist 0" );
2947 USHORT nCol = pActBand->nTransCell[nWwCol];
2949 if ((USHORT)nAktRow >= pTabLines->Count())
2951 ASSERT(!this, "Actual row bigger than expected." );
2952 if (bPam)
2953 MoveOutsideTable();
2954 return false;
2957 pTabLine = (*pTabLines)[nAktRow];
2958 pTabBoxes = &pTabLine->GetTabBoxes();
2960 if (nCol >= pTabBoxes->Count())
2962 if (bPam)
2964 // The first paragraph in a cell with upper autospacing has upper
2965 // spacing set to 0
2966 if (
2967 pIo->bParaAutoBefore && pIo->bFirstPara &&
2968 !pIo->pWDop->fDontUseHTMLAutoSpacing
2971 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2974 // The last paragraph in a cell with lower autospacing has lower
2975 // spacing set to 0
2976 if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2977 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2979 ParkPaM();
2981 return false;
2983 pTabBox = (*pTabBoxes)[nCol];
2984 if( !pTabBox->GetSttNd() )
2986 ASSERT(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2987 if (bPam)
2988 MoveOutsideTable();
2989 return false;
2991 if (bPam)
2993 pAktWWCell = &pActBand->pTCs[ nWwCol ];
2995 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2996 if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2997 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2999 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
3000 if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
3001 pIo->SetLowerSpacing(*pIo->pPaM, 0);
3003 //We need to set the pPaM on the first cell, invalid
3004 //or not so that we can collect paragraph proproties over
3005 //all the cells, but in that case on the valid cell we do not
3006 //want to reset the fmt properties
3007 if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1)
3009 pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1;
3010 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3011 // Zur Sicherheit schon jetzt setzen, da bei den Zellen, die
3012 // zum Randausgleich eingefuegt werden, sonst der Style
3013 // nicht gesetzt wird.
3014 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
3015 // uebrigens: da diese Zellen unsichtbare Hilfskonstruktionen sind,
3016 // und nur dazu dienen, zerfranste Aussehen der WW-Tabelle
3017 // nachzuahmen, braucht NICHT SetTxtFmtCollAndListLevel()
3018 // verwendet zu werden.
3021 // Better to turn Snap to Grid off for all paragraphs in tables
3022 if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode())
3024 const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID);
3025 SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm);
3027 if(rSnapToGrid.GetValue())
3029 SvxParaGridItem aGridItem( rSnapToGrid );
3030 aGridItem.SetValue(false);
3032 SwPosition* pGridPos = pIo->pPaM->GetPoint();
3034 xub_StrLen nEnd = pGridPos->nContent.GetIndex();
3035 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
3036 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem);
3037 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd);
3038 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
3042 StartMiserableHackForUnsupportedDirection(nWwCol);
3044 return true;
3047 void WW8TabDesc::InsertCells( short nIns )
3049 pTabLine = (*pTabLines)[nAktRow];
3050 pTabBoxes = &pTabLine->GetTabBoxes();
3051 pTabBox = (*pTabBoxes)[0];
3053 pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(),
3054 (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->Count(), nIns );
3055 // mit dem Dritten Parameter wird das FrmFmt der Boxen angegeben.
3056 // hier kann man auch noch optimieren, um FrmFmts zu sparen
3059 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3061 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3062 return; // kuenstlich erzeugte Zellen -> Kein Rand
3065 SvxBoxItem aFmtBox( RES_BOX );
3066 if (pActBand->pTCs) // neither Cell Border nor Default Border defined ?
3068 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3069 if (pIo->IsBorder(pT->rgbrc))
3070 pIo->SetBorder(aFmtBox, pT->rgbrc);
3073 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
3075 aFmtBox.SetDistance(
3076 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
3077 BOX_LINE_TOP);
3079 else
3080 aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP);
3081 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
3083 aFmtBox.SetDistance(
3084 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
3085 BOX_LINE_BOTTOM);
3087 else
3088 aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM);
3090 // nGapHalf bedeutet bei WW ein *horizontaler* Abstand zwischen
3091 // Tabellenzelle und -Inhalt
3092 short nLeftDist =
3093 pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
3094 short nRightDist =
3095 pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
3096 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
3098 aFmtBox.SetDistance(
3099 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
3100 BOX_LINE_LEFT);
3102 else
3103 aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT);
3104 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
3106 aFmtBox.SetDistance(
3107 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
3108 BOX_LINE_RIGHT);
3110 else
3111 aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT);
3113 pBox->GetFrmFmt()->SetFmtAttr(aFmtBox);
3116 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3118 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3119 return; // kuenstlich erzeugte Zellen -> Keine Farbe
3121 bool bFound=false;
3122 if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3124 Color aColor(pActBand->pNewSHDs[nWwIdx]);
3125 if (aColor.GetColor() == 0x00333333)
3126 pIo->maTracer.Log(sw::log::eAutoColorBg);
3127 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND));
3128 bFound = true;
3131 //If there was no new shades, or no new shade setting
3132 if (pActBand->pSHDs && !bFound)
3134 WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3135 if (!rSHD.GetValue()) // auto
3136 return;
3138 SwWW8Shade aSh( pIo->bVer67, rSHD );
3139 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3143 SvxFrameDirection MakeDirection(sal_uInt16 nCode, BOOL bIsBiDi)
3145 SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3146 // 1: Asian layout with rotated CJK characters
3147 // 5: Asian layout
3148 // 3: Western layout rotated by 90 degrees
3149 // 4: Western layout
3150 switch (nCode)
3152 default:
3153 ASSERT(eDir == 4, "unknown direction code, maybe its a bitfield");
3154 case 3:
3155 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3156 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3157 // <--
3158 break;
3159 case 5:
3160 eDir = FRMDIR_VERT_TOP_RIGHT;
3161 break;
3162 case 1:
3163 eDir = FRMDIR_VERT_TOP_RIGHT;
3164 break;
3165 case 4:
3166 // --> FME/Alan Yaniger: 2006-09-15 #i38158# Consider RTL tables:
3167 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
3168 // <--
3169 break;
3171 return eDir;
3174 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3176 if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3177 return;
3178 SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3179 pBox->GetFrmFmt()->SetFmtAttr(aItem);
3182 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3184 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3185 return;
3187 sal_Int16 eVertOri=text::VertOrientation::TOP;
3189 if( pActBand->pTCs )
3191 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3192 switch (pT->nVertAlign)
3194 case 0:
3195 default:
3196 eVertOri = text::VertOrientation::TOP;
3197 break;
3198 case 1:
3199 eVertOri = text::VertOrientation::CENTER;
3200 break;
3201 case 2:
3202 eVertOri = text::VertOrientation::BOTTOM;
3203 break;
3207 pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) );
3210 void WW8TabDesc::AdjustNewBand()
3212 if( pActBand->nSwCols > nDefaultSwCols ) // Zellen splitten
3213 InsertCells( pActBand->nSwCols - nDefaultSwCols );
3215 SetPamInCell( 0, false);
3216 ASSERT( pTabBoxes && pTabBoxes->Count() == (USHORT)pActBand->nSwCols,
3217 "Falsche Spaltenzahl in Tabelle" )
3219 if( bClaimLineFmt )
3221 pTabLine->ClaimFrmFmt(); // noetig wg. Zeilenhoehe
3222 SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3224 if (pActBand->nLineHeight == 0) // 0 = Auto
3225 aF.SetHeightSizeType( ATT_VAR_SIZE );
3226 else
3228 if (pActBand->nLineHeight < 0) // Pos = min, Neg = exakt
3230 aF.SetHeightSizeType(ATT_FIX_SIZE);
3231 pActBand->nLineHeight = -pActBand->nLineHeight;
3233 if (pActBand->nLineHeight < MINLAY) // nicht erlaubte Zeilenhoehe
3234 pActBand->nLineHeight = MINLAY;
3236 aF.SetHeight(pActBand->nLineHeight);// Min- / Exakt-Hoehe setzen
3238 pTabLine->GetFrmFmt()->SetFmtAttr(aF);
3241 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3242 //we can split the row
3243 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3244 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3245 // Word versions >= 2002.
3246 bool bSetCantSplit = pActBand->bCantSplit;
3247 if(bSetCantSplit)
3248 bSetCantSplit = pActBand->bCantSplit90;
3250 pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit));
3252 short i; // SW-Index
3253 short j; // WW-Index
3254 short nW; // Breite
3255 SwFmtFrmSize aFS( ATT_FIX_SIZE );
3256 j = pActBand->bLEmptyCol ? -1 : 0;
3258 for( i = 0; i < pActBand->nSwCols; i++ )
3260 // setze Zellenbreite
3261 if( j < 0 )
3262 nW = pActBand->nCenter[0] - nMinLeft;
3263 else
3265 //Set j to first non invalid cell
3266 while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3267 j++;
3269 if( j < pActBand->nWwCols )
3270 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3271 else
3272 nW = nMaxRight - pActBand->nCenter[j];
3273 pActBand->nWidth[ j ] = nW;
3276 SwTableBox* pBox = (*pTabBoxes)[i];
3277 // liesse sich durch intelligentes Umhaengen der FrmFmts noch weiter
3278 // verringern
3279 pBox->ClaimFrmFmt();
3281 SetTabBorders(pBox, j);
3283 // #i18128# word has only one line between adjoining vertical cells
3284 // we have to mimick this in the filter by picking the larger of the
3285 // sides and using that one on one side of the line (right)
3286 SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX));
3287 const SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT);
3288 int nCurrentRightLineWidth = 0;
3289 if(pLeftLine)
3290 nCurrentRightLineWidth = pLeftLine->GetInWidth() + pLeftLine->GetOutWidth() + pLeftLine->GetDistance();
3292 if (i != 0)
3294 SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3295 SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX));
3296 const SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT);
3297 int nOldBoxRightLineWidth = 0;
3298 if(pRightLine)
3299 nOldBoxRightLineWidth = pRightLine->GetInWidth() + pRightLine->GetOutWidth() + pRightLine->GetDistance();
3301 if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3302 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT);
3304 aOldBox.SetLine(0, BOX_LINE_RIGHT);
3305 pBox2->GetFrmFmt()->SetFmtAttr(aOldBox);
3308 pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox);
3310 SetTabVertAlign(pBox, j);
3311 SetTabDirection(pBox, j);
3312 if( pActBand->pSHDs || pActBand->pNewSHDs)
3313 SetTabShades(pBox, j);
3314 j++;
3316 aFS.SetWidth( nW );
3317 pBox->GetFrmFmt()->SetFmtAttr( aFS );
3319 // ueberspringe nicht existente Zellen
3320 while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3322 pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3323 j++;
3328 void WW8TabDesc::TableCellEnd()
3330 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
3332 EndMiserableHackForUnsupportedDirection(nAktCol);
3334 // neue Zeile
3335 if( pIo->bWasTabRowEnd )
3337 // bWasTabRowEnd will be deactivated in
3338 // SwWW8ImplReader::ProcessSpecial()
3340 USHORT iCol = GetLogicalWWCol();
3341 if (iCol < aNumRuleNames.size())
3343 aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3344 aNumRuleNames.end());
3347 nAktCol = 0;
3348 nAktRow++;
3349 nAktBandRow++;
3350 ASSERT( pActBand , "pActBand ist 0" );
3351 if( pActBand )
3353 if( nAktRow >= nRows ) // am Tabellenende gibt's nichts sinnvolles
3354 return; // mehr zu tun
3356 bool bNewBand = nAktBandRow >= pActBand->nRows;
3357 if( bNewBand )
3358 { // neues Band noetig ?
3359 pActBand = pActBand->pNextBand; //
3360 nAktBandRow = 0;
3361 ASSERT( pActBand, "pActBand ist 0" );
3362 AdjustNewBand();
3364 else
3366 SwTableBox* pBox = (*pTabBoxes)[0];
3367 SwSelBoxes aBoxes;
3368 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) );
3372 else
3373 { // neue Spalte ( Zelle )
3374 nAktCol++;
3376 SetPamInCell(nAktCol, true);
3378 // finish Annotated Level Numbering ?
3379 if (pIo->bAnl && !pIo->bAktAND_fNumberAcross)
3380 pIo->StopAllAnl(IsValidCell(nAktCol));
3383 // ggfs. die Box in fuer diese Col offene Merge-Gruppe eintragen
3384 SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell,
3385 WW8SelBoxInfo* pActGroup,
3386 SwTableBox* pActBox,
3387 USHORT nCol )
3389 // Rueckgabewert defaulten
3390 SwTableBox* pResult = 0;
3392 // pruefen, ob die Box zu mergen ist
3393 // --> OD 2005-02-04 #118544# - If cell is the first one to be merged,
3394 // a new merge group has to be provided.
3395 // E.g., it could be that a cell is the first one to be merged, but no
3396 // new merge group is provided, because the potential other cell to be merged
3397 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3398 if ( pActBand->bExist[ nCol ] &&
3399 ( ( rCell.bFirstMerged && pActGroup ) ||
3400 rCell.bMerged ||
3401 rCell.bVertMerge ||
3402 rCell.bVertRestart ) )
3403 // <--
3405 // passende Merge-Gruppe ermitteln
3406 WW8SelBoxInfo* pTheMergeGroup = 0;
3407 if( pActGroup )
3408 // Gruppe uebernehmen
3409 pTheMergeGroup = pActGroup;
3410 else
3412 // Gruppe finden
3413 short nMGrIdx;
3414 if( FindMergeGroup( pActBand->nCenter[ nCol ],
3415 pActBand->nWidth[ nCol ], true, nMGrIdx ) )
3416 pTheMergeGroup = (*pMergeGroups)[ nMGrIdx ];
3418 if( pTheMergeGroup )
3420 // aktuelle Box der Merge-Gruppe hinzufuegen
3421 pTheMergeGroup->Insert( pActBox, pTheMergeGroup->Count() );
3423 // Target-Box zurueckmelden
3424 pResult = (*pTheMergeGroup)[ 0 ];
3427 return pResult;
3431 USHORT WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3433 USHORT nCol = 0;
3434 if( pActBand && pActBand->pTCs)
3436 for( USHORT iCol = 1; iCol <= nAktCol; ++iCol )
3438 if( !pActBand->pTCs[ iCol-1 ].bMerged )
3439 ++nCol;
3442 return nCol;
3445 // find name of numrule valid for current WW-COL
3446 const String& WW8TabDesc::GetNumRuleName() const
3448 USHORT nCol = GetLogicalWWCol();
3449 if (nCol < aNumRuleNames.size())
3450 return aNumRuleNames[nCol];
3451 else
3452 return aEmptyStr;
3455 void WW8TabDesc::SetNumRuleName( const String& rName )
3457 USHORT nCol = GetLogicalWWCol();
3458 for (USHORT nSize = static_cast< USHORT >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3459 aNumRuleNames.push_back(aEmptyStr);
3460 aNumRuleNames[nCol] = rName;
3463 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp)
3465 // Entering a table so make sure the the FirstPara flag gets set
3466 bFirstPara = true;
3467 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3468 // Fussnote
3469 if (bReadNoTbl)
3470 return false;
3472 if (pTableDesc)
3473 maTableStack.push(pTableDesc);
3475 // --> OD 2005-01-27 #i33818# - determine absolute position object attributes,
3476 // if possible. It's needed for nested tables.
3477 WW8FlyPara* pTableWFlyPara( 0L );
3478 WW8SwFlyPara* pTableSFlyPara( 0L );
3479 // --> OD 2005-03-21 #i45301# - anchor nested table inside Writer fly frame
3480 // only at-character, if absolute position object attributes are available.
3481 // Thus, default anchor type is as-character anchored.
3482 RndStdIds eAnchor( FLY_AS_CHAR );
3483 // <--
3484 if ( nInTable )
3486 WW8_TablePos* pNestedTabPos( 0L );
3487 WW8_TablePos aNestedTabPos;
3488 WW8PLCFxSave1 aSave;
3489 pPlcxMan->GetPap()->Save( aSave );
3490 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
3491 WW8_CP nMyStartCp = nStartCp;
3492 if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) &&
3493 ParseTabPos( &aNestedTabPos, pPap ) )
3495 pNestedTabPos = &aNestedTabPos;
3497 pPlcxMan->GetPap()->Restore( aSave );
3498 if ( pNestedTabPos )
3500 ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos );
3501 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3502 if ( pTableWFlyPara )
3504 // --> OD 2007-07-03 #148498#
3505 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3506 // containing WW8 page top margin.
3507 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara,
3508 maSectionManager.GetWWPageTopMargin(),
3509 maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(),
3510 nIniFlyDx, nIniFlyDy);
3511 // <--
3512 // --> OD 2005-03-21 #i45301# - anchor nested table Writer fly
3513 // frame at-character
3514 eAnchor = FLY_AT_CHAR;
3515 // <--
3519 // <--
3521 pTableDesc = new WW8TabDesc( this, nStartCp );
3523 if( pTableDesc->Ok() )
3525 int nNewInTable = nInTable + 1;
3526 if (InEqualApo(nNewInTable))
3528 ASSERT(pSFlyPara->pFlyFmt,
3529 "how could we be in a local apo and have no apo");
3532 if ((eAnchor == FLY_AT_CHAR)
3533 && !maTableStack.empty() && !InEqualApo(nNewInTable) )
3535 pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint());
3536 SfxItemSet aItemSet(rDoc.GetAttrPool(),
3537 RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3538 // --> OD 2005-01-26 #i33818# - anchor the Writer fly frame for
3539 // the nested table at-character.
3540 // --> OD 2005-03-21 #i45301#
3541 SwFmtAnchor aAnchor( eAnchor );
3542 aAnchor.SetAnchor( pTableDesc->pParentPos );
3543 aItemSet.Put( aAnchor );
3544 pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor,
3545 pTableDesc->pParentPos, &aItemSet);
3546 ASSERT( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor,
3547 "Not the anchor type requested!" );
3548 // <--
3549 MoveInsideFly(pTableDesc->pFlyFmt);
3551 pTableDesc->CreateSwTable();
3552 if (pTableDesc->pFlyFmt)
3554 pTableDesc->SetSizePosition(pTableDesc->pFlyFmt);
3555 // --> OD 2005-01-26 #i33818# - Use absolute position object
3556 // attributes, if existing, and apply them to the created Writer fly
3557 // frame.
3558 if ( pTableWFlyPara && pTableSFlyPara )
3560 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3561 SwFmtAnchor aAnchor( FLY_AT_CHAR );
3562 aAnchor.SetAnchor( pTableDesc->pParentPos );
3563 aFlySet.Put( aAnchor );
3564 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet );
3566 else
3568 SwFmtHoriOrient aHori =
3569 pTableDesc->pTable->GetFrmFmt()->GetHoriOrient();
3570 pTableDesc->pFlyFmt->SetFmtAttr(aHori);
3571 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) );
3573 // <--
3574 // --> OD 2005-01-27 #i33818# - The nested table doesn't have to leave
3575 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3576 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( TRUE ) );
3577 // <--
3579 else
3580 pTableDesc->SetSizePosition(0);
3581 pTableDesc->UseSwTable();
3583 else
3584 PopTableDesc();
3586 // --> OD 2005-01-28 #i33818#
3587 delete pTableWFlyPara;
3588 delete pTableSFlyPara;
3589 // <--
3591 bool bSuccess = (0 != pTableDesc);
3592 if (bSuccess)
3594 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3595 static_cast<sal_Int32>(maTableStack.size())));
3597 return bSuccess;
3600 bool lcl_PamContainsFly(SwPaM & rPam)
3602 bool bResult = false;
3603 SwNodeRange aRg( rPam.Start()->nNode, rPam.End()->nNode );
3604 SwDoc * pDoc = rPam.GetDoc();
3606 sal_uInt16 n = 0;
3607 SwSpzFrmFmts * pSpzFmts = pDoc->GetSpzFrmFmts();
3608 sal_uInt16 nCount = pSpzFmts->Count();
3609 while (!bResult && n < nCount)
3611 SwFrmFmt* pFly = (*pSpzFmts)[n];
3612 const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
3614 switch (pAnchor->GetAnchorId())
3616 case FLY_AT_PARA:
3617 case FLY_AT_CHAR:
3619 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
3621 if (pAPos != NULL &&
3622 aRg.aStart <= pAPos->nNode &&
3623 pAPos->nNode <= aRg.aEnd)
3625 bResult = true;
3628 break;
3629 default:
3630 break;
3633 ++n;
3636 return bResult;
3639 void SwWW8ImplReader::TabCellEnd()
3641 if (nInTable && pTableDesc)
3643 pTableDesc->TableCellEnd();
3645 if (bReadTable
3646 && pWFlyPara == NULL
3647 && mpTableEndPaM.get() != NULL
3648 && (! SwPaM::Overlap(*pPaM, *mpTableEndPaM))
3649 && SwPaM::LessThan(*mpTableEndPaM, *pPaM)
3650 && mpTableEndPaM->GetPoint()->nNode.GetNode().IsTxtNode()
3651 && !lcl_PamContainsFly(*mpTableEndPaM)
3654 rDoc.DelFullPara(*mpTableEndPaM);
3658 bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3659 bReadTable = false;
3660 mpTableEndPaM.reset();
3663 void SwWW8ImplReader::Read_TabCellEnd( USHORT, const BYTE* pData, short nLen)
3665 if( ( nLen > 0 ) && ( *pData == 1 ) )
3666 bWasTabCellEnd = true;
3669 void SwWW8ImplReader::Read_TabRowEnd( USHORT, const BYTE* pData, short nLen ) // Sprm25
3671 if( ( nLen > 0 ) && ( *pData == 1 ) )
3672 bWasTabRowEnd = true;
3675 void SwWW8ImplReader::PopTableDesc()
3677 if (pTableDesc && pTableDesc->pFlyFmt)
3679 MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos);
3682 delete pTableDesc;
3683 if (maTableStack.empty())
3684 pTableDesc = 0;
3685 else
3687 pTableDesc = maTableStack.top();
3688 maTableStack.pop();
3692 void SwWW8ImplReader::StopTable()
3694 maTracer.LeaveEnvironment(sw::log::eTable);
3696 ASSERT(pTableDesc, "Panic, stop table with no table!");
3697 if (!pTableDesc)
3698 return;
3700 // We are leaving a table so make sure the next paragraph doesn't think
3701 // it's the first paragraph
3702 bFirstPara = false;
3704 pTableDesc->FinishSwTable();
3705 PopTableDesc();
3707 if (!maTableStack.empty())
3709 maTracer.EnterEnvironment(sw::log::eTable, rtl::OUString::valueOf(
3710 static_cast<sal_Int32>(maTableStack.size())));
3713 bReadTable = true;
3714 // --> OD 2009-04-16 #i101116#
3715 // Keep PaM on table end only for nested tables
3716 if ( nInTable > 1 )
3718 mpTableEndPaM.reset(new SwPaM(*pPaM));
3720 // <--
3723 // GetTableLeft() wird fuer absatzgebundene Grafikobjekte in Tabellen
3724 // gebraucht.
3725 // WW nimmt bei eingerueckten Tabellen den Absatzrand, der ohne Tabelle
3726 // gueltig waere, als Basis; SW benutzt den linken Tabellenrand.
3727 short SwWW8ImplReader::GetTableLeft()
3729 return (pTableDesc) ? pTableDesc->GetMinLeft() : 0;
3732 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3734 if( !pTableDesc )
3735 return false;
3737 const WW8_TCell* pCell = pTableDesc->GetAktWWCell();
3739 return !pTableDesc->IsValidCell( pTableDesc->GetAktCol() )
3740 || ( pCell
3741 && ( !pCell->bFirstMerged
3742 && ( pCell->bMerged
3743 || ( pCell->bVertMerge
3744 && !pCell->bVertRestart
3751 USHORT SwWW8ImplReader::StyleUsingLFO( USHORT nLFOIndex ) const
3753 USHORT nRes = USHRT_MAX;
3754 if( pCollA )
3756 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3757 if( pCollA[ nI ].bValid
3758 && (nLFOIndex == pCollA[ nI ].nLFOIndex) )
3759 nRes = nI;
3761 return nRes;
3764 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const
3766 SwFmt* pRet = 0;
3767 if( pCollA )
3769 for(USHORT nI = 0; nI < pStyles->GetCount(); nI++ )
3770 if( pCollA[ nI ].bValid
3771 && (rName.Equals( pCollA[ nI ].GetOrgWWName())) )
3773 pRet = pCollA[ nI ].pFmt;
3774 break;
3777 return pRet;
3780 //-----------------------------------------
3781 // class WW8RStyle
3782 //-----------------------------------------
3784 const BYTE* WW8RStyle::HasParaSprm( USHORT nId ) const
3786 if( !pParaSprms || !nSprmsLen )
3787 return 0;
3789 const BYTE* pSprms = pParaSprms;
3790 USHORT i, x;
3792 for( i=0; i < nSprmsLen; )
3794 USHORT nAktId = maSprmParser.GetSprmId(pSprms);
3795 // Sprm found ?
3796 if( nAktId == nId )
3797 return pSprms + maSprmParser.DistanceToData(nId);
3799 x = maSprmParser.GetSprmSize(nAktId, pSprms);
3800 i = i + x;
3801 pSprms += x;
3803 return 0; // Sprm not found
3806 void WW8RStyle::ImportSprms(BYTE *pSprms, short nLen, bool bPap)
3808 if (!nLen)
3809 return;
3811 if( bPap )
3813 pParaSprms = pSprms; // fuer HasParaSprms()
3814 nSprmsLen = nLen;
3817 while ( nLen > 0 )
3819 USHORT nL1 = pIo->ImportSprm(pSprms);
3820 nLen = nLen - nL1;
3821 pSprms += nL1;
3824 pParaSprms = 0;
3825 nSprmsLen = 0;
3828 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3830 if (!nLen)
3831 return;
3833 BYTE *pSprms = new BYTE[nLen];
3835 pStStrm->Seek(nPosFc);
3836 pStStrm->Read(pSprms, nLen);
3838 ImportSprms(pSprms, nLen, bPap);
3840 delete[] pSprms;
3843 static inline short WW8SkipOdd(SvStream* pSt )
3845 if ( pSt->Tell() & 0x1 )
3847 UINT8 c;
3848 pSt->Read( &c, 1 );
3849 return 1;
3851 return 0;
3854 static inline short WW8SkipEven(SvStream* pSt )
3856 if (!(pSt->Tell() & 0x1))
3858 UINT8 c;
3859 pSt->Read( &c, 1 );
3860 return 1;
3862 return 0;
3865 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3867 INT16 cbUPX;
3869 if( 0 < nLen ) // Empty ?
3871 if (bOdd)
3872 nLen = nLen - WW8SkipEven( pStStrm );
3873 else
3874 nLen = nLen - WW8SkipOdd( pStStrm );
3876 *pStStrm >> cbUPX;
3878 nLen-=2;
3880 if ( cbUPX > nLen )
3881 cbUPX = nLen; // !cbUPX auf nLen verkleinert!
3883 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3885 if( bPAP )
3887 UINT16 id;
3888 *pStStrm >> id;
3890 cbUPX-= 2;
3891 nLen-= 2;
3894 if( 0 < cbUPX )
3896 sal_Size nPos = pStStrm->Tell(); // falls etwas falsch interpretiert
3897 // wird, gehts danach wieder richtig
3898 ImportSprms( nPos, cbUPX, bPAP );
3900 if ( pStStrm->Tell() != nPos + cbUPX )
3901 pStStrm->Seek( nPos+cbUPX );
3903 nLen = nLen - cbUPX;
3907 return nLen;
3910 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3912 if( nLen <= 0 )
3913 return;
3914 if (bOdd)
3915 nLen = nLen - WW8SkipEven( pStStrm );
3916 else
3917 nLen = nLen - WW8SkipOdd( pStStrm );
3919 if( bPara ) // Grupx.Papx
3920 nLen = ImportUPX(nLen, true, bOdd);
3921 ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3924 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3925 : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()),
3926 pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0)
3928 pIo->nColls = cstd;
3929 pIo->pCollA = cstd ? new SwWW8StyInf[ cstd ] : NULL; // Style-UEbersetzung WW->SW
3932 void WW8RStyle::Set1StyleDefaults()
3934 if (!bCJKFontChanged) // Style no CJK Font? set the default
3935 pIo->SetNewFontAttr(ftcStandardChpCJKStsh, true, RES_CHRATR_CJK_FONT);
3937 // see i25247
3938 const WW8_FFN* pF = pIo->pFonts->GetFont(3);
3939 if (pF)
3941 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(pF->chs);
3942 if ((ftcStandardChpCTLStsh == 0) && (eEnc == RTL_TEXTENCODING_MS_1255))
3943 ftcStandardChpCTLStsh = 3;
3946 if (ftcStandardChpCJKStsh == 0)
3947 ftcStandardChpCJKStsh = 2;
3949 if (!bCTLFontChanged) // Style no CTL Font? set the default
3950 pIo->SetNewFontAttr(ftcStandardChpCTLStsh, true, RES_CHRATR_CTL_FONT);
3952 //#88976# western 2nd to make western charset conversion the default
3953 if (!bFontChanged) // Style has no Font? set the default,
3955 pIo->SetNewFontAttr(ftcStandardChpStsh, true, RES_CHRATR_FONT);
3956 /* removed by a patch from cmc for #i52786#
3957 if (pIo->bVer67)
3958 SetStyleCharSet(pIo->pCollA[pIo->nAktColl]);
3962 if( !pIo->bNoAttrImport )
3964 // Style has no text color set, winword default is auto
3965 if ( !bTxtColChanged )
3966 pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3968 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3969 if( !bFSizeChanged )
3971 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3972 pIo->pAktColl->SetFmtAttr(aAttr);
3973 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3974 pIo->pAktColl->SetFmtAttr(aAttr);
3977 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3978 if( !bFCTLSizeChanged )
3980 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3981 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3982 pIo->pAktColl->SetFmtAttr(aAttr);
3985 if( pIo->pWDop->fWidowControl && !bWidowsChanged ) // Widows ?
3987 pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3988 pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3993 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3995 SwFmt* pColl;
3996 bool bStyExist;
3997 if (rSI.bColl)
3999 // Para-Style
4000 sw::util::ParaStyleMapper::StyleResult aResult =
4001 pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
4002 pColl = aResult.first;
4003 bStyExist = aResult.second;
4005 else
4007 // Char-Style
4008 sw::util::CharStyleMapper::StyleResult aResult =
4009 pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
4010 pColl = aResult.first;
4011 bStyExist = aResult.second;
4014 bool bImport = !bStyExist || pIo->mbNewDoc; // Inhalte Importieren ?
4015 bool bOldNoImp = pIo->bNoAttrImport;
4016 rSI.bImportSkipped = !bImport;
4018 if( !bImport )
4019 pIo->bNoAttrImport = true;
4020 else
4022 if (bStyExist)
4024 // --> OD 2007-01-25 #i73790# - method renamed
4025 pColl->ResetAllFmtAttr();
4026 // <--
4028 pColl->SetAuto(false); // nach Empfehlung JP
4029 } // macht die UI aber anders
4030 pIo->pAktColl = pColl;
4031 rSI.pFmt = pColl; // UEbersetzung WW->SW merken
4032 rSI.bImportSkipped = !bImport;
4034 // Set Based on style
4035 USHORT j = rSI.nBase;
4036 if (j != nThisStyle && j < cstd )
4038 SwWW8StyInf* pj = &pIo->pCollA[j];
4039 if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl)
4041 rSI.pFmt->SetDerivedFrom( pj->pFmt ); // ok, Based on eintragen
4042 rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
4043 rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
4044 rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
4045 rSI.n81Flags = pj->n81Flags;
4046 rSI.n81BiDiFlags = pj->n81BiDiFlags;
4047 rSI.nOutlineLevel = pj->nOutlineLevel;
4048 rSI.bParaAutoBefore = pj->bParaAutoBefore;
4049 rSI.bParaAutoAfter = pj->bParaAutoAfter;
4051 if (pj->pWWFly)
4052 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly);
4055 else if( pIo->mbNewDoc && bStyExist )
4056 rSI.pFmt->SetDerivedFrom(0);
4058 rSI.nFollow = nNextStyle; // Follow merken
4060 pStyRule = 0; // falls noetig, neu anlegen
4061 bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
4062 bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
4063 pIo->SetNAktColl( nThisStyle );
4064 pIo->bStyNormal = nThisStyle == 0;
4065 return bOldNoImp;
4068 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
4070 // Alle moeglichen Attribut-Flags zuruecksetzen,
4071 // da es in Styles keine Attr-Enden gibt
4073 pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol
4074 = pIo->bSpec = pIo->bObj = pIo->bSymbol = false;
4075 pIo->nCharFmt = -1;
4077 // If Style basiert auf Nichts oder Basis ignoriert
4078 if ((rSI.nBase >= cstd || pIo->pCollA[rSI.nBase].bImportSkipped) && rSI.bColl)
4080 //! Char-Styles funktionieren aus
4081 // unerfindlichen Gruenden nicht
4082 // -> dann evtl. harte WW-Defaults
4083 // reinsetzen
4084 Set1StyleDefaults();
4087 pStyRule = 0; // zur Sicherheit
4088 pIo->bStyNormal = false;
4089 pIo->SetNAktColl( 0 );
4090 pIo->bNoAttrImport = bOldNoImp;
4091 // rasch nochmal die Listen-Merk-Felder zuruecksetzen,
4092 // fuer den Fall dass sie beim einlesen des Styles verwendet wurden
4093 pIo->nLFOPosition = USHRT_MAX;
4094 pIo->nListLevel = WW8ListManager::nMaxLevel;
4097 void WW8RStyle::Import1Style( USHORT nNr )
4099 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4101 if( rSI.bImported || !rSI.bValid )
4102 return;
4104 rSI.bImported = true; // jetzt schon Flag setzen
4105 // verhindert endlose Rekursion
4107 // gueltig und nicht NIL und noch nicht Importiert
4109 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4110 Import1Style( rSI.nBase );
4112 pStStrm->Seek( rSI.nFilePos );
4114 short nSkip, cbStd;
4115 String sName;
4117 WW8_STD* pStd = Read1Style( nSkip, &sName, &cbStd );// lies Style
4119 if (pStd)
4120 rSI.SetOrgWWIdent( sName, pStd->sti );
4122 // either no Name or unused Slot or unknown Style
4124 if ( !pStd || (0 == sName.Len()) || ((1 != pStd->sgc) && (2 != pStd->sgc)) )
4126 pStStrm->SeekRel( nSkip );
4127 return;
4130 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(pStd->sti), nNr, pStd->istdNext);
4132 // falls etwas falsch interpretiert wird, gehts danach wieder richtig
4133 long nPos = pStStrm->Tell();
4135 //Variable parts of the STD start at even byte offsets, but "inside
4136 //the STD", which I take to meaning even in relation to the starting
4137 //position of the STD, which matches findings in #89439#, generally it
4138 //doesn't matter as the STSHI starts off nearly always on an even
4139 //offset
4141 //Import of the Style Contents
4142 ImportGrupx(nSkip, pStd->sgc == 1, rSI.nFilePos & 1);
4144 PostStyle(rSI, bOldNoImp);
4146 pStStrm->Seek( nPos+nSkip );
4147 delete pStd;
4150 void WW8RStyle::RecursiveReg(USHORT nNr)
4152 SwWW8StyInf &rSI = pIo->pCollA[nNr];
4153 if( rSI.bImported || !rSI.bValid )
4154 return;
4156 rSI.bImported = true;
4158 if( rSI.nBase < cstd && !pIo->pCollA[rSI.nBase].bImported )
4159 RecursiveReg(rSI.nBase);
4161 pIo->RegisterNumFmtOnStyle(nNr);
4166 After all styles are imported then we can recursively apply numbering
4167 styles to them, and change their tab stop settings if they turned out
4168 to have special first line indentation.
4170 void WW8RStyle::PostProcessStyles()
4172 USHORT i;
4174 Clear all imported flags so that we can recursively apply numbering
4175 formats and use it to mark handled ones
4177 for (i=0; i < cstd; ++i)
4178 pIo->pCollA[i].bImported = false;
4181 Register the num formats and tabstop changes on the styles recursively.
4185 In the same loop apply the tabstop changes required because we need to
4186 change their location if theres a special indentation for the first line,
4187 By avoiding making use of each styles margins during reading of their
4188 tabstops we don't get problems with doubly adjusting tabstops that
4189 are inheritied.
4191 for (i=0; i < cstd; ++i)
4193 if (pIo->pCollA[i].bValid)
4195 RecursiveReg(i);
4200 void WW8RStyle::ScanStyles() // untersucht Style-Abhaengigkeiten
4201 { // und ermittelt die Filepos fuer jeden Style
4203 WW8_FC nStyleStart = rFib.fcStshf;
4204 pStStrm->Seek( nStyleStart );
4206 for (USHORT i = 0; i < cstd; ++i)
4208 short nSkip;
4209 SwWW8StyInf &rSI = pIo->pCollA[i];
4211 rSI.nFilePos = pStStrm->Tell(); // merke FilePos
4212 WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD
4213 rSI.bValid = (0 != pStd);
4214 if (rSI.bValid)
4216 rSI.nBase = pStd->istdBase; // merke Basis
4217 rSI.bColl = ( pStd->sgc == 1 ); // Para-Style
4219 else
4220 rSI = SwWW8StyInf();
4222 delete pStd;
4223 pStStrm->SeekRel( nSkip ); // ueberlese Namen und Sprms
4227 std::vector<BYTE> ChpxToSprms(const Word2CHPX &rChpx)
4229 std::vector<BYTE> aRet;
4231 aRet.push_back(60);
4232 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBold) );
4234 aRet.push_back(61);
4235 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalic) );
4237 aRet.push_back(62);
4238 aRet.push_back( static_cast< BYTE >(128 + rChpx.fStrike) );
4240 aRet.push_back(63);
4241 aRet.push_back( static_cast< BYTE >(128 + rChpx.fOutline) );
4243 aRet.push_back(65);
4244 aRet.push_back( static_cast< BYTE >(128 + rChpx.fSmallCaps) );
4246 aRet.push_back(66);
4247 aRet.push_back( static_cast< BYTE >(128 + rChpx.fCaps) );
4249 aRet.push_back(67);
4250 aRet.push_back( static_cast< BYTE >(128 + rChpx.fVanish) );
4252 if (rChpx.fsFtc)
4254 aRet.push_back(68);
4255 SVBT16 a;
4256 ShortToSVBT16(rChpx.ftc, a);
4257 aRet.push_back(a[1]);
4258 aRet.push_back(a[0]);
4261 if (rChpx.fsKul)
4263 aRet.push_back(69);
4264 aRet.push_back(rChpx.kul);
4267 if (rChpx.fsLid)
4269 aRet.push_back(72);
4270 SVBT16 a;
4271 ShortToSVBT16(rChpx.lid, a);
4272 aRet.push_back(a[1]);
4273 aRet.push_back(a[0]);
4276 if (rChpx.fsIco)
4278 aRet.push_back(73);
4279 aRet.push_back(rChpx.ico);
4282 if (rChpx.fsHps)
4284 aRet.push_back(74);
4286 SVBT16 a;
4287 ShortToSVBT16(rChpx.hps, a);
4288 aRet.push_back(a[0]);
4289 // aRet.push_back(a[1]);
4292 if (rChpx.fsPos)
4294 aRet.push_back(76);
4295 aRet.push_back(rChpx.hpsPos);
4298 aRet.push_back(80);
4299 aRet.push_back( static_cast< BYTE >(128 + rChpx.fBoldBi) );
4301 aRet.push_back(81);
4302 aRet.push_back( static_cast< BYTE >(128 + rChpx.fItalicBi) );
4304 if (rChpx.fsFtcBi)
4306 aRet.push_back(82);
4307 SVBT16 a;
4308 ShortToSVBT16(rChpx.fsFtcBi, a);
4309 aRet.push_back(a[1]);
4310 aRet.push_back(a[0]);
4313 if (rChpx.fsLidBi)
4315 aRet.push_back(83);
4316 SVBT16 a;
4317 ShortToSVBT16(rChpx.lidBi, a);
4318 aRet.push_back(a[1]);
4319 aRet.push_back(a[0]);
4322 if (rChpx.fsIcoBi)
4324 aRet.push_back(84);
4325 aRet.push_back(rChpx.icoBi);
4328 if (rChpx.fsHpsBi)
4330 aRet.push_back(85);
4331 SVBT16 a;
4332 ShortToSVBT16(rChpx.hpsBi, a);
4333 aRet.push_back(a[1]);
4334 aRet.push_back(a[0]);
4337 return aRet;
4340 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4342 Word2CHPX aChpx;
4344 if (!nSize)
4345 return aChpx;
4347 rSt.Seek(nOffset);
4349 sal_uInt8 nCount=0;
4351 while (1)
4353 sal_uInt8 nFlags8;
4354 rSt >> nFlags8;
4355 nCount++;
4357 aChpx.fBold = nFlags8 & 0x01;
4358 aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4359 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4360 aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4361 aChpx.fFldVanish = (nFlags8 & 0x10) >> 4;
4362 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4363 aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4364 aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4366 if (nCount >= nSize) break;
4367 rSt >> nFlags8;
4368 nCount++;
4370 aChpx.fRMark = nFlags8 & 0x01;
4371 aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4372 aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4373 aChpx.fObj = (nFlags8 & 0x08) >> 3;
4374 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4375 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4376 aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4377 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4379 if (nCount >= nSize) break;
4380 rSt >> nFlags8;
4381 nCount++;
4383 aChpx.fsIco = nFlags8 & 0x01;
4384 aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4385 aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4386 aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4387 aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4388 aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4389 aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4390 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4392 if (nCount >= nSize) break;
4393 rSt >> nFlags8;
4394 nCount++;
4396 aChpx.fsFtcBi = nFlags8 & 0x01;
4397 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4398 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4400 if (nCount >= nSize) break;
4401 rSt >> aChpx.ftc;
4402 nCount+=2;
4404 if (nCount >= nSize) break;
4405 rSt >> aChpx.hps;
4406 nCount+=2;
4408 if (nCount >= nSize) break;
4409 rSt >> nFlags8;
4410 nCount++;
4412 aChpx.qpsSpace = nFlags8 & 0x3F;
4413 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4414 aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4416 if (nCount >= nSize) break;
4417 rSt >> nFlags8;
4418 nCount++;
4420 aChpx.ico = nFlags8 & 0x1F;
4421 aChpx.kul = (nFlags8 & 0xE0) >> 5;
4423 if (nCount >= nSize) break;
4424 rSt >> aChpx.hpsPos;
4425 nCount++;
4427 if (nCount >= nSize) break;
4428 rSt >> aChpx.icoBi;
4429 nCount++;
4431 if (nCount >= nSize) break;
4432 rSt >> aChpx.lid;
4433 nCount+=2;
4435 if (nCount >= nSize) break;
4436 rSt >> aChpx.ftcBi;
4437 nCount+=2;
4439 if (nCount >= nSize) break;
4440 rSt >> aChpx.hpsBi;
4441 nCount+=2;
4443 if (nCount >= nSize) break;
4444 rSt >> aChpx.lidBi;
4445 nCount+=2;
4447 if (nCount >= nSize) break;
4448 rSt >> aChpx.fcPic;
4449 nCount+=4;
4451 break;
4454 rSt.SeekRel(nSize-nCount);
4455 return aChpx;
4458 namespace
4460 struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4463 void WW8RStyle::ImportOldFormatStyles()
4465 for (sal_uInt16 i=0; i < cstd; ++i)
4467 pIo->pCollA[i].bColl = true;
4468 //every chain must end eventually at the null style (style code 222)
4469 pIo->pCollA[i].nBase = 222;
4472 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4473 pIo->pWwFib->chseTables);
4475 sal_uInt16 cstcStd;
4476 rSt >> cstcStd;
4478 sal_uInt16 cbName;
4479 rSt >> cbName;
4480 sal_uInt16 nByteCount = 2;
4481 USHORT stcp=0;
4482 while (nByteCount < cbName)
4484 sal_uInt8 nCount;
4485 rSt >> nCount;
4486 nByteCount++;
4488 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4489 SwWW8StyInf &rSI = pIo->pCollA[stc];
4490 if (nCount != 0xFF) // undefined style
4492 String sName;
4493 if (nCount == 0) // inbuilt style
4495 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4496 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4497 sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4498 else
4499 sName = String(CREATE_CONST_ASC("Unknown"));
4501 else // user style
4503 ByteString aTmp;
4504 nByteCount = static_cast< sal_uInt16 >(nByteCount + SafeReadString(aTmp, nCount, rSt));
4505 sName = String(aTmp, eStructChrSet);
4507 rSI.SetOrgWWIdent(sName, stc);
4508 rSI.bImported = true;
4510 else
4512 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4513 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4515 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4516 rSI.SetOrgWWIdent(sName, stc);
4519 stcp++;
4522 USHORT nStyles=stcp;
4524 std::vector<pxoffset> aCHPXOffsets(stcp);
4525 sal_uInt16 cbChpx;
4526 rSt >> cbChpx;
4527 nByteCount = 2;
4528 stcp=0;
4529 std::vector< std::vector<BYTE> > aConvertedChpx;
4530 while (nByteCount < cbChpx)
4532 sal_uInt8 cb;
4533 rSt >> cb;
4534 nByteCount++;
4536 aCHPXOffsets[stcp].mnSize = 0;
4538 if (cb != 0xFF)
4540 sal_uInt8 nRemainder = cb;
4542 aCHPXOffsets[stcp].mnOffset = rSt.Tell();
4543 aCHPXOffsets[stcp].mnSize = nRemainder;
4545 Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset,
4546 aCHPXOffsets[stcp].mnSize);
4547 aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4549 nByteCount += nRemainder;
4551 else
4552 aConvertedChpx.push_back( std::vector<BYTE>() );
4554 stcp++;
4555 if (stcp == nStyles)
4557 rSt.SeekRel(cbChpx-nByteCount);
4558 nByteCount += cbChpx-nByteCount;
4562 std::vector<pxoffset> aPAPXOffsets(stcp);
4563 sal_uInt16 cbPapx;
4564 rSt >> cbPapx;
4565 nByteCount = 2;
4566 stcp=0;
4567 while (nByteCount < cbPapx)
4569 sal_uInt8 cb;
4570 rSt >> cb;
4571 nByteCount++;
4573 aPAPXOffsets[stcp].mnSize = 0;
4575 if (cb != 0xFF)
4577 sal_uInt8 stc2;
4578 rSt >> stc2;
4579 rSt.SeekRel(6);
4580 nByteCount+=7;
4581 sal_uInt8 nRemainder = cb-7;
4583 aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4584 aPAPXOffsets[stcp].mnSize = nRemainder;
4586 rSt.SeekRel(nRemainder);
4587 nByteCount += nRemainder;
4590 stcp++;
4592 if (stcp == nStyles)
4594 rSt.SeekRel(cbPapx-nByteCount);
4595 nByteCount += cbPapx-nByteCount;
4599 sal_uInt16 iMac;
4600 rSt >> iMac;
4602 if (iMac > nStyles) iMac = nStyles;
4604 for (stcp = 0; stcp < iMac; ++stcp)
4606 sal_uInt8 stcNext, stcBase;
4607 rSt >> stcNext;
4608 rSt >> stcBase;
4610 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4613 #i64557# style based on itself
4614 every chain must end eventually at the null style (style code 222)
4616 if (stc == stcBase)
4617 stcBase = 222;
4619 SwWW8StyInf &rSI = pIo->pCollA[stc];
4620 rSI.nBase = stcBase;
4622 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4624 if (eSti == ww::stiNil)
4625 continue;
4627 rSI.bValid = true;
4629 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4630 pIo->pCollA[stc].bColl = false;
4632 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4634 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4635 true);
4637 if (aConvertedChpx[stcp].size() > 0)
4638 ImportSprms(&(aConvertedChpx[stcp][0]),
4639 static_cast< short >(aConvertedChpx[stcp].size()),
4640 false);
4642 PostStyle(rSI, bOldNoImp);
4646 void WW8RStyle::ImportNewFormatStyles()
4648 ScanStyles(); // Scanne Based On
4650 for (USHORT i = 0; i < cstd; ++i) // import Styles
4651 if (pIo->pCollA[i].bValid)
4652 Import1Style( i );
4655 void WW8RStyle::ImportStyles()
4657 if (ww::eWW2 == pIo->pWwFib->GetFIBVersion())
4658 ImportOldFormatStyles();
4659 else
4660 ImportNewFormatStyles();
4663 void WW8RStyle::Import()
4665 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4666 pIo->pStandardFmtColl =
4667 pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
4669 if( pIo->nIniFlags & WW8FL_NO_STYLES )
4670 return;
4672 ImportStyles();
4674 for (USHORT i = 0; i < cstd; ++i)
4676 // Follow chain
4677 SwWW8StyInf* pi = &pIo->pCollA[i];
4678 USHORT j = pi->nFollow;
4679 if( j < cstd )
4681 SwWW8StyInf* pj = &pIo->pCollA[j];
4682 if ( j != i // sinnvoller Index ?
4683 && pi->pFmt // Format ok ?
4684 && pj->pFmt // Derived-Format ok ?
4685 && pi->bColl // geht nur bei Absatz-Vorlagen (WW)
4686 && pj->bColl ){ // beides gleicher Typ ?
4687 ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl(
4688 *(SwTxtFmtColl*)pj->pFmt ); // ok, eintragen
4692 // Die Sonderbehandlung zur Setzen der
4693 // Default-Zeichenvorlage "Absatz-Standardschriftart" ( Style-ID 65 ) fehlt
4694 // Sie ist aber defaultmaessig leer ( WW6 dt und US ) und von der
4695 // WW-UI nicht zu veraendern, so dass das nicht stoert.
4696 // Der Mechanismus waere folgender:
4697 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4699 // fuer z.B. Tabellen wird ein immer gueltiger Std-Style gebraucht
4701 if( pIo->StyleExists(0) && pIo->pCollA[0].pFmt && pIo->pCollA[0].bColl && pIo->pCollA[0].bValid )
4702 pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->pCollA[0].pFmt;
4703 else
4704 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4707 // set Hyphenation flag on BASIC para-style
4708 if (pIo->mbNewDoc && pIo->pStandardFmtColl)
4710 if (pIo->pWDop->fAutoHyphen
4711 && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(
4712 RES_PARATR_HYPHENZONE, false) )
4714 SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4715 aAttr.GetMinLead() = 2;
4716 aAttr.GetMinTrail() = 2;
4717 aAttr.GetMaxHyphens() = 0;
4719 pIo->pStandardFmtColl->SetFmtAttr( aAttr );
4723 Word defaults to ltr not from environment like writer. Regardless of
4724 the page/sections rtl setting the standard style lack of rtl still
4725 means ltr
4727 if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR,
4728 false))
4730 pIo->pStandardFmtColl->SetFmtAttr(
4731 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4735 // wir sind jetzt nicht mehr beim Style einlesen:
4736 pIo->pAktColl = 0;
4739 CharSet SwWW8StyInf::GetCharSet() const
4741 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4742 return eRTLFontSrcCharSet;
4743 return eLTRFontSrcCharSet;
4746 CharSet SwWW8StyInf::GetCJKCharSet() const
4748 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4749 return eRTLFontSrcCharSet;
4750 return eCJKFontSrcCharSet;
4753 /* vi:set tabstop=4 shiftwidth=4 expandtab: */