bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / ww8par2.cxx
blob01baf330889efab39af3a0ca4ca49233224b5cf7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <boost/scoped_ptr.hpp>
21 #include <comphelper/string.hxx>
22 #include <tools/solar.h>
23 #include <vcl/vclenum.hxx>
24 #include <vcl/font.hxx>
25 #include <hintids.hxx>
26 #include <editeng/colritem.hxx>
27 #include <editeng/orphitem.hxx>
28 #include <editeng/widwitem.hxx>
29 #include <editeng/brushitem.hxx>
30 #include <editeng/boxitem.hxx>
31 #include <editeng/lrspitem.hxx>
32 #include <editeng/fhgtitem.hxx>
33 #include <editeng/hyphenzoneitem.hxx>
34 #include <editeng/frmdiritem.hxx>
35 #include <editeng/langitem.hxx>
36 #include <editeng/charrotateitem.hxx>
37 #include <editeng/pgrditem.hxx>
38 #include <msfilter.hxx>
39 #include <pam.hxx> // fuer SwPam
40 #include <doc.hxx>
41 #include <docary.hxx>
42 #include <ndtxt.hxx> // class SwTxtNode
43 #include <paratr.hxx> // SwNumRuleItem
44 #include <poolfmt.hxx> // RES_POOLCOLL_STANDARD
45 #include <swtable.hxx> // class SwTableLines, ...
46 #include <tblsel.hxx> // class _SwSelBox
47 #include <mdiexp.hxx>
48 #include <fmtpdsc.hxx>
49 #include <txtftn.hxx>
50 #include <frmfmt.hxx>
51 #include <ftnidx.hxx>
52 #include <fmtftn.hxx>
53 #include <charfmt.hxx>
54 #include <SwStyleNameMapper.hxx>
55 #include <fltshell.hxx> // for the attribute stack
56 #include <fmtanchr.hxx>
57 #include <fmtrowsplt.hxx>
58 #include <fmtfollowtextflow.hxx> // #i33818#
59 #include <numrule.hxx>
60 #include "../inc/wwstyles.hxx"
61 #include "writerhelper.hxx"
62 #include "ww8struc.hxx" // struct TC
63 #include "ww8par.hxx"
64 #include "ww8par2.hxx"
66 #include <frmatr.hxx>
68 #include <iostream>
70 using namespace ::com::sun::star;
73 class WW8SelBoxInfo
74 : public std::vector<SwTableBox*>
76 private:
77 WW8SelBoxInfo(const WW8SelBoxInfo&);
78 WW8SelBoxInfo& operator=(const WW8SelBoxInfo&);
79 public:
80 short nGroupXStart;
81 short nGroupWidth;
82 bool bGroupLocked;
84 WW8SelBoxInfo(short nXCenter, short nWidth)
85 : nGroupXStart( nXCenter ), nGroupWidth( nWidth ), bGroupLocked(false)
89 typedef boost::ptr_vector<WW8SelBoxInfo> WW8MergeGroups;
91 WW8TabBandDesc::WW8TabBandDesc()
93 memset(this, 0, sizeof(*this));
94 for (size_t i = 0; i < sizeof(maDirections)/sizeof(sal_uInt16); ++i)
95 maDirections[i] = 4;
98 WW8TabBandDesc::~WW8TabBandDesc()
100 delete[] pTCs;
101 delete[] pSHDs;
102 delete[] pNewSHDs;
105 class WW8TabDesc
107 std::vector<String> aNumRuleNames;
108 sw::util::RedlineStack *mpOldRedlineStack;
110 SwWW8ImplReader* pIo;
112 WW8TabBandDesc* pFirstBand;
113 WW8TabBandDesc* pActBand;
115 SwPosition* pTmpPos;
117 SwTableNode* pTblNd; // table node
118 const SwTableLines* pTabLines; // row array of node
119 SwTableLine* pTabLine; // current row
120 SwTableBoxes* pTabBoxes; // boxes array in current row
121 SwTableBox* pTabBox; // current cell
123 WW8MergeGroups aMergeGroups; // list of all cells to be merged
125 WW8_TCell* pAktWWCell;
127 short nRows;
128 short nDefaultSwCols;
129 short nBands;
130 short nMinLeft;
131 short nConvertedLeft;
132 short nMaxRight;
133 short nSwWidth;
134 short nPreferredWidth;
135 short nOrgDxaLeft;
137 bool bOk;
138 bool bClaimLineFmt;
139 sal_Int16 eOri;
140 bool bIsBiDi;
141 // 2. common admin info
142 short nAktRow;
143 short nAktBandRow; // SW: row of current band
144 // 3. admin info for writer
145 short nAktCol;
147 sal_uInt16 nRowsToRepeat;
149 // 4. methods
151 sal_uInt16 GetLogicalWWCol() const;
152 void SetTabBorders( SwTableBox* pBox, short nIdx );
153 void SetTabShades( SwTableBox* pBox, short nWwIdx );
154 void SetTabVertAlign( SwTableBox* pBox, short nWwIdx );
155 void SetTabDirection( SwTableBox* pBox, short nWwIdx );
156 void CalcDefaults();
157 bool SetPamInCell(short nWwCol, bool bPam);
158 void InsertCells( short nIns );
159 void AdjustNewBand();
161 WW8SelBoxInfo* FindMergeGroup(short nX1, short nWidth, bool bExact);
163 // single box - maybe used in a merge group
164 // (the merge groups are processed later at once)
165 SwTableBox* UpdateTableMergeGroup(WW8_TCell& rCell,
166 WW8SelBoxInfo* pActGroup, SwTableBox* pActBox, sal_uInt16 nCol );
167 void StartMiserableHackForUnsupportedDirection(short nWwCol);
168 void EndMiserableHackForUnsupportedDirection(short nWwCol);
169 //No copying
170 WW8TabDesc(const WW8TabDesc&);
171 WW8TabDesc &operator=(const WW8TabDesc&);
172 public:
173 const SwTable* pTable; // table
174 SwPosition* pParentPos;
175 SwFlyFrmFmt* pFlyFmt;
176 SfxItemSet aItemSet;
177 bool IsValidCell(short nCol) const;
178 bool InFirstParaInCell() const;
180 WW8TabDesc( SwWW8ImplReader* pIoClass, WW8_CP nStartCp );
181 bool Ok() const { return bOk; }
182 void CreateSwTable();
183 void UseSwTable();
184 void SetSizePosition(SwFrmFmt* pFrmFmt);
185 void TableCellEnd();
186 void MoveOutsideTable();
187 void ParkPaM();
188 void FinishSwTable();
189 void MergeCells();
190 short GetMinLeft() const { return nConvertedLeft; }
191 ~WW8TabDesc();
192 SwPosition *GetPos() { return pTmpPos; }
194 const WW8_TCell* GetAktWWCell() const { return pAktWWCell; }
195 short GetAktCol() const { return nAktCol; }
196 // find name of numrule valid for current WW-COL
197 const String& GetNumRuleName() const;
198 void SetNumRuleName( const String& rName );
200 sw::util::RedlineStack* getOldRedlineStack(){ return mpOldRedlineStack; }
203 void sw::util::RedlineStack::close( const SwPosition& rPos,
204 RedlineType_t eType, WW8TabDesc* pTabDesc )
206 // If the redline type is not found in the redline stack, we have to check if there has been
207 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
208 if( !close( rPos, eType ) )
210 if( pTabDesc && pTabDesc->getOldRedlineStack() )
212 bool const bResult =
213 pTabDesc->getOldRedlineStack()->close(rPos, eType);
214 OSL_ENSURE( bResult, "close without open!");
215 (void) bResult; // unused in non-debug
221 void wwSectionManager::SetCurrentSectionHasFootnote()
223 OSL_ENSURE(!maSegments.empty(),
224 "should not be possible, must be at least one segment");
225 if (!maSegments.empty())
226 maSegments.back().mbHasFootnote = true;
229 bool wwSectionManager::CurrentSectionIsVertical() const
231 OSL_ENSURE(!maSegments.empty(),
232 "should not be possible, must be at least one segment");
233 if (!maSegments.empty())
234 return maSegments.back().IsVertical();
235 return false;
238 bool wwSectionManager::CurrentSectionIsProtected() const
240 OSL_ENSURE(!maSegments.empty(),
241 "should not be possible, must be at least one segment");
242 if (!maSegments.empty())
243 return SectionIsProtected(maSegments.back());
244 return false;
247 sal_uInt32 wwSectionManager::GetPageLeft() const
249 return !maSegments.empty() ? maSegments.back().nPgLeft : 0;
252 sal_uInt32 wwSectionManager::GetPageRight() const
254 return !maSegments.empty() ? maSegments.back().nPgRight : 0;
257 sal_uInt32 wwSectionManager::GetPageWidth() const
259 return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
262 sal_uInt32 wwSectionManager::GetTextAreaWidth() const
264 return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
267 sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
269 return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
272 sal_uInt16 SwWW8ImplReader::End_Ftn()
275 Ignoring Footnote outside of the normal Text. People will put footnotes
276 into field results and field commands.
278 if (bIgnoreText ||
279 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
281 return 0;
284 OSL_ENSURE(!maFtnStack.empty(), "footnote end without start");
285 if (maFtnStack.empty())
286 return 0;
288 bool bFtEdOk = false;
289 const FtnDescriptor &rDesc = maFtnStack.back();
291 //Get the footnote character and remove it from the txtnode. We'll
292 //replace it with the footnote
293 SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode();
294 xub_StrLen nPos = pPaM->GetPoint()->nContent.GetIndex();
296 String sChar;
297 SwTxtAttr* pFN = 0;
298 //There should have been a footnote char, we will replace this.
299 if (pTxt && nPos)
301 sChar.Append(pTxt->GetTxt()[--nPos]);
302 pPaM->SetMark();
303 pPaM->GetMark()->nContent--;
304 rDoc.DeleteRange( *pPaM );
305 pPaM->DeleteMark();
306 SwFmtFtn aFtn(rDesc.meType == MAN_EDN);
307 pFN = pTxt->InsertItem(aFtn, nPos, nPos);
309 OSL_ENSURE(pFN, "Probleme beim Anlegen des Fussnoten-Textes");
310 if (pFN)
313 SwPosition aTmpPos( *pPaM->GetPoint() ); // remember old cursor position
314 WW8PLCFxSaveAll aSave;
315 pPlcxMan->SaveAllPLCFx( aSave );
316 WW8PLCFMan* pOldPlcxMan = pPlcxMan;
318 const SwNodeIndex* pSttIdx = ((SwTxtFtn*)pFN)->GetStartNode();
319 OSL_ENSURE(pSttIdx, "Probleme beim Anlegen des Fussnoten-Textes");
321 ((SwTxtFtn*)pFN)->SetSeqNo( rDoc.GetFtnIdxs().size() );
323 bool bOld = bFtnEdn;
324 bFtnEdn = true;
326 // read content of Ft-/End-Note
327 Read_HdFtFtnText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
328 bFtEdOk = true;
329 bFtnEdn = bOld;
331 OSL_ENSURE(sChar.Len()==1 && ((rDesc.mbAutoNum == (sChar.GetChar(0) == 2))),
332 "footnote autonumbering must be 0x02, and everthing else must not be");
334 // If no automatic numbering use the following char from the main text
335 // as the footnote number
336 if (!rDesc.mbAutoNum)
337 ((SwTxtFtn*)pFN)->SetNumber(0, &sChar);
340 Delete the footnote char from the footnote if its at the beginning
341 as usual. Might not be if the user has already deleted it, e.g.
342 #i14737#
344 SwNodeIndex& rNIdx = pPaM->GetPoint()->nNode;
345 rNIdx = pSttIdx->GetIndex() + 1;
346 SwTxtNode* pTNd = rNIdx.GetNode().GetTxtNode();
347 if (pTNd && !pTNd->GetTxt().isEmpty() && sChar.Len())
349 if (pTNd->GetTxt()[0] == sChar.GetChar(0))
351 pPaM->GetPoint()->nContent.Assign( pTNd, 0 );
352 pPaM->SetMark();
353 // Strip out tabs we may have inserted on export #i24762#
354 if (pTNd->GetTxt()[1] == 0x09)
355 pPaM->GetMark()->nContent++;
356 pPaM->GetMark()->nContent++;
357 pReffingStck->Delete(*pPaM);
358 rDoc.DeleteRange( *pPaM );
359 pPaM->DeleteMark();
363 *pPaM->GetPoint() = aTmpPos; // restore Cursor
365 pPlcxMan = pOldPlcxMan; // Restore attributes
366 pPlcxMan->RestoreAllPLCFx( aSave );
369 if (bFtEdOk)
370 maSectionManager.SetCurrentSectionHasFootnote();
372 maFtnStack.pop_back();
373 return 0;
376 long SwWW8ImplReader::Read_Ftn(WW8PLCFManResult* pRes)
379 Ignoring Footnote outside of the normal Text. People will put footnotes
380 into field results and field commands.
382 if (bIgnoreText ||
383 pPaM->GetPoint()->nNode < rDoc.GetNodes().GetEndOfExtras().GetIndex())
385 return 0;
388 FtnDescriptor aDesc;
389 aDesc.mbAutoNum = true;
390 if (eEDN == pRes->nSprmId)
392 aDesc.meType = MAN_EDN;
393 if (pPlcxMan->GetEdn())
394 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetEdn()->GetData();
396 else
398 aDesc.meType = MAN_FTN;
399 if (pPlcxMan->GetFtn())
400 aDesc.mbAutoNum = 0 != *(short*)pPlcxMan->GetFtn()->GetData();
403 aDesc.mnStartCp = pRes->nCp2OrIdx;
404 aDesc.mnLen = pRes->nMemLen;
406 maFtnStack.push_back(aDesc);
408 return 0;
411 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP* pPap, WW8_CP &rStartCp,
412 int nLevel) const
414 WW8PLCFxDesc aRes;
415 aRes.pMemPos = 0;
416 aRes.nEndPos = rStartCp;
418 while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
420 if (pPap->Where() != WW8_CP_MAX)
422 const sal_uInt8* pB = pPap->HasSprm(TabRowSprm(nLevel));
423 if (pB && *pB == 1)
425 const sal_uInt8 *pLevel = 0;
426 if (0 != (pLevel = pPap->HasSprm(0x6649)))
428 if (nLevel + 1 == *pLevel)
429 return true;
431 else
433 OSL_ENSURE(!nLevel || pLevel, "sublevel without level sprm");
434 return true; // RowEnd found
439 aRes.nStartPos = aRes.nEndPos;
440 aRes.pMemPos = 0;
441 //Seek to our next block of properties
442 if (!(pPap->SeekPos(aRes.nStartPos)))
444 aRes.nEndPos = WW8_CP_MAX;
445 pPap->SetDirty(true);
447 pPap->GetSprms(&aRes);
448 pPap->SetDirty(false);
449 //Update our aRes to get the new starting point of the next properties
450 rStartCp = aRes.nEndPos;
453 return false;
456 ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
457 const WW8_TablePos *pTabPos)
459 const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : 0;
460 ApoTestResults aRet;
461 // Frame in Style Definition (word appears to ignore them if inside an
462 // text autoshape)
463 if (!bTxbxFlySection && nAktColl < vColl.size())
464 aRet.mpStyleApo = StyleExists(nAktColl) ? vColl[nAktColl].pWWFly : 0;
467 #i1140#
468 If I have a table and apply a style to one of its frames that should cause
469 a paragraph that its applied to it to only exist as a separate floating
470 frame, then the behavour depends on which cell that it has been applied
471 to. If its the first cell of a row then the whole table row jumps into the
472 new frame, if its not then then the paragraph attributes are applied
473 "except" for the floating frame stuff. i.e. its ignored. So if theres a
474 table, and we're not in the first cell then we ignore the fact that the
475 paragraph style wants to be in a different frame.
477 This sort of mindbending inconsistency is surely why frames are deprecated
478 in word 97 onwards and hidden away from the user
481 #i1532# & #i5379#
482 If we are already a table in a frame then we must grab the para properties
483 to see if we are still in that frame.
486 aRet.m_bHasSprm37 = pPlcxMan->HasParaSprm( bVer67 ? 37 : 0x2423 );
487 const sal_uInt8 *pSrpm29 = pPlcxMan->HasParaSprm( bVer67 ? 29 : 0x261B );
488 aRet.m_bHasSprm29 = pSrpm29 != NULL;
489 aRet.m_nSprm29 = pSrpm29 ? *pSrpm29 : 0;
491 // Is there some frame data here
492 bool bNowApo = aRet.HasFrame() || pTopLevelTable;
493 if (bNowApo)
495 if (WW8FlyPara *pTest = ConstructApo(aRet, pTabPos))
496 delete pTest;
497 else
498 bNowApo = false;
501 bool bTestAllowed = !bTxbxFlySection && !bTableRowEnd;
502 if (bTestAllowed)
504 //Test is allowed if there is no table.
505 //Otherwise only allowed if we are in the
506 //first paragraph of the first cell of a row.
507 //(And only if the row we are inside is at the
508 //same level as the previous row, think tables
509 //in tables)
510 if (nCellLevel == nInTable)
513 if (!nInTable)
514 bTestAllowed = true;
515 else
517 if (!pTableDesc)
519 OSL_ENSURE(pTableDesc, "What!");
520 bTestAllowed = false;
522 else
524 // #i39468#
525 // If current cell isn't valid, the test is allowed.
526 // The cell isn't valid, if e.g. there is a new row
527 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
528 bTestAllowed =
529 pTableDesc->GetAktCol() == 0 &&
530 ( !pTableDesc->IsValidCell( pTableDesc->GetAktCol() ) ||
531 pTableDesc->InFirstParaInCell() );
537 if (!bTestAllowed)
538 return aRet;
540 aRet.mbStartApo = bNowApo && !InAnyApo(); // APO-start
541 aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end
543 //If it happens that we are in a table, then if its not the first cell
544 //then any attributes that might otherwise cause the contents to jump
545 //into another frame don't matter, a table row sticks together as one
546 //unit no matter what else happens. So if we are not in a table at
547 //all, or if we are in the first cell then test that the last frame
548 //data is the same as the current one
549 if (bNowApo && InEqualApo(nCellLevel))
551 // two bordering eachother
552 if (!TestSameApo(aRet, pTabPos))
553 aRet.mbStopApo = aRet.mbStartApo = true;
556 return aRet;
558 //---------------------------------------------------------------------
559 // helper methods for outline, numbering and bullets
560 //---------------------------------------------------------------------
562 static void SetBaseAnlv(SwNumFmt &rNum, WW8_ANLV &rAV, sal_uInt8 nSwLevel )
564 static SvxExtNumType eNumA[8] = { SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
565 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N, SVX_NUM_ARABIC,
566 SVX_NUM_ARABIC, SVX_NUM_ARABIC };
568 static SvxAdjust eAdjA[4] = { SVX_ADJUST_LEFT,
569 SVX_ADJUST_RIGHT, SVX_ADJUST_LEFT, SVX_ADJUST_LEFT };
570 // in fact the following 2, but writer UI does not provide
571 // SVX_ADJUST_CENTER, SVX_ADJUST_BLOCKLINE };
573 rNum.SetNumberingType( static_cast< sal_Int16 >(( SVBT8ToByte( rAV.nfc ) < 8 ) ?
574 eNumA[SVBT8ToByte( rAV.nfc ) ] : SVX_NUM_NUMBER_NONE) );
575 if ((SVBT8ToByte(rAV.aBits1 ) & 0x4) >> 2)
576 rNum.SetIncludeUpperLevels(nSwLevel + 1);
577 rNum.SetStart( SVBT16ToShort( rAV.iStartAt ) );
578 rNum.SetNumAdjust( eAdjA[SVBT8ToByte( rAV.aBits1 ) & 0x3] );
580 rNum.SetCharTextDistance( SVBT16ToShort( rAV.dxaSpace ) );
581 sal_Int16 nIndent = std::abs((sal_Int16)SVBT16ToShort( rAV.dxaIndent ));
582 if( SVBT8ToByte( rAV.aBits1 ) & 0x08 ) //fHang
584 rNum.SetFirstLineOffset( -nIndent );
585 rNum.SetLSpace( nIndent );
586 rNum.SetAbsLSpace( nIndent );
588 else
589 rNum.SetCharTextDistance( nIndent ); // width of number is missing
591 if( SVBT8ToByte( rAV.nfc ) == 5 || SVBT8ToByte( rAV.nfc ) == 7 )
593 String sP( rNum.GetSuffix() );
594 sP.Insert( '.', 0 );
595 rNum.SetSuffix( sP ); // ordinal number
599 void SwWW8ImplReader::SetAnlvStrings(SwNumFmt &rNum, WW8_ANLV &rAV,
600 const sal_uInt8* pTxt, bool bOutline)
602 bool bInsert = false; // Default
603 CharSet eCharSet = eStructCharSet;
605 const WW8_FFN* pF = pFonts->GetFont(SVBT16ToShort(rAV.ftc)); // FontInfo
606 bool bListSymbol = pF && ( pF->chs == 2 ); // Symbol/WingDings/...
608 String sTxt;
609 if (bVer67)
611 sTxt = String( (sal_Char*)pTxt, SVBT8ToByte( rAV.cbTextBefore )
612 + SVBT8ToByte( rAV.cbTextAfter ), eCharSet );
614 else
616 for(xub_StrLen i = SVBT8ToByte(rAV.cbTextBefore);
617 i < SVBT8ToByte(rAV.cbTextAfter); ++i, pTxt += 2)
619 sTxt.Append(SVBT16ToShort(*(SVBT16*)pTxt));
623 if( bOutline )
624 { // outline
625 if( !rNum.GetIncludeUpperLevels() // there are <= 1 number to show
626 || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ) // or this level has none
628 // if self defined digits
629 bInsert = true; // then apply character
631 // replace by simple Bullet ?
632 if( bListSymbol )
634 // use cBulletChar for correct mapping on MAC
635 OUStringBuffer aBuf;
636 comphelper::string::padToLength(aBuf, SVBT8ToByte(rAV.cbTextBefore)
637 + SVBT8ToByte(rAV.cbTextAfter), cBulletChar);
638 sTxt = aBuf.makeStringAndClear();
642 else
643 { // numbering / bullets
644 bInsert = true;
645 if( bListSymbol )
647 FontFamily eFamily;
648 String aName;
649 FontPitch ePitch;
651 if( GetFontParams( SVBT16ToShort( rAV.ftc ), eFamily, aName,
652 ePitch, eCharSet ) ){
654 Font aFont;
655 aFont.SetName( aName );
656 aFont.SetFamily( eFamily );
658 aFont.SetCharSet( eCharSet );
659 rNum.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
661 rNum.SetBulletFont( &aFont );
663 // take only the very first character
664 if( rAV.cbTextBefore || rAV.cbTextAfter)
665 rNum.SetBulletChar( sTxt.GetChar( 0 ) );
666 else
667 rNum.SetBulletChar( 0x2190 );
671 if( bInsert )
673 if( rAV.cbTextBefore )
675 String sP( sTxt.Copy( 0, SVBT8ToByte( rAV.cbTextBefore ) ) );
676 rNum.SetPrefix( sP );
678 if( SVBT8ToByte( rAV.cbTextAfter ) )
680 String sP( rNum.GetSuffix() );
681 sP.Insert( sTxt.Copy( SVBT8ToByte( rAV.cbTextBefore ),
682 SVBT8ToByte( rAV.cbTextAfter ) ) );
683 rNum.SetSuffix( sP );
685 // The characters before and after multipe digits do not apply because
686 // those are handled different by the writer and the result is in most
687 // cases worse than without.
691 // SetAnld gets a WW-ANLD-Descriptor and a Level and modifies the NumRules
692 // which are provided by pNumR. This is used for everything beside
693 // outline inside the text.
694 void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD* pAD, sal_uInt8 nSwLevel,
695 bool bOutLine)
697 SwNumFmt aNF;
698 if (pAD)
699 { // there is a Anld-Sprm
700 bAktAND_fNumberAcross = 0 != SVBT8ToByte( pAD->fNumberAcross );
701 WW8_ANLV &rAV = pAD->eAnlv;
702 SetBaseAnlv(aNF, rAV, nSwLevel); // set the base format
703 SetAnlvStrings(aNF, rAV, pAD->rgchAnld, bOutLine ); // set the rest
705 pNumR->Set(nSwLevel, aNF);
708 //-------------------------------------------------------
709 // chapter numbering and bullets
710 //-------------------------------------------------------
711 // Chapter numbering happens in the style definition.
712 // Sprm 13 provides the level, Sprm 12 the content.
714 SwNumRule* SwWW8ImplReader::GetStyRule()
716 if( pStyles->pStyRule ) // Bullet-Style already present
717 return pStyles->pStyRule;
719 const String aBaseName(OUString("WW8StyleNum"));
720 const String aName( rDoc.GetUniqueNumRuleName( &aBaseName, false) );
722 // #i86652#
723 sal_uInt16 nRul = rDoc.MakeNumRule( aName, 0, false,
724 SvxNumberFormat::LABEL_ALIGNMENT );
725 pStyles->pStyRule = rDoc.GetNumRuleTbl()[nRul];
726 // Auto == false-> Nummerierungsvorlage
727 pStyles->pStyRule->SetAutoRule(false);
729 return pStyles->pStyRule;
732 // Sprm 13
733 void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16, const sal_uInt8* pData, short nLen )
735 nSwNumLevel = 0xff; // Default: invalid
737 if( nLen <= 0 )
738 return;
740 // StyleDef ?
741 if( pAktColl )
743 // only for SwTxtFmtColl, not CharFmt
744 // WW: 0 = no Numbering
745 SwWW8StyInf * pColl = GetStyle(nAktColl);
746 if (pColl != NULL && pColl->bColl && *pData)
748 // Range WW:1..9 -> SW:0..8 no bullets / numbering
750 if (*pData <= MAXLEVEL && *pData <= 9)
752 nSwNumLevel = *pData - 1;
753 if (!bNoAttrImport)
754 ((SwTxtFmtColl*)pAktColl)->AssignToListLevelOfOutlineStyle( nSwNumLevel ); //<-end,zhaojianwei
755 // For WW-NoNumbering also NO_NUMBERING could be used.
756 // ( For normal numberierung NO_NUM has to be used:
757 // NO_NUM : pauses numbering,
758 // NO_NUMBERING : no numbering at all )
761 else if( *pData == 10 || *pData == 11 )
763 // remember type, the rest happens at Sprm 12
764 pStyles->nWwNumLevel = *pData;
768 else
770 //Not StyleDef
771 if (!bAnl)
772 StartAnl(pData); // begin of outline / bullets
773 NextAnlLine(pData);
777 void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm 12
779 SwWW8StyInf * pStyInf = GetStyle(nAktColl);
780 if( !pAktColl || nLen <= 0 // only for Styledef
781 || (pStyInf && !pStyInf->bColl) // ignore CharFmt ->
782 || ( nIniFlags & WW8FL_NO_OUTLINE ) )
784 nSwNumLevel = 0xff;
785 return;
789 if( nSwNumLevel <= MAXLEVEL // Value range mapping WW:1..9 -> SW:0..8
790 && nSwNumLevel <= 9 ){ // No Bullets or Numbering
792 // If NumRuleItems were set, either directly or through inheritance, disable them now
793 pAktColl->SetFmtAttr( SwNumRuleItem() );
795 String aName(OUString("Outline"));
796 SwNumRule aNR( rDoc.GetUniqueNumRuleName( &aName ),
797 SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
798 OUTLINE_RULE );
799 aNR = *rDoc.GetOutlineNumRule();
801 SetAnld(&aNR, (WW8_ANLD*)pData, nSwNumLevel, true);
803 // Missing Levels need not be replenished
804 rDoc.SetOutlineNumRule( aNR );
805 }else if( pStyles->nWwNumLevel == 10 || pStyles->nWwNumLevel == 11 ){
806 SwNumRule* pNR = GetStyRule();
807 SetAnld(pNR, (WW8_ANLD*)pData, 0, false);
808 pAktColl->SetFmtAttr( SwNumRuleItem( pNR->GetName() ) );
810 pStyInf = GetStyle(nAktColl);
811 if (pStyInf != NULL)
812 pStyInf->bHasStyNumRule = true;
816 //-----------------------------------------
817 // Numbering / Bullets
818 //-----------------------------------------
820 // SetNumOlst() carries the Numrules for this cell to SwNumFmt.
821 // For this the info is fetched from OLST and not from ANLD ( see later )
822 // ( only for outline inside text; Bullets / numbering use ANLDs )
823 void SwWW8ImplReader::SetNumOlst(SwNumRule* pNumR, WW8_OLST* pO, sal_uInt8 nSwLevel)
825 SwNumFmt aNF;
826 WW8_ANLV &rAV = pO->rganlv[nSwLevel];
827 SetBaseAnlv(aNF, rAV, nSwLevel);
828 // ... and then the Strings
829 int nTxtOfs = 0;
830 sal_uInt8 i;
831 WW8_ANLV* pAV1; // search String-Positions
832 for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
834 nTxtOfs += SVBT8ToByte(pAV1->cbTextBefore)
835 + SVBT8ToByte(pAV1->cbTextAfter);
838 if (!bVer67)
839 nTxtOfs *= 2;
840 SetAnlvStrings(aNF, rAV, pO->rgch + nTxtOfs, true); // and apply
841 pNumR->Set(nSwLevel, aNF);
844 // The OLST is at the beginning of each section that contains outlines.
845 // The ANLDs that are connected to each outline-line contain only nonsense,
846 // so the OLSTs are remembered for the section to have usable information
847 // when outline-paragraphs occur.
848 void SwWW8ImplReader::Read_OLST( sal_uInt16, const sal_uInt8* pData, short nLen )
850 delete pNumOlst;
851 if (nLen <= 0)
853 pNumOlst = 0;
854 return;
856 pNumOlst = new WW8_OLST;
857 if( nLen < sal::static_int_cast< sal_Int32 >(sizeof( WW8_OLST )) ) // fill if to short
858 memset( pNumOlst, 0, sizeof( *pNumOlst ) );
859 *pNumOlst = *(WW8_OLST*)pData;
862 WW8LvlType GetNumType(sal_uInt8 nWwLevelNo)
864 WW8LvlType nRet = WW8_None;
865 if( nWwLevelNo == 12 )
866 nRet = WW8_Pause;
867 else if( nWwLevelNo == 10 )
868 nRet = WW8_Numbering;
869 else if( nWwLevelNo == 11 )
870 nRet = WW8_Sequence;
871 else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
872 nRet = WW8_Outline;
873 return nRet;
876 SwNumRule *ANLDRuleMap::GetNumRule(sal_uInt8 nNumType)
878 return (WW8_Numbering == nNumType ? mpNumberingNumRule : mpOutlineNumRule);
881 void ANLDRuleMap::SetNumRule(SwNumRule *pRule, sal_uInt8 nNumType)
883 if (WW8_Numbering == nNumType)
884 mpNumberingNumRule = pRule;
885 else
886 mpOutlineNumRule = pRule;
890 // StartAnl is called at the beginning of a row area that contains
891 // outline / numbering / bullets
892 void SwWW8ImplReader::StartAnl(const sal_uInt8* pSprm13)
894 bAktAND_fNumberAcross = false;
896 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType(*pSprm13));
897 if (nT == WW8_Pause || nT == WW8_None)
898 return;
900 nWwNumType = nT;
901 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
903 // check for COL numbering:
904 const sal_uInt8* pS12 = 0;// sprmAnld
905 String sNumRule;
907 if (pTableDesc)
909 sNumRule = pTableDesc->GetNumRuleName();
910 if (sNumRule.Len())
912 pNumRule = rDoc.FindNumRulePtr(sNumRule);
913 if (!pNumRule)
914 sNumRule.Erase();
915 else
917 // this is ROW numbering ?
918 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
919 if (pS12 && 0 != SVBT8ToByte(((WW8_ANLD*)pS12)->fNumberAcross))
920 sNumRule.Erase();
925 SwWW8StyInf * pStyInf = GetStyle(nAktColl);
926 if (!sNumRule.Len() && pStyInf != NULL && pStyInf->bHasStyNumRule)
928 sNumRule = pStyInf->pFmt->GetNumRule().GetValue();
929 pNumRule = rDoc.FindNumRulePtr(sNumRule);
930 if (!pNumRule)
931 sNumRule.Erase();
934 if (!sNumRule.Len())
936 if (!pNumRule)
938 // #i86652#
939 pNumRule = rDoc.GetNumRuleTbl()[
940 rDoc.MakeNumRule( sNumRule, 0, false,
941 SvxNumberFormat::LABEL_ALIGNMENT ) ];
943 if (pTableDesc)
945 if (!pS12)
946 pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E); // sprmAnld
947 if (!pS12 || !SVBT8ToByte( ((WW8_ANLD*)pS12)->fNumberAcross))
948 pTableDesc->SetNumRuleName(pNumRule->GetName());
952 bAnl = true;
954 // set NumRules via stack
955 pCtrlStck->NewAttr(*pPaM->GetPoint(),
956 SfxStringItem(RES_FLTR_NUMRULE, pNumRule->GetName()));
958 maANLDRules.SetNumRule(pNumRule, nWwNumType);
961 // NextAnlLine() is called once for every row of a
962 // outline / numbering / bullet
963 void SwWW8ImplReader::NextAnlLine(const sal_uInt8* pSprm13)
965 if (!bAnl)
966 return;
968 SwNumRule *pNumRule = maANLDRules.GetNumRule(nWwNumType);
970 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
971 // sdw3
973 // WW:10 = numberierung -> SW:0 & WW:11 = bullets -> SW:0
974 if (*pSprm13 == 10 || *pSprm13 == 11)
976 nSwNumLevel = 0;
977 if (!pNumRule->GetNumFmt(nSwNumLevel))
979 // not defined yet
980 // sprmAnld o. 0
981 const sal_uInt8* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
982 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
985 else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // range WW:1..9 -> SW:0..8
987 nSwNumLevel = *pSprm13 - 1; // outline
988 // undefined
989 if (!pNumRule->GetNumFmt(nSwNumLevel))
991 if (pNumOlst) // there was a OLST
993 //Assure upper levels are set, #i9556#
994 for (sal_uInt8 nI = 0; nI < nSwNumLevel; ++nI)
996 if (!pNumRule->GetNumFmt(nI))
997 SetNumOlst(pNumRule, pNumOlst, nI);
1000 SetNumOlst(pNumRule, pNumOlst , nSwNumLevel);
1002 else // no Olst -> use Anld
1004 // sprmAnld
1005 const sal_uInt8* pS12 = pPlcxMan->HasParaSprm(bVer67 ? 12 : 0xC63E);
1006 SetAnld(pNumRule, (WW8_ANLD*)pS12, nSwNumLevel, false);
1010 else
1011 nSwNumLevel = 0xff; // no number
1013 SwTxtNode* pNd = pPaM->GetNode()->GetTxtNode();
1014 if (nSwNumLevel < MAXLEVEL)
1015 pNd->SetAttrListLevel( nSwNumLevel );
1016 else
1018 pNd->SetAttrListLevel(0);
1019 pNd->SetCountedInList( false );
1023 void SwWW8ImplReader::StopAllAnl(bool bGoBack)
1025 //Of course we're not restarting, but we'll make use of our knowledge
1026 //of the implementation to do it.
1027 StopAnlToRestart(WW8_None, bGoBack);
1030 void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType, bool bGoBack)
1032 if (bGoBack)
1034 SwPosition aTmpPos(*pPaM->GetPoint());
1035 pPaM->Move(fnMoveBackward, fnGoCntnt);
1036 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1037 *pPaM->GetPoint() = aTmpPos;
1039 else
1040 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_NUMRULE);
1042 maANLDRules.mpNumberingNumRule = 0;
1044 #i18816#
1045 my take on this problem is that moving either way from an outline to a
1046 numbering doesn't halt the outline, while the numbering is always halted
1048 bool bNumberingNotStopOutline =
1049 (((nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1050 ((nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1051 if (!bNumberingNotStopOutline)
1052 maANLDRules.mpOutlineNumRule = 0;
1054 nSwNumLevel = 0xff;
1055 nWwNumType = WW8_None;
1056 bAnl = false;
1059 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc& rBand )
1061 *this = rBand;
1062 if( rBand.pTCs )
1064 pTCs = new WW8_TCell[nWwCols];
1065 memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1067 if( rBand.pSHDs )
1069 pSHDs = new WW8_SHD[nWwCols];
1070 memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1072 if( rBand.pNewSHDs )
1074 pNewSHDs = new sal_uInt32[nWwCols];
1075 memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(sal_uInt32));
1077 memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1080 // ReadDef reads the cell position and the borders of a band
1081 void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS)
1083 if (!bVer67)
1084 pS++;
1086 short nLen = (sal_Int16)SVBT16ToShort( pS - 2 ); // not beautiful
1088 sal_uInt8 nCols = *pS; // number of cells
1089 short nOldCols = nWwCols;
1091 if( nCols > MAX_COL )
1092 return;
1094 nWwCols = nCols;
1096 const sal_uInt8* pT = &pS[1];
1097 nLen --;
1098 int i;
1099 for(i=0; i<=nCols; i++, pT+=2 )
1100 nCenter[i] = (sal_Int16)SVBT16ToShort( pT ); // X-borders
1101 nLen -= 2 * ( nCols + 1 );
1102 if( nCols != nOldCols ) // different column count
1104 delete[] pTCs, pTCs = 0;
1105 delete[] pSHDs, pSHDs = 0;
1106 delete[] pNewSHDs, pNewSHDs = 0;
1109 short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // realy saved
1111 if (!pTCs && nCols)
1113 // create empty TCs
1114 pTCs = new WW8_TCell[nCols];
1115 setcelldefaults(pTCs,nCols);
1118 short nColsToRead = nFileCols;
1119 if (nColsToRead > nCols)
1120 nColsToRead = nCols;
1122 if( nColsToRead )
1124 // read TCs
1127 Attention: Beginning with Ver8 there is an extra ushort per TC
1128 added and the size of the border code is doubled.
1129 Because of this a simple copy (pTCs[i] = *pTc;)
1130 is not possible.
1132 Advantage: The work structure suits better.
1134 WW8_TCell* pAktTC = pTCs;
1135 if( bVer67 )
1137 WW8_TCellVer6* pTc = (WW8_TCellVer6*)pT;
1138 for(i=0; i<nColsToRead; i++, ++pAktTC,++pTc)
1140 if( i < nColsToRead )
1141 { // TC from file ?
1142 sal_uInt8 aBits1 = SVBT8ToByte( pTc->aBits1Ver6 );
1143 pAktTC->bFirstMerged = ( ( aBits1 & 0x01 ) != 0 );
1144 pAktTC->bMerged = ( ( aBits1 & 0x02 ) != 0 );
1145 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1146 pTc->rgbrcVer6[ WW8_TOP ].aBits1, sizeof( SVBT16 ) );
1147 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1148 pTc->rgbrcVer6[ WW8_LEFT ].aBits1, sizeof( SVBT16 ) );
1149 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1150 pTc->rgbrcVer6[ WW8_BOT ].aBits1, sizeof( SVBT16 ) );
1151 memcpy( pAktTC->rgbrc[ WW8_RIGHT ].aBits1,
1152 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1153 if( ( pAktTC->bMerged )
1154 && ( i > 0 ) )
1156 // Cell merged -> remember
1157 //bWWMergedVer6[i] = true;
1158 memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1,
1159 pTc->rgbrcVer6[ WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
1160 // apply right border to previous cell
1161 // bExist must not be set to false, because WW
1162 // does not count this cells in text boxes....
1167 else
1169 WW8_TCellVer8* pTc = (WW8_TCellVer8*)pT;
1170 for (int k = 0; k < nColsToRead; ++k, ++pAktTC, ++pTc )
1172 sal_uInt16 aBits1 = SVBT16ToShort( pTc->aBits1Ver8 );
1173 pAktTC->bFirstMerged = ( ( aBits1 & 0x0001 ) != 0 );
1174 pAktTC->bMerged = ( ( aBits1 & 0x0002 ) != 0 );
1175 pAktTC->bVertical = ( ( aBits1 & 0x0004 ) != 0 );
1176 pAktTC->bBackward = ( ( aBits1 & 0x0008 ) != 0 );
1177 pAktTC->bRotateFont = ( ( aBits1 & 0x0010 ) != 0 );
1178 pAktTC->bVertMerge = ( ( aBits1 & 0x0020 ) != 0 );
1179 pAktTC->bVertRestart = ( ( aBits1 & 0x0040 ) != 0 );
1180 pAktTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 );
1181 // note: in aBits1 there are 7 bits unused,
1182 // followed by another 16 unused bits
1184 // In Version 8 koennen we can copy all border codes at once!
1185 memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) );
1189 // #i25071 In '97 text direction appears to be only set using TC properties
1190 // not with sprmTTextFlow so we need to cycle through the maDirections and
1191 // double check any non-default directions
1192 for (int k = 0; k < nCols; ++k)
1194 if(maDirections[k] == 4)
1196 if(pTCs[k].bVertical)
1198 if(pTCs[k].bBackward)
1199 maDirections[k] = 3;
1200 else
1201 maDirections[k] = 1;
1210 void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC)
1212 if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
1214 sal_uInt8 nitcFirst= pParamsTSetBRC[0];// first col to be changed
1215 sal_uInt8 nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1
1216 sal_uInt8 nFlag = *(pParamsTSetBRC+2);
1218 if (nitcFirst >= nWwCols)
1219 return;
1221 if (nitcLim > nWwCols)
1222 nitcLim = nWwCols;
1224 bool bChangeRight = (nFlag & 0x08) ? true : false;
1225 bool bChangeBottom = (nFlag & 0x04) ? true : false;
1226 bool bChangeLeft = (nFlag & 0x02) ? true : false;
1227 bool bChangeTop = (nFlag & 0x01) ? true : false;
1229 WW8_TCell* pAktTC = pTCs + nitcFirst;
1230 if( bVer67 )
1232 WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3);
1234 for( int i = nitcFirst; i < nitcLim; ++i, ++pAktTC )
1236 if( bChangeTop )
1238 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1239 pBRC->aBits1,
1240 sizeof( SVBT16 ) );
1242 if( bChangeLeft )
1244 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1245 pBRC->aBits1,
1246 sizeof( SVBT16 ) );
1248 if( bChangeBottom )
1250 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1251 pBRC->aBits1,
1252 sizeof( SVBT16 ) );
1254 if( bChangeRight )
1256 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1257 pBRC->aBits1,
1258 sizeof( SVBT16 ) );
1262 else
1264 WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3);
1266 for( int i = nitcFirst; i < nitcLim; ++i, ++pAktTC )
1268 if( bChangeTop )
1270 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits1,
1271 pBRC->aBits1,
1272 sizeof( SVBT16 ) );
1273 memcpy( pAktTC->rgbrc[ WW8_TOP ].aBits2,
1274 pBRC->aBits2,
1275 sizeof( SVBT16 ) );
1277 if( bChangeLeft )
1279 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
1280 pBRC->aBits1,
1281 sizeof( SVBT16 ) );
1282 memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits2,
1283 pBRC->aBits2,
1284 sizeof( SVBT16 ) );
1286 if( bChangeBottom )
1288 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits1,
1289 pBRC->aBits1,
1290 sizeof( SVBT16 ) );
1291 memcpy( pAktTC->rgbrc[ WW8_BOT ].aBits2,
1292 pBRC->aBits2,
1293 sizeof( SVBT16 ) );
1295 if( bChangeRight )
1297 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
1298 pBRC->aBits1,
1299 sizeof( SVBT16 ) );
1300 memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits2,
1301 pBRC->aBits2,
1302 sizeof( SVBT16 ) );
1309 void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams)
1311 // sprmTTableBorders
1312 if( bVer67 )
1314 for( int i = 0; i < 6; ++i )
1316 aDefBrcs[i].aBits1[0] = pParams[ 2*i ];
1317 aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ];
1320 else // aDefBrcs = *(BRC(*)[6])pS;
1321 memcpy( aDefBrcs, pParams, 24 );
1324 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol)
1326 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1327 // whose index is within a certain range to be a certain value.
1329 if( nWwCols && pParamsTDxaCol ) // set one or more cell length(s)
1331 sal_uInt8 nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1332 sal_uInt8 nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1
1333 short nDxaCol = (sal_Int16)SVBT16ToShort( pParamsTDxaCol + 2 );
1334 short nOrgWidth;
1335 short nDelta;
1337 for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1339 nOrgWidth = nCenter[i+1] - nCenter[i];
1340 nDelta = nDxaCol - nOrgWidth;
1341 for( int j = i+1; j <= nWwCols; j++ )
1343 nCenter[j] = nCenter[j] + nDelta;
1349 void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8* pParamsTInsert)
1351 if( nWwCols && pParamsTInsert ) // set one or more cell length(s)
1353 sal_uInt8 nitcInsert = pParamsTInsert[0]; // position at which to insert
1354 if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index
1355 return;
1356 sal_uInt8 nctc = pParamsTInsert[1]; // number of cells
1357 sal_uInt16 ndxaCol = SVBT16ToShort( pParamsTInsert+2 );
1359 short nNewWwCols;
1360 if (nitcInsert > nWwCols)
1362 nNewWwCols = nitcInsert+nctc;
1363 //if new count would be outside max possible count, clip it, and calc a new replacement
1364 //legal nctc
1365 if (nNewWwCols > MAX_COL)
1367 nNewWwCols = MAX_COL;
1368 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nitcInsert);
1371 else
1373 nNewWwCols = nWwCols+nctc;
1374 //if new count would be outside max possible count, clip it, and calc a new replacement
1375 //legal nctc
1376 if (nNewWwCols > MAX_COL)
1378 nNewWwCols = MAX_COL;
1379 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nWwCols);
1383 WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1384 setcelldefaults(pTC2s, nNewWwCols);
1386 if (pTCs)
1388 memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1389 delete[] pTCs;
1391 pTCs = pTC2s;
1393 //If we have to move some cells
1394 if (nitcInsert <= nWwCols)
1396 // adjust the left x-position of the dummy at the very end
1397 nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1398 for( int i = nWwCols-1; i >= nitcInsert; i--)
1400 // adjust the left x-position
1401 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1403 // adjust the cell's borders
1404 pTCs[i + nctc] = pTCs[i];
1408 //if itcMac is larger than full size, fill in missing ones first
1409 for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1410 nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1412 //now add in our new cells
1413 for( int j = 0;j < nctc; j++)
1414 nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1416 nWwCols = nNewWwCols;
1420 void WW8TabBandDesc::ProcessDirection(const sal_uInt8* pParams)
1422 sal_uInt8 nStartCell = *pParams++;
1423 sal_uInt8 nEndCell = *pParams++;
1424 sal_uInt16 nCode = SVBT16ToShort(pParams);
1426 OSL_ENSURE(nStartCell < nEndCell, "not as I thought");
1427 OSL_ENSURE(nEndCell < MAX_COL + 1, "not as I thought");
1428 if (nStartCell > MAX_COL)
1429 return;
1430 if (nEndCell > MAX_COL + 1)
1431 nEndCell = MAX_COL + 1;
1433 for (;nStartCell < nEndCell; ++nStartCell)
1434 maDirections[nStartCell] = nCode;
1437 void WW8TabBandDesc::ProcessSpacing(const sal_uInt8* pParams)
1439 sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1440 OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1441 if (nLen != 6)
1442 return;
1443 mbHasSpacing=true;
1444 #if OSL_DEBUG_LEVEL > 0
1445 sal_uInt8 nWhichCell = *pParams;
1446 OSL_ENSURE(nWhichCell == 0, "Expected cell to be 0!");
1447 #endif
1448 ++pParams; //Skip which cell
1449 ++pParams; //unknown byte
1451 sal_uInt8 nSideBits = *pParams++;
1452 OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1453 ++pParams; //unknown byte
1454 sal_uInt16 nValue = SVBT16ToShort( pParams );
1455 for (int i = wwTOP; i <= wwRIGHT; i++)
1457 switch (nSideBits & (1 << i))
1459 case 1 << wwTOP:
1460 mnDefaultTop = nValue;
1461 break;
1462 case 1 << wwLEFT:
1463 mnDefaultLeft = nValue;
1464 break;
1465 case 1 << wwBOTTOM:
1466 mnDefaultBottom = nValue;
1467 break;
1468 case 1 << wwRIGHT:
1469 mnDefaultRight = nValue;
1470 break;
1471 case 0:
1472 break;
1473 default:
1474 OSL_ENSURE(!this, "Impossible");
1475 break;
1480 void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8* pParams)
1482 sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1483 OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1484 if (nLen != 6)
1485 return;
1486 sal_uInt8 nWhichCell = *pParams++;
1487 OSL_ENSURE(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1488 if (nWhichCell >= MAX_COL + 1)
1489 return;
1491 ++pParams; //unknown byte
1492 sal_uInt8 nSideBits = *pParams++;
1493 OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1494 nOverrideSpacing[nWhichCell] |= nSideBits;
1496 OSL_ENSURE(nOverrideSpacing[nWhichCell] < 0x10,
1497 "Unexpected value for nSideBits");
1498 #if OSL_DEBUG_LEVEL > 0
1499 sal_uInt8 nUnknown2 = *pParams;
1500 OSL_ENSURE(nUnknown2 == 0x3, "Unexpected value for spacing2");
1501 #endif
1502 ++pParams;
1503 sal_uInt16 nValue = SVBT16ToShort( pParams );
1505 for (int i=0; i < 4; i++)
1507 if (nSideBits & (1 << i))
1508 nOverrideValues[nWhichCell][i] = nValue;
1512 void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8* pParamsTDelete)
1514 if( nWwCols && pParamsTDelete ) // set one or more cell length(s)
1516 sal_uInt8 nitcFirst= pParamsTDelete[0]; // first col to be deleted
1517 if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1518 return;
1519 sal_uInt8 nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1520 if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1521 return;
1524 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1525 * greater than or equal to itcLim to be moved
1527 int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1529 if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1531 WW8_TCell* pAktTC = pTCs + nitcFirst;
1532 int i = 0;
1533 while( i < nShlCnt )
1535 // adjust the left x-position
1536 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1538 // adjust the cell's borders
1539 *pAktTC = pTCs[ nitcLim + i];
1541 ++i;
1542 ++pAktTC;
1544 // adjust the left x-position of the dummy at the very end
1545 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1548 short nCellsDeleted = nitcLim - nitcFirst;
1549 //clip delete request to available number of cells
1550 if (nCellsDeleted > nWwCols)
1551 nCellsDeleted = nWwCols;
1552 nWwCols -= nCellsDeleted;
1556 // ReadShd reads the background color of a cell
1557 // ReadDef must be called before
1558 void WW8TabBandDesc::ReadShd(const sal_uInt8* pS )
1560 sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1561 if( !nLen )
1562 return;
1564 if( !pSHDs )
1566 pSHDs = new WW8_SHD[nWwCols];
1567 memset( pSHDs, 0, nWwCols * sizeof( WW8_SHD ) );
1570 short nAnz = nLen >> 1;
1571 if (nAnz > nWwCols)
1572 nAnz = nWwCols;
1574 SVBT16* pShd;
1575 int i;
1576 for(i=0, pShd = (SVBT16*)pS; i<nAnz; i++, pShd++ )
1577 pSHDs[i].SetWWValue( *pShd );
1580 void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67)
1582 sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1583 if (!nLen)
1584 return;
1586 if (!pNewSHDs)
1587 pNewSHDs = new sal_uInt32[nWwCols];
1589 short nAnz = nLen / 10; //10 bytes each
1590 if (nAnz > nWwCols)
1591 nAnz = nWwCols;
1593 int i=0;
1594 while (i < nAnz)
1595 pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1597 while (i < nWwCols)
1598 pNewSHDs[i++] = COL_AUTO;
1601 void WW8TabBandDesc::setcelldefaults(WW8_TCell *pCells, short nCols)
1603 memset( pCells, 0, nCols * sizeof( WW8_TCell ) );
1606 const sal_uInt8 *HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1608 const sal_uInt8 *pParams;
1609 if (bVer67)
1610 pParams = pPap->HasSprm(24);
1611 else
1613 if (0 == (pParams = pPap->HasSprm(0x244B)))
1614 pParams = pPap->HasSprm(0x2416);
1616 return pParams;
1619 enum wwTableSprm
1621 sprmNil,
1623 sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable,
1624 sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc,
1625 sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
1626 sprmTDxaGapHalf, sprmTTableBorders,
1628 sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing
1631 wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1633 switch (eVer)
1635 case ww::eWW8:
1636 switch (nId)
1638 case 0xF614:
1639 return sprmTTableWidth;
1640 case 0x7629:
1641 return sprmTTextFlow;
1642 case 0x3403:
1643 return sprmTFCantSplit;
1644 case 0x3404:
1645 return sprmTTableHeader;
1646 case 0x3466:
1647 return sprmTFCantSplit90;
1648 case 0x5400:
1649 return sprmTJc;
1650 case 0x560B:
1651 return sprmTFBiDi;
1652 case 0x5622:
1653 return sprmTDelete;
1654 case 0x7621:
1655 return sprmTInsert;
1656 case 0x7623:
1657 return sprmTDxaCol;
1658 case 0x9407:
1659 return sprmTDyaRowHeight;
1660 case 0x9601:
1661 return sprmTDxaLeft;
1662 case 0x9602:
1663 return sprmTDxaGapHalf;
1664 case 0xD605:
1665 return sprmTTableBorders;
1666 case 0xD608:
1667 return sprmTDefTable;
1668 case 0xD609:
1669 return sprmTDefTableShd;
1670 case 0xD612:
1671 return sprmTDefTableNewShd;
1672 case 0xD620:
1673 return sprmTSetBrc;
1674 case 0xD632:
1675 return sprmTSpacing;
1676 case 0xD634:
1677 return sprmTNewSpacing;
1679 break;
1680 case ww::eWW7:
1681 case ww::eWW6:
1682 switch (nId)
1684 case 182:
1685 return sprmTJc;
1686 case 183:
1687 return sprmTDxaLeft;
1688 case 184:
1689 return sprmTDxaGapHalf;
1690 case 186:
1691 return sprmTTableHeader;
1692 case 187:
1693 return sprmTTableBorders;
1694 case 189:
1695 return sprmTDyaRowHeight;
1696 case 190:
1697 return sprmTDefTable;
1698 case 191:
1699 return sprmTDefTableShd;
1700 case 193:
1701 return sprmTSetBrc;
1702 case 194:
1703 return sprmTInsert;
1704 case 195:
1705 return sprmTDelete;
1706 case 196:
1707 return sprmTDxaCol;
1709 break;
1710 case ww::eWW2:
1711 switch (nId)
1713 case 146:
1714 return sprmTJc;
1715 case 147:
1716 return sprmTDxaLeft;
1717 case 148:
1718 return sprmTDxaGapHalf;
1719 case 153:
1720 return sprmTDyaRowHeight;
1721 case 154:
1722 return sprmTDefTable;
1723 case 155:
1724 return sprmTDefTableShd;
1725 case 157:
1726 return sprmTSetBrc;
1727 case 158:
1728 return sprmTInsert;
1729 case 159:
1730 return sprmTDelete;
1731 case 160:
1732 return sprmTDxaCol;
1734 break;
1736 return sprmNil;
1739 WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
1740 mpOldRedlineStack(0),
1741 pIo(pIoClass),
1742 pFirstBand(0),
1743 pActBand(0),
1744 pTmpPos(0),
1745 pTblNd(0),
1746 pTabLines(0),
1747 pTabLine(0),
1748 pTabBoxes(0),
1749 pTabBox(0),
1750 pAktWWCell(0),
1751 nRows(0),
1752 nDefaultSwCols(0),
1753 nBands(0),
1754 nMinLeft(0),
1755 nConvertedLeft(0),
1756 nMaxRight(0),
1757 nSwWidth(0),
1758 nPreferredWidth(0),
1759 nOrgDxaLeft(0),
1760 bOk(true),
1761 bClaimLineFmt(false),
1762 eOri(text::HoriOrientation::NONE),
1763 bIsBiDi(false),
1764 nAktRow(0),
1765 nAktBandRow(0),
1766 nAktCol(0),
1767 nRowsToRepeat(0),
1768 pTable(0),
1769 pParentPos(0),
1770 pFlyFmt(0),
1771 aItemSet(pIo->rDoc.GetAttrPool(),RES_FRMATR_BEGIN,RES_FRMATR_END-1)
1773 pIo->bAktAND_fNumberAcross = false;
1775 static const sal_Int16 aOriArr[] =
1777 text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1780 bool bOldVer = ww::IsSevenMinus(pIo->GetFib().GetFIBVersion());
1781 WW8_TablePos aTabPos;
1783 WW8PLCFxSave1 aSave;
1784 pIo->pPlcxMan->GetPap()->Save( aSave );
1786 WW8PLCFx_Cp_FKP* pPap = pIo->pPlcxMan->GetPapPLCF();
1788 eOri = text::HoriOrientation::LEFT;
1790 WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1792 wwSprmParser aSprmParser(pIo->GetFib().GetFIBVersion());
1794 // process pPap until end of table found
1797 short nTabeDxaNew = SHRT_MAX;
1798 bool bTabRowJustRead = false;
1799 const sal_uInt8* pShadeSprm = 0;
1800 const sal_uInt8* pNewShadeSprm = 0;
1801 WW8_TablePos *pTabPos = 0;
1803 // search end of a tab row
1804 if(!(pIo->SearchRowEnd(pPap, nStartCp, pIo->nInTable)))
1806 bOk = false;
1807 break;
1810 // Get the SPRM chains:
1811 // first from PAP and then from PCD (of the Piece Table)
1812 WW8PLCFxDesc aDesc;
1813 pPap->GetSprms( &aDesc );
1814 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1816 const sal_uInt8* pParams = aSprmIter.GetAktParams();
1817 for (int nLoop = 0; nLoop < 2; ++nLoop)
1819 bool bRepeatedSprm = false;
1820 while (aSprmIter.GetSprms() && 0 != (pParams = aSprmIter.GetAktParams()))
1822 sal_uInt16 nId = aSprmIter.GetAktId();
1823 wwTableSprm eSprm = GetTableSprm(nId, pIo->GetFib().GetFIBVersion());
1824 switch (eSprm)
1826 case sprmTTableWidth:
1828 const sal_uInt8 b0 = pParams[0];
1829 const sal_uInt8 b1 = pParams[1];
1830 const sal_uInt8 b2 = pParams[2];
1831 if (b0 == 3) // Twips
1832 nPreferredWidth = b2 * 0x100 + b1;
1834 break;
1835 case sprmTTextFlow:
1836 pNewBand->ProcessDirection(pParams);
1837 break;
1838 case sprmTFCantSplit:
1839 pNewBand->bCantSplit = *pParams;
1840 bClaimLineFmt = true;
1841 break;
1842 case sprmTFCantSplit90:
1843 pNewBand->bCantSplit90 = *pParams;
1844 bClaimLineFmt = true;
1845 break;
1846 case sprmTTableBorders:
1847 pNewBand->ProcessSprmTTableBorders(bOldVer, pParams);
1848 break;
1849 case sprmTTableHeader:
1850 if (!bRepeatedSprm)
1852 nRowsToRepeat++;
1853 bRepeatedSprm = true;
1855 break;
1856 case sprmTJc:
1857 // sprmTJc - Justification Code
1858 if (nRows == 0)
1859 eOri = aOriArr[*pParams & 0x3];
1860 break;
1861 case sprmTFBiDi:
1862 bIsBiDi = SVBT16ToShort(pParams) ? true : false;
1863 break;
1864 case sprmTDxaGapHalf:
1865 pNewBand->nGapHalf = (sal_Int16)SVBT16ToShort( pParams );
1866 break;
1867 case sprmTDyaRowHeight:
1868 pNewBand->nLineHeight = (sal_Int16)SVBT16ToShort( pParams );
1869 bClaimLineFmt = true;
1870 break;
1871 case sprmTDefTable:
1872 pNewBand->ReadDef(bOldVer, pParams);
1873 bTabRowJustRead = true;
1874 break;
1875 case sprmTDefTableShd:
1876 pShadeSprm = pParams;
1877 break;
1878 case sprmTDefTableNewShd:
1879 pNewShadeSprm = pParams;
1880 break;
1881 case sprmTDxaLeft:
1882 // our Writer cannot shift single table lines
1883 // horizontally so we have to find the smallest
1884 // parameter (meaning the left-most position) and then
1885 // shift the whole table to that margin (see below)
1887 short nDxaNew = (sal_Int16)SVBT16ToShort( pParams );
1888 nOrgDxaLeft = nDxaNew;
1889 if( nDxaNew < nTabeDxaNew )
1890 nTabeDxaNew = nDxaNew;
1892 break;
1893 case sprmTSetBrc:
1894 pNewBand->ProcessSprmTSetBRC(bOldVer, pParams);
1895 break;
1896 case sprmTDxaCol:
1897 pNewBand->ProcessSprmTDxaCol(pParams);
1898 break;
1899 case sprmTInsert:
1900 pNewBand->ProcessSprmTInsert(pParams);
1901 break;
1902 case sprmTDelete:
1903 pNewBand->ProcessSprmTDelete(pParams);
1904 break;
1905 case sprmTNewSpacing:
1906 pNewBand->ProcessSpacing(pParams);
1907 break;
1908 case sprmTSpacing:
1909 pNewBand->ProcessSpecificSpacing(pParams);
1910 break;
1911 default:
1914 aSprmIter.advance();
1917 if( !nLoop )
1919 pPap->GetPCDSprms( aDesc );
1920 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1924 // WW-Tables can contain Fly-changes. For this abort tables here
1925 // and start again. *pPap is still before TabRowEnd, so TestApo()
1926 // can be called with the last parameter set to false and therefore
1927 // take effect.
1929 if (bTabRowJustRead)
1931 if (pShadeSprm)
1932 pNewBand->ReadShd(pShadeSprm);
1933 if (pNewShadeSprm)
1934 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
1937 if( nTabeDxaNew < SHRT_MAX )
1939 short* pCenter = pNewBand->nCenter;
1940 short firstDxaCenter = *pCenter;
1941 for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
1943 // #i30298# Use sprmTDxaLeft to adjust the left indent
1944 // #i40461# Use dxaGapHalf during calculation
1945 *pCenter +=
1946 (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
1950 if (!pActBand)
1951 pActBand = pFirstBand = pNewBand;
1952 else
1954 pActBand->pNextBand = pNewBand;
1955 pActBand = pNewBand;
1957 nBands++;
1959 pNewBand = new WW8TabBandDesc;
1961 nRows++;
1962 pActBand->nRows++;
1964 //Seek our pap to its next block of properties
1965 WW8PLCFxDesc aRes;
1966 aRes.pMemPos = 0;
1967 aRes.nStartPos = nStartCp;
1969 if (!(pPap->SeekPos(aRes.nStartPos)))
1971 aRes.nEndPos = WW8_CP_MAX;
1972 pPap->SetDirty(true);
1974 pPap->GetSprms(&aRes);
1975 pPap->SetDirty(false);
1977 //Are we at the end of available properties
1978 if (
1979 !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
1980 aRes.nStartPos == WW8_CP_MAX
1983 bOk = false;
1984 break;
1987 //Are we still in a table cell
1988 pParams = HasTabCellSprm(pPap, bOldVer);
1989 const sal_uInt8 *pLevel = pPap->HasSprm(0x6649);
1990 // InTable
1991 if (!pParams || (1 != *pParams) ||
1992 (pLevel && (*pLevel <= pIo->nInTable)))
1994 break;
1997 //Get the end of row new table positioning data
1998 WW8_CP nMyStartCp=nStartCp;
1999 if (pIo->SearchRowEnd(pPap, nMyStartCp, pIo->nInTable))
2000 if (pIo->ParseTabPos(&aTabPos, pPap))
2001 pTabPos = &aTabPos;
2003 //Move back to this cell
2004 aRes.pMemPos = 0;
2005 aRes.nStartPos = nStartCp;
2007 // PlcxMan currently points too far ahead so we need to bring
2008 // it back to where we are trying to make a table
2009 pIo->pPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2010 if (!(pPap->SeekPos(aRes.nStartPos)))
2012 aRes.nEndPos = WW8_CP_MAX;
2013 pPap->SetDirty(true);
2015 pPap->GetSprms(&aRes);
2016 pPap->SetDirty(false);
2018 //Does this row match up with the last row closely enough to be
2019 //considered part of the same table
2020 ApoTestResults aApo = pIo->TestApo(pIo->nInTable + 1, false, pTabPos);
2023 ##513##, #79474# If this is not sufficent, then we should look at
2024 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2025 part of this table, but instead is an absolutely positioned table
2026 outside of this one
2028 if (aApo.mbStopApo)
2029 break;
2030 if (aApo.mbStartApo)
2032 //if there really is a fly here, and not a "null" fly then break.
2033 WW8FlyPara *pNewFly = pIo->ConstructApo(aApo, pTabPos);
2034 if (pNewFly)
2035 delete pNewFly;
2036 else
2037 break;
2040 nStartCp = aRes.nEndPos;
2042 while( 1 );
2044 if( bOk )
2046 if( pActBand->nRows > 1 )
2048 // last band has more than 1 cell
2049 delete pNewBand;
2050 pNewBand = new WW8TabBandDesc( *pActBand ); // create new
2051 pActBand->nRows--; // wegen Sonderbehandlung Raender-Defaults
2052 pNewBand->nRows = 1;
2053 pActBand->pNextBand = pNewBand; // am Ende einschleifen
2054 nBands++;
2055 pNewBand = 0; // do not delete
2057 CalcDefaults();
2059 delete pNewBand;
2061 pIo->pPlcxMan->GetPap()->Restore( aSave );
2064 WW8TabDesc::~WW8TabDesc()
2066 WW8TabBandDesc* pR = pFirstBand;
2067 while(pR)
2069 WW8TabBandDesc* pR2 = pR->pNextBand;
2070 delete pR;
2071 pR = pR2;
2074 delete pParentPos;
2077 void WW8TabDesc::CalcDefaults()
2079 short nMinCols = SHRT_MAX;
2080 WW8TabBandDesc* pR;
2082 nMinLeft = SHRT_MAX;
2083 nMaxRight = SHRT_MIN;
2086 If we are an honestly inline centered table, then the normal rules of
2087 engagement for left and right margins do not apply. The multiple rows are
2088 centered regardless of the actual placement of rows, so we cannot have
2089 mismatched rows as is possible in other configurations.
2091 e.g. change the example bugdoc in word from text wrapping of none (inline)
2092 to around (in frame (bApo)) and the table splits into two very disjoint
2093 rows as the beginning point of each row are very different
2095 if ((!pIo->InLocalApo()) && (eOri == text::HoriOrientation::CENTER))
2097 for (pR = pFirstBand; pR; pR = pR->pNextBand)
2098 for( short i = pR->nWwCols; i >= 0; --i)
2099 pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2102 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2103 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2105 if( pR->nCenter[0] < nMinLeft )
2106 nMinLeft = pR->nCenter[0];
2108 for( short i = 0; i < pR->nWwCols; i++ )
2111 If the margins are so large as to make the displayable
2112 area inside them smaller than the minimum allowed then adjust the
2113 width to fit. But only do it if the two cells are not the exact
2114 same value, if they are then the cell does not really exist and will
2115 be blended together into the same cell through the use of the
2116 nTrans(late) array.
2117 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2119 int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2120 if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2122 pR->nCenter[i+1] = pR->nCenter[i]+MINLAY+pR->nGapHalf * 2;
2126 if( pR->nCenter[pR->nWwCols] > nMaxRight )
2127 nMaxRight = pR->nCenter[pR->nWwCols];
2129 nSwWidth = nMaxRight - nMinLeft;
2131 // If the table is right aligned we need to align all rows to the
2132 // row that has the furthest right point
2134 if(eOri == text::HoriOrientation::RIGHT)
2136 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2138 int adjust = nMaxRight - pR->nCenter[pR->nWwCols];
2139 for( short i = 0; i < pR->nWwCols + 1; i++ )
2141 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2147 // 2. pass: Detect number of writer columns. This can exceed the count
2148 // of columns in WW by 2, because SW in constrast to WW does not provide
2149 // fringed left and right borders and has to fill with empty boxes.
2150 // Non exisitent cells can reduce the number of columns.
2152 // 3. pass: Replace border with defaults if needed
2153 nConvertedLeft = nMinLeft;
2155 short nLeftMaxThickness = 0, nRightMaxThickness=0;
2156 for( pR = pFirstBand ; pR; pR = pR->pNextBand )
2158 if( !pR->pTCs )
2160 pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2161 memset( pR->pTCs, 0, pR->nWwCols * sizeof( WW8_TCell ) );
2163 for (int k = 0; k < pR->nWwCols; ++k)
2165 WW8_TCell* pT = &pR->pTCs[k];
2166 int i, j;
2167 for( i = 0; i < 4; i ++ )
2169 if (pT->rgbrc[i].IsZeroed(pIo->bVer67))
2171 // if shadow is set, its invalid
2172 j = i;
2173 switch( i )
2175 case 0:
2176 // outer top / horizontally inside
2177 j = (pR == pFirstBand) ? 0 : 4;
2178 break;
2179 case 1:
2180 // outer left / vertically inside
2181 j = k ? 5 : 1;
2182 break;
2183 case 2:
2184 // outer bottom / horizontally inside
2185 j = pR->pNextBand ? 4 : 2;
2186 break;
2187 case 3:
2188 // outer right / vertically inside
2189 j = (k == pR->nWwCols - 1) ? 3 : 5;
2190 break;
2192 // mangel mit Defaults ueber
2193 pT->rgbrc[i] = pR->aDefBrcs[j];
2197 if (pR->nWwCols)
2200 Similiar to graphics and other elements word does not totally
2201 factor the width of the border into its calculations of size, we
2202 do so we must adjust out widths and other dimensions to fit. It
2203 appears that what occurs is that the last cell's right margin if
2204 the margin width that is not calculated into winwords table
2205 dimensions, so in that case increase the table to include the
2206 extra width of the right margin.
2208 if ( pIo->bVer67 ?
2209 !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20)
2210 : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000))
2212 short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2213 DetermineBorderProperties(pIo->bVer67);
2214 pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2215 if (nThickness > nRightMaxThickness)
2216 nRightMaxThickness = nThickness;
2220 The left space of the table is in nMinLeft, but again this
2221 does not consider the margin thickness to its left in the
2222 placement value, so get the thickness of the left border,
2223 half is placed to the left of the nominal left side, and
2224 half to the right.
2226 if ( pIo->bVer67 ?
2227 !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20)
2228 : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000))
2230 short nThickness = pR->pTCs[0].rgbrc[1].
2231 DetermineBorderProperties(pIo->bVer67);
2232 if (nThickness > nLeftMaxThickness)
2233 nLeftMaxThickness = nThickness;
2237 nSwWidth = nSwWidth + nRightMaxThickness;
2238 nMaxRight = nMaxRight + nRightMaxThickness;
2239 nConvertedLeft = nMinLeft-(nLeftMaxThickness/2);
2241 for( pR = pFirstBand; pR; pR = pR->pNextBand )
2243 pR->nSwCols = pR->nWwCols;
2244 pR->bLEmptyCol = pR->nCenter[0] - nMinLeft >= MINLAY;
2245 pR->bREmptyCol = (nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2247 short nAddCols = pR->bLEmptyCol + pR->bREmptyCol;
2248 sal_uInt16 i;
2249 sal_uInt16 j = ( pR->bLEmptyCol ) ? 1 : 0;
2250 for (i = 0; i < pR->nWwCols; ++i)
2252 pR->nTransCell[i] = (sal_Int8)j;
2253 if ( pR->nCenter[i] < pR->nCenter[i+1] )
2255 pR->bExist[i] = true;
2256 j++;
2258 else
2260 pR->bExist[i] = false;
2261 nAddCols--;
2265 OSL_ENSURE(i,"no columns in row ?");
2268 If the last cell was "false" then there is no valid cell following it,
2269 so the default mapping forward wont't work. So map it (and
2270 contigious invalid cells backwards to the last valid cell instead.
2272 if (i && pR->bExist[i-1] == false)
2274 sal_uInt16 k=i-1;
2275 while (k && pR->bExist[k] == false)
2276 k--;
2277 for (sal_uInt16 n=k+1;n<i;n++)
2278 pR->nTransCell[n] = pR->nTransCell[k];
2281 pR->nTransCell[i++] = (sal_Int8)(j++); // Can exceed by 2 among other
2282 pR->nTransCell[i] = (sal_Int8)j; // things because of bREmptyCol
2284 pR->nSwCols = pR->nSwCols + nAddCols;
2285 if( pR->nSwCols < nMinCols )
2286 nMinCols = pR->nSwCols;
2290 #i9718#
2291 Find the largest of the borders on cells that adjoin top bottom and remove
2292 the val from the top and put in on the bottom cell. I can't seem to make
2293 disjoint upper and lowers to see what happens there.
2296 if ((nMinLeft && !bIsBiDi && text::HoriOrientation::LEFT == eOri) ||
2297 (nMinLeft != -108 && bIsBiDi && text::HoriOrientation::RIGHT == eOri)) // Word sets the first nCenter value to -108 when no indent is used
2298 eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2300 nDefaultSwCols = nMinCols; // because inserting cells is cheaper than merging
2301 if( nDefaultSwCols == 0 )
2302 bOk = false;
2303 pActBand = pFirstBand;
2304 nAktBandRow = 0;
2305 OSL_ENSURE( pActBand, "pActBand ist 0" );
2308 void WW8TabDesc::SetSizePosition(SwFrmFmt* pFrmFmt)
2310 SwFrmFmt* pApply = pFrmFmt;
2311 if (!pApply )
2312 pApply = pTable->GetFrmFmt();
2313 OSL_ENSURE(pApply,"No frame");
2314 pApply->SetFmtAttr(aItemSet);
2315 if (pFrmFmt)
2317 SwFmtFrmSize aSize = pFrmFmt->GetFrmSize();
2318 aSize.SetHeightSizeType(ATT_MIN_SIZE);
2319 aSize.SetHeight(MINLAY);
2320 pFrmFmt->SetFmtAttr(aSize);
2321 pTable->GetFrmFmt()->SetFmtAttr(SwFmtHoriOrient(0,text::HoriOrientation::FULL));
2325 void wwSectionManager::PrependedInlineNode(const SwPosition &rPos,
2326 const SwNode &rNode)
2328 OSL_ENSURE(!maSegments.empty(),
2329 "should not be possible, must be at least one segment");
2330 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2331 maSegments.back().maStart = SwNodeIndex(rNode);
2334 void WW8TabDesc::CreateSwTable()
2336 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
2338 // if there is already some content on the Node append new node to ensure
2339 // that this content remains ABOVE the table
2340 SwPosition* pPoint = pIo->pPaM->GetPoint();
2341 bool bInsNode = pPoint->nContent.GetIndex() ? true : false;
2342 bool bSetMinHeight = false;
2345 #i8062#
2346 Set fly anchor to its anchor pos, so that if a table starts immediately
2347 at this position a new node will be inserted before inserting the table.
2349 if (!bInsNode && pIo->pFmtOfJustInsertedApo)
2351 const SwPosition* pAPos =
2352 pIo->pFmtOfJustInsertedApo->GetAnchor().GetCntntAnchor();
2353 if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2355 bInsNode = true;
2356 bSetMinHeight = true;
2358 SwFmtSurround aSur(pIo->pFmtOfJustInsertedApo->GetSurround());
2359 aSur.SetAnchorOnly(true);
2360 pIo->pFmtOfJustInsertedApo->SetFmtAttr(aSur);
2364 if (bSetMinHeight == true)
2366 // minimize Fontsize to minimize height growth of the header/footer
2367 // set font size to 1 point to minimize y-growth of Hd/Ft
2368 SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2369 pIo->NewAttr( aSz );
2370 pIo->pCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2373 if (bInsNode)
2374 pIo->AppendTxtNode(*pPoint);
2376 pTmpPos = new SwPosition( *pIo->pPaM->GetPoint() );
2378 // The table is small: The number of columns is the lowest count of
2379 // columns of the origin, because inserting is faster than deleting.
2380 // The number of rows is the count of bands because (identically)
2381 // rows of a band can be duplicated easy.
2382 pTable = pIo->rDoc.InsertTable(
2383 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
2384 *pTmpPos, nBands, nDefaultSwCols, eOri, 0, 0, sal_False, sal_True );
2386 OSL_ENSURE(pTable && pTable->GetFrmFmt(), "insert table failed");
2387 if (!pTable || !pTable->GetFrmFmt())
2388 return;
2390 SwTableNode* pTableNode = pTable->GetTableNode();
2391 OSL_ENSURE(pTableNode, "no table node!");
2392 if (pTableNode)
2394 pIo->maSectionManager.PrependedInlineNode(*pIo->pPaM->GetPoint(),
2395 *pTableNode);
2398 // Check if the node into which the table should be inserted already
2399 // contains a Pagedesc. If so that Pagedesc would be moved to the
2400 // row after the table, whats wrong. So delete and
2401 // set later to the table format.
2402 if (SwTxtNode *const pNd = pTmpPos->nNode.GetNode().GetTxtNode())
2404 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2406 SfxPoolItem *pSetAttr = 0;
2407 const SfxPoolItem* pItem;
2408 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2410 pSetAttr = new SvxFmtBreakItem( *(SvxFmtBreakItem*)pItem );
2411 pNd->ResetAttr( RES_BREAK );
2414 // eventually set the PageDesc/Break now to the table
2415 if (pSetAttr)
2417 aItemSet.Put(*pSetAttr);
2418 delete pSetAttr;
2423 // total width of table
2424 if( nMaxRight - nMinLeft > MINLAY * nDefaultSwCols )
2426 pTable->GetFrmFmt()->SetFmtAttr(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2427 aItemSet.Put(SwFmtFrmSize(ATT_FIX_SIZE, nSwWidth));
2430 SvxFrameDirectionItem aDirection(
2431 bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
2432 pTable->GetFrmFmt()->SetFmtAttr(aDirection);
2434 if (text::HoriOrientation::LEFT_AND_WIDTH == eOri)
2436 if (!pIo->nInTable && pIo->InLocalApo() && pIo->pSFlyPara->pFlyFmt &&
2437 GetMinLeft())
2439 //If we are inside a frame and we have a border, the frames
2440 //placement does not consider the tables border, which word
2441 //displays outside the frame, so adjust here.
2442 SwFmtHoriOrient aHori(pIo->pSFlyPara->pFlyFmt->GetHoriOrient());
2443 sal_Int16 eHori = aHori.GetHoriOrient();
2444 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2445 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2447 //With multiple table, use last table settings. Perhaps
2448 //the maximum is what word does ?
2449 aHori.SetPos(pIo->pSFlyPara->nXPos + GetMinLeft());
2450 aHori.SetHoriOrient(text::HoriOrientation::NONE);
2451 pIo->pSFlyPara->pFlyFmt->SetFmtAttr(aHori);
2454 else
2456 //If bApo is set, then this table is being placed in a floating
2457 //frame, and the frame matches the left and right *lines* of the
2458 //table, so the space to the left of the table isn't to be used
2459 //inside the frame, in word the dialog involved greys out the
2460 //ability to set the margin.
2461 SvxLRSpaceItem aL( RES_LR_SPACE );
2462 // set right to original DxaLeft (i28656)
2464 long nLeft = 0;
2465 if (!bIsBiDi)
2466 nLeft = GetMinLeft();
2467 else
2469 if (nPreferredWidth)
2471 nLeft = pIo->maSectionManager.GetTextAreaWidth();
2472 nLeft = nLeft - nPreferredWidth - nOrgDxaLeft;
2474 else
2475 nLeft = -GetMinLeft();
2478 aL.SetLeft(nLeft);
2480 aItemSet.Put(aL);
2484 mpOldRedlineStack = pIo->mpRedlineStack;
2485 pIo->mpRedlineStack = new sw::util::RedlineStack(pIo->rDoc);
2488 void WW8TabDesc::UseSwTable()
2490 // init global Vars
2491 pTabLines = &pTable->GetTabLines();
2492 nAktRow = nAktCol = nAktBandRow = 0;
2494 pTblNd = (SwTableNode*)(*pTabLines)[0]->GetTabBoxes()[0]->
2495 GetSttNd()->FindTableNode();
2496 OSL_ENSURE( pTblNd, "wo ist mein TabellenNode" );
2498 // #i69519# - Restrict rows to repeat to a decent value
2499 if ( nRowsToRepeat == static_cast<sal_uInt16>(nRows) )
2500 nRowsToRepeat = 1;
2502 pTblNd->GetTable().SetRowsToRepeat( nRowsToRepeat );
2503 // insert extra cells if needed and something like this
2504 AdjustNewBand();
2506 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2507 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), 0, false);
2509 // now set the correct PaM and prepare first merger group if any
2510 SetPamInCell(nAktCol, true);
2511 aDup.Insert(*pIo->pPaM->GetPoint());
2513 pIo->bWasTabRowEnd = false;
2514 pIo->bWasTabCellEnd = false;
2517 void WW8TabDesc::MergeCells()
2519 short nRow;
2521 for (pActBand=pFirstBand, nRow=0; pActBand; pActBand=pActBand->pNextBand)
2523 // insert current box into merge group if appropriate
2524 if( pActBand->pTCs )
2526 for( short j = 0; j < pActBand->nRows; j++, nRow++ )
2527 for( short i = 0; i < pActBand->nWwCols; i++ )
2529 WW8SelBoxInfo* pActMGroup = 0;
2531 // start a new merge group if appropriate
2533 OSL_ENSURE(nRow < (sal_uInt16)pTabLines->size(),
2534 "Too few lines, table ended early");
2535 if (nRow >= (sal_uInt16)pTabLines->size())
2536 return;
2537 pTabLine = (*pTabLines)[ nRow ];
2538 pTabBoxes = &pTabLine->GetTabBoxes();
2540 sal_uInt16 nCol = pActBand->nTransCell[ i ];
2541 if (!pActBand->bExist[i])
2542 continue;
2543 OSL_ENSURE(nCol < pTabBoxes->size(),
2544 "Too few columns, table ended early");
2545 if (nCol >= pTabBoxes->size())
2546 return;
2547 pTabBox = (*pTabBoxes)[nCol];
2548 WW8_TCell& rCell = pActBand->pTCs[ i ];
2549 // is this the left upper cell of a merge group ?
2551 bool bMerge = false;
2552 if ( rCell.bVertRestart && !rCell.bMerged )
2553 bMerge = true;
2554 else if (rCell.bFirstMerged && pActBand->bExist[i])
2556 // Some tests to avoid merging cells which previously were
2557 // declared invalid because of sharing the exact same dimensions
2558 // as their previous cell
2560 //If theres anything underneath/above we're ok.
2561 if (rCell.bVertMerge || rCell.bVertRestart)
2562 bMerge = true;
2563 else
2565 //If its a hori merge only, and the only things in
2566 //it are invalid cells then its already taken care
2567 //of, so don't merge.
2568 for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2569 if (pActBand->pTCs[ i2 ].bMerged &&
2570 !pActBand->pTCs[ i2 ].bFirstMerged )
2572 if (pActBand->bExist[i2])
2574 bMerge = true;
2575 break;
2578 else
2579 break;
2584 if (bMerge)
2586 short nX1 = pActBand->nCenter[ i ];
2587 short nWidth = pActBand->nWidth[ i ];
2589 // 2. create current merge group
2590 pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2592 // determine size of new merge group
2593 // before inserted the new merge group.
2594 // Needed to correctly locked previously created merge groups.
2595 // Calculate total width and set
2596 short nSizCell = pActBand->nWidth[ i ];
2597 for (sal_uInt16 i2 = i+1; i2 < pActBand->nWwCols; i2++ )
2598 if (pActBand->pTCs[ i2 ].bMerged &&
2599 !pActBand->pTCs[ i2 ].bFirstMerged )
2601 nSizCell = nSizCell + pActBand->nWidth[ i2 ];
2603 else
2604 break;
2605 pActMGroup->nGroupWidth = nSizCell;
2607 // locked previously created merge groups,
2608 // after determining the size for the new merge group.
2609 // 1. If necessary close old merge group(s) that overlap
2610 // the X-area of the new group
2611 for (;;)
2613 WW8SelBoxInfo* p = FindMergeGroup(
2614 nX1, pActMGroup->nGroupWidth, false );
2615 if (p == 0)
2617 break;
2619 p->bGroupLocked = true;
2622 // 3. push to group array
2623 aMergeGroups.push_back(pActMGroup);
2626 // if necessary add the current box to a merge group
2627 // (that can be a newly created or another group)
2628 UpdateTableMergeGroup( rCell, pActMGroup, pTabBox, i );
2634 //There is a limbo area in word at the end of the row marker
2635 //where properties can live in word, there is no location in
2636 //writer equivalent, so try and park the cursor in the best
2637 //match, see #i23022#/#i18644#
2638 void WW8TabDesc::ParkPaM()
2640 SwTableBox *pTabBox2 = 0;
2641 short nRow = nAktRow + 1;
2642 if (nRow < (sal_uInt16)pTabLines->size())
2644 if (SwTableLine *pLine = (*pTabLines)[nRow])
2646 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2647 pTabBox2 = rBoxes.empty() ? 0 : rBoxes.front();
2651 if (!pTabBox2 || !pTabBox2->GetSttNd())
2653 MoveOutsideTable();
2654 return;
2657 if (pIo->pPaM->GetPoint()->nNode != pTabBox2->GetSttIdx() + 1)
2659 pIo->pPaM->GetPoint()->nNode = pTabBox2->GetSttIdx() + 1;
2660 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2661 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2665 void WW8TabDesc::MoveOutsideTable()
2667 OSL_ENSURE(pTmpPos && pIo, "I've forgotten where the table is anchored");
2668 if (pTmpPos && pIo)
2669 *pIo->pPaM->GetPoint() = *pTmpPos;
2672 void WW8TabDesc::FinishSwTable()
2674 pIo->mpRedlineStack->closeall(*pIo->pPaM->GetPoint());
2675 delete pIo->mpRedlineStack;
2676 pIo->mpRedlineStack = mpOldRedlineStack;
2677 mpOldRedlineStack = 0;
2679 WW8DupProperties aDup(pIo->rDoc,pIo->pCtrlStck);
2680 pIo->pCtrlStck->SetAttr( *pIo->pPaM->GetPoint(), 0, false);
2682 MoveOutsideTable();
2683 delete pTmpPos, pTmpPos = 0;
2685 aDup.Insert(*pIo->pPaM->GetPoint());
2687 pIo->bWasTabRowEnd = false;
2688 pIo->bWasTabCellEnd = false;
2690 pIo->maInsertedTables.InsertTable(*pTblNd, *pIo->pPaM);
2692 MergeCells();
2694 // if needed group cells together that should be merged
2695 if( !aMergeGroups.empty() )
2697 // process all merge groups one by one
2698 for (
2699 WW8MergeGroups::iterator groupIt = aMergeGroups.begin();
2700 groupIt != aMergeGroups.end();
2701 ++groupIt)
2703 sal_uInt16 nActBoxCount = groupIt->size();
2705 if( ( 1 < nActBoxCount ) && (*groupIt)[0] )
2707 const sal_uInt16 nRowSpan = groupIt->size();
2708 for (sal_uInt16 n = 0; n < nRowSpan; ++n)
2710 SwTableBox* pCurrentBox = (*groupIt)[n];
2711 const long nRowSpanSet = n == 0 ?
2712 nRowSpan :
2713 ((-1) * (nRowSpan - n));
2714 pCurrentBox->setRowSpan( nRowSpanSet );
2718 pIo->pFmtOfJustInsertedApo = 0;
2719 aMergeGroups.clear();
2724 // browse aMergeGroups, detect the index of the first fitting group or -1 otherwise
2726 // Parameter: nXcenter = center position of asking box
2727 // nWidth = width of asking box
2728 // bExact = flag, if box has to fit into group
2729 // or only has to touch
2731 WW8SelBoxInfo* WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact)
2733 if( !aMergeGroups.empty() )
2735 // still valid area near the boundery
2736 const short nToleranz = 4;
2737 // box boundery
2738 short nX2 = nX1 + nWidth;
2739 // approximate group boundery
2740 short nGrX1;
2741 short nGrX2;
2743 // improvement: search backwards
2744 for ( short iGr = aMergeGroups.size() - 1; iGr >= 0; --iGr )
2746 // the currently inspected group
2747 WW8SelBoxInfo& rActGroup = aMergeGroups[ iGr ];
2748 if (!rActGroup.bGroupLocked)
2750 // approximate group boundery with room (tolerance) to the *outside*
2751 nGrX1 = rActGroup.nGroupXStart - nToleranz;
2752 nGrX2 = rActGroup.nGroupXStart
2753 +rActGroup.nGroupWidth + nToleranz;
2755 // If box fits report success
2757 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2759 return &rActGroup;
2762 // does the box share areas with the group?
2764 if( !bExact )
2766 // successful if nX1 *or* nX2 are inside the group
2767 if( ( ( nX1 > nGrX1 )
2768 && ( nX1 < nGrX2 - 2*nToleranz ) )
2769 || ( ( nX2 > nGrX1 + 2*nToleranz )
2770 && ( nX2 < nGrX2 ) )
2771 // or nX1 and nX2 surround the group
2772 || ( ( nX1 <=nGrX1 )
2773 && ( nX2 >=nGrX2 ) ) )
2775 return &rActGroup;
2781 return 0;
2784 bool WW8TabDesc::IsValidCell(short nCol) const
2786 return (static_cast<size_t>(nCol) < SAL_N_ELEMENTS(pActBand->bExist)) &&
2787 pActBand->bExist[nCol] &&
2788 (sal_uInt16)nAktRow < pTabLines->size();
2791 bool WW8TabDesc::InFirstParaInCell() const
2793 //e.g. #i19718#
2794 if (!pTabBox || !pTabBox->GetSttNd())
2796 OSL_FAIL("Problem with table");
2797 return false;
2800 if (!IsValidCell(GetAktCol()))
2801 return false;
2803 if (pIo->pPaM->GetPoint()->nNode == pTabBox->GetSttIdx() + 1)
2804 return true;
2806 return false;
2809 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol)
2811 OSL_ENSURE(pActBand, "Impossible");
2812 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2814 pIo->pCtrlStck->NewAttr(*pIo->pPaM->GetPoint(),
2815 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE));
2819 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol)
2821 OSL_ENSURE(pActBand, "Impossible");
2822 if (pActBand && pActBand->maDirections[nWwCol] == 3)
2823 pIo->pCtrlStck->SetAttr(*pIo->pPaM->GetPoint(), RES_CHRATR_ROTATE);
2826 bool WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2828 OSL_ENSURE( pActBand, "pActBand ist 0" );
2830 sal_uInt16 nCol = pActBand->transCell(nWwCol);
2832 if ((sal_uInt16)nAktRow >= pTabLines->size())
2834 OSL_ENSURE(!this, "Actual row bigger than expected." );
2835 if (bPam)
2836 MoveOutsideTable();
2837 return false;
2840 pTabLine = (*pTabLines)[nAktRow];
2841 pTabBoxes = &pTabLine->GetTabBoxes();
2843 if (nCol >= pTabBoxes->size())
2845 if (bPam)
2847 // The first paragraph in a cell with upper autospacing has upper
2848 // spacing set to 0
2849 if (
2850 pIo->bParaAutoBefore && pIo->bFirstPara &&
2851 !pIo->pWDop->fDontUseHTMLAutoSpacing
2854 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2857 // The last paragraph in a cell with lower autospacing has lower
2858 // spacing set to 0
2859 if (pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2860 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2862 ParkPaM();
2864 return false;
2866 pTabBox = (*pTabBoxes)[nCol];
2867 if( !pTabBox->GetSttNd() )
2869 OSL_ENSURE(pTabBox->GetSttNd(), "Probleme beim Aufbau der Tabelle");
2870 if (bPam)
2871 MoveOutsideTable();
2872 return false;
2874 if (bPam)
2876 pAktWWCell = &pActBand->pTCs[ nWwCol ];
2878 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2879 if(pIo->bParaAutoBefore && pIo->bFirstPara && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2880 pIo->SetUpperSpacing(*pIo->pPaM, 0);
2882 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2883 if(pIo->bParaAutoAfter && !pIo->pWDop->fDontUseHTMLAutoSpacing)
2884 pIo->SetLowerSpacing(*pIo->pPaM, 0);
2886 //We need to set the pPaM on the first cell, invalid
2887 //or not so that we can collect paragraph proproties over
2888 //all the cells, but in that case on the valid cell we do not
2889 //want to reset the fmt properties
2890 if (pIo->pPaM->GetPoint()->nNode != pTabBox->GetSttIdx() + 1)
2892 pIo->pPaM->GetPoint()->nNode = pTabBox->GetSttIdx() + 1;
2893 pIo->pPaM->GetPoint()->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2894 // Precautionally set now, otherwise the style is not set for cells
2895 // that are inserted for margin balancing.
2896 pIo->rDoc.SetTxtFmtColl(*pIo->pPaM, (SwTxtFmtColl*)pIo->pDfltTxtFmtColl);
2897 // because this cells are invisible helper constructions only to simulate
2898 // the frayed view of WW-tables we do NOT need SetTxtFmtCollAndListLevel()
2901 // Better to turn Snap to Grid off for all paragraphs in tables
2902 if(SwTxtNode *pNd = pIo->pPaM->GetNode()->GetTxtNode())
2904 const SfxPoolItem &rItm = pNd->SwCntntNode::GetAttr(RES_PARATR_SNAPTOGRID);
2905 SvxParaGridItem &rSnapToGrid = (SvxParaGridItem&)(rItm);
2907 if(rSnapToGrid.GetValue())
2909 SvxParaGridItem aGridItem( rSnapToGrid );
2910 aGridItem.SetValue(false);
2912 SwPosition* pGridPos = pIo->pPaM->GetPoint();
2914 xub_StrLen nEnd = pGridPos->nContent.GetIndex();
2915 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), 0);
2916 pIo->pCtrlStck->NewAttr(*pGridPos, aGridItem);
2917 pGridPos->nContent.Assign(pIo->pPaM->GetCntntNode(), nEnd);
2918 pIo->pCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
2922 StartMiserableHackForUnsupportedDirection(nWwCol);
2924 return true;
2927 void WW8TabDesc::InsertCells( short nIns )
2929 pTabLine = (*pTabLines)[nAktRow];
2930 pTabBoxes = &pTabLine->GetTabBoxes();
2931 pTabBox = (*pTabBoxes)[0];
2933 pIo->rDoc.GetNodes().InsBoxen( pTblNd, pTabLine, (SwTableBoxFmt*)pTabBox->GetFrmFmt(),
2934 (SwTxtFmtColl*)pIo->pDfltTxtFmtColl, 0, pTabBoxes->size(), nIns );
2935 // The third parameter contains the FrmFmt of the boxes.
2936 // Here it is possible to optimize to save (reduce) FrmFmts.
2939 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
2941 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
2942 return; // faked cells -> no border
2945 SvxBoxItem aFmtBox( RES_BOX );
2946 if (pActBand->pTCs) // neither Cell Border nor Default Border defined ?
2948 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
2949 if (pIo->IsBorder(pT->rgbrc))
2950 pIo->SetBorder(aFmtBox, pT->rgbrc);
2953 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
2955 aFmtBox.SetDistance(
2956 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwTOP],
2957 BOX_LINE_TOP);
2959 else
2960 aFmtBox.SetDistance(pActBand->mnDefaultTop, BOX_LINE_TOP);
2961 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwBOTTOM))
2963 aFmtBox.SetDistance(
2964 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwBOTTOM],
2965 BOX_LINE_BOTTOM);
2967 else
2968 aFmtBox.SetDistance(pActBand->mnDefaultBottom,BOX_LINE_BOTTOM);
2970 // nGapHalf for WW is a *horizontal* gap between table cell and content.
2971 short nLeftDist =
2972 pActBand->mbHasSpacing ? pActBand->mnDefaultLeft : pActBand->nGapHalf;
2973 short nRightDist =
2974 pActBand->mbHasSpacing ? pActBand->mnDefaultRight : pActBand->nGapHalf;
2975 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
2977 aFmtBox.SetDistance(
2978 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwLEFT],
2979 BOX_LINE_LEFT);
2981 else
2982 aFmtBox.SetDistance(nLeftDist, BOX_LINE_LEFT);
2983 if (pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
2985 aFmtBox.SetDistance(
2986 pActBand->nOverrideValues[nWwIdx][WW8TabBandDesc::wwRIGHT],
2987 BOX_LINE_RIGHT);
2989 else
2990 aFmtBox.SetDistance(nRightDist,BOX_LINE_RIGHT);
2992 pBox->GetFrmFmt()->SetFmtAttr(aFmtBox);
2995 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
2997 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
2998 return; // faked cells -> no color
3000 bool bFound=false;
3001 if (pActBand->pNewSHDs && pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3003 Color aColor(pActBand->pNewSHDs[nWwIdx]);
3004 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aColor, RES_BACKGROUND));
3005 bFound = true;
3008 //If there was no new shades, or no new shade setting
3009 if (pActBand->pSHDs && !bFound)
3011 WW8_SHD& rSHD = pActBand->pSHDs[nWwIdx];
3012 if (!rSHD.GetValue()) // auto
3013 return;
3015 SwWW8Shade aSh( pIo->bVer67, rSHD );
3016 pBox->GetFrmFmt()->SetFmtAttr(SvxBrushItem(aSh.aColor, RES_BACKGROUND));
3020 SvxFrameDirection MakeDirection(sal_uInt16 nCode, bool bIsBiDi)
3022 SvxFrameDirection eDir = FRMDIR_ENVIRONMENT;
3023 // 1: Asian layout with rotated CJK characters
3024 // 5: Asian layout
3025 // 3: Western layout rotated by 90 degrees
3026 // 4: Western layout
3027 switch (nCode)
3029 default:
3030 OSL_ENSURE(eDir == 4, "unknown direction code, maybe its a bitfield");
3031 case 3:
3032 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP; // #i38158# - Consider RTL tables
3033 break;
3034 case 5:
3035 eDir = FRMDIR_VERT_TOP_RIGHT;
3036 break;
3037 case 1:
3038 eDir = FRMDIR_VERT_TOP_RIGHT;
3039 break;
3040 case 4:
3041 eDir = bIsBiDi ? FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP; // #i38158# - Consider RTL tables
3042 break;
3044 return eDir;
3047 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3049 if (nWwIdx < 0 || nWwIdx >= pActBand->nWwCols)
3050 return;
3051 SvxFrameDirectionItem aItem(MakeDirection(pActBand->maDirections[nWwIdx], bIsBiDi), RES_FRAMEDIR);
3052 pBox->GetFrmFmt()->SetFmtAttr(aItem);
3055 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3057 if( nWwIdx < 0 || nWwIdx >= pActBand->nWwCols )
3058 return;
3060 sal_Int16 eVertOri=text::VertOrientation::TOP;
3062 if( pActBand->pTCs )
3064 WW8_TCell* pT = &pActBand->pTCs[nWwIdx];
3065 switch (pT->nVertAlign)
3067 case 0:
3068 default:
3069 eVertOri = text::VertOrientation::TOP;
3070 break;
3071 case 1:
3072 eVertOri = text::VertOrientation::CENTER;
3073 break;
3074 case 2:
3075 eVertOri = text::VertOrientation::BOTTOM;
3076 break;
3080 pBox->GetFrmFmt()->SetFmtAttr( SwFmtVertOrient(0,eVertOri) );
3083 void WW8TabDesc::AdjustNewBand()
3085 if( pActBand->nSwCols > nDefaultSwCols ) // split cells
3086 InsertCells( pActBand->nSwCols - nDefaultSwCols );
3088 SetPamInCell( 0, false);
3089 OSL_ENSURE( pTabBoxes && pTabBoxes->size() == (sal_uInt16)pActBand->nSwCols,
3090 "Falsche Spaltenzahl in Tabelle" );
3092 if( bClaimLineFmt )
3094 pTabLine->ClaimFrmFmt(); // necessary because of cell height
3095 SwFmtFrmSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3097 if (pActBand->nLineHeight == 0) // 0 = Auto
3098 aF.SetHeightSizeType( ATT_VAR_SIZE );
3099 else
3101 if (pActBand->nLineHeight < 0) // positive = min, negative = exact
3103 aF.SetHeightSizeType(ATT_FIX_SIZE);
3104 pActBand->nLineHeight = -pActBand->nLineHeight;
3106 if (pActBand->nLineHeight < MINLAY) // invalid cell height
3107 pActBand->nLineHeight = MINLAY;
3109 aF.SetHeight(pActBand->nLineHeight);// set min/exact height
3111 pTabLine->GetFrmFmt()->SetFmtAttr(aF);
3114 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3115 //we can split the row
3116 // bCantSplit: Always true for rows containing merged cells (Word <= 2000 crashes otherwise)
3117 // So in case bCantSplit is true, we check for bCantSplit90, which has been introduced for
3118 // Word versions >= 2002.
3119 bool bSetCantSplit = pActBand->bCantSplit;
3120 if(bSetCantSplit)
3121 bSetCantSplit = pActBand->bCantSplit90;
3123 pTabLine->GetFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bSetCantSplit));
3125 short i; // SW-Index
3126 short j; // WW-Index
3127 short nW; // Width
3128 SwFmtFrmSize aFS( ATT_FIX_SIZE );
3129 j = pActBand->bLEmptyCol ? -1 : 0;
3131 for( i = 0; i < pActBand->nSwCols; i++ )
3133 // set cell width
3134 if( j < 0 )
3135 nW = pActBand->nCenter[0] - nMinLeft;
3136 else
3138 //Set j to first non invalid cell
3139 while ((j < pActBand->nWwCols) && (!pActBand->bExist[j]))
3140 j++;
3142 if( j < pActBand->nWwCols )
3143 nW = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3144 else
3145 nW = nMaxRight - pActBand->nCenter[j];
3146 pActBand->nWidth[ j ] = nW;
3149 SwTableBox* pBox = (*pTabBoxes)[i];
3150 // could be reduced further by intelligent moving of FrmFmts
3151 pBox->ClaimFrmFmt();
3153 SetTabBorders(pBox, j);
3155 // #i18128# word has only one line between adjoining vertical cells
3156 // we have to mimick this in the filter by picking the larger of the
3157 // sides and using that one on one side of the line (right)
3158 SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrmFmt()), RES_BOX));
3159 const ::editeng::SvxBorderLine *pLeftLine = aCurrentBox.GetLine(BOX_LINE_LEFT);
3160 int nCurrentRightLineWidth = 0;
3161 if(pLeftLine)
3162 nCurrentRightLineWidth = pLeftLine->GetScaledWidth();
3164 if (i != 0)
3166 SwTableBox* pBox2 = (*pTabBoxes)[i-1];
3167 SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrmFmt()), RES_BOX));
3168 const ::editeng::SvxBorderLine *pRightLine = aOldBox.GetLine(BOX_LINE_RIGHT);
3169 int nOldBoxRightLineWidth = 0;
3170 if(pRightLine)
3171 nOldBoxRightLineWidth = pRightLine->GetScaledWidth();
3173 if(nOldBoxRightLineWidth>nCurrentRightLineWidth)
3174 aCurrentBox.SetLine(aOldBox.GetLine(BOX_LINE_RIGHT), BOX_LINE_LEFT);
3176 aOldBox.SetLine(0, BOX_LINE_RIGHT);
3177 pBox2->GetFrmFmt()->SetFmtAttr(aOldBox);
3180 pBox->GetFrmFmt()->SetFmtAttr(aCurrentBox);
3182 SetTabVertAlign(pBox, j);
3183 SetTabDirection(pBox, j);
3184 if( pActBand->pSHDs || pActBand->pNewSHDs)
3185 SetTabShades(pBox, j);
3186 j++;
3188 aFS.SetWidth( nW );
3189 pBox->GetFrmFmt()->SetFmtAttr( aFS );
3191 // skip non existing cells
3192 while( ( j < pActBand->nWwCols ) && !pActBand->bExist[j] )
3194 pActBand->nWidth[j] = pActBand->nCenter[j+1] - pActBand->nCenter[j];
3195 j++;
3200 void WW8TabDesc::TableCellEnd()
3202 ::SetProgressState(pIo->nProgress, pIo->mpDocShell); // Update
3204 EndMiserableHackForUnsupportedDirection(nAktCol);
3206 // new line/row
3207 if( pIo->bWasTabRowEnd )
3209 // bWasTabRowEnd will be deactivated in
3210 // SwWW8ImplReader::ProcessSpecial()
3212 sal_uInt16 iCol = GetLogicalWWCol();
3213 if (iCol < aNumRuleNames.size())
3215 aNumRuleNames.erase(aNumRuleNames.begin() + iCol,
3216 aNumRuleNames.end());
3219 nAktCol = 0;
3220 nAktRow++;
3221 nAktBandRow++;
3222 OSL_ENSURE( pActBand , "pActBand ist 0" );
3223 if( pActBand )
3225 if( nAktRow >= nRows ) // nothing to at end of table
3226 return;
3228 bool bNewBand = nAktBandRow >= pActBand->nRows;
3229 if( bNewBand )
3230 { // new band needed ?
3231 pActBand = pActBand->pNextBand;
3232 nAktBandRow = 0;
3233 OSL_ENSURE( pActBand, "pActBand ist 0" );
3234 AdjustNewBand();
3236 else
3238 SwTableBox* pBox = (*pTabBoxes)[0];
3239 SwSelBoxes aBoxes;
3240 pIo->rDoc.InsertRow( pTable->SelLineFromBox( pBox, aBoxes ) );
3244 else
3245 { // new column ( cell )
3246 nAktCol++;
3248 SetPamInCell(nAktCol, true);
3250 // finish Annotated Level Numbering ?
3251 if (pIo->bAnl && !pIo->bAktAND_fNumberAcross)
3252 pIo->StopAllAnl(IsValidCell(nAktCol));
3255 // if necessary register the box for the merge group for this column
3256 SwTableBox* WW8TabDesc::UpdateTableMergeGroup( WW8_TCell& rCell,
3257 WW8SelBoxInfo* pActGroup,
3258 SwTableBox* pActBox,
3259 sal_uInt16 nCol )
3261 // set default for return
3262 SwTableBox* pResult = 0;
3264 // check if the box has to be merged
3265 // If cell is the first one to be merged, a new merge group has to be provided.
3266 // E.g., it could be that a cell is the first one to be merged, but no
3267 // new merge group is provided, because the potential other cell to be merged
3268 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3269 if ( pActBand->bExist[ nCol ] &&
3270 ( ( rCell.bFirstMerged && pActGroup ) ||
3271 rCell.bMerged ||
3272 rCell.bVertMerge ||
3273 rCell.bVertRestart ) )
3275 // detect appropriate merge group
3276 WW8SelBoxInfo* pTheMergeGroup = 0;
3277 if( pActGroup )
3278 // assign group
3279 pTheMergeGroup = pActGroup;
3280 else
3282 // find group
3283 pTheMergeGroup = FindMergeGroup(
3284 pActBand->nCenter[ nCol ], pActBand->nWidth[ nCol ], true );
3286 if( pTheMergeGroup )
3288 // add current box to merge group
3289 pTheMergeGroup->push_back(pActBox);
3290 // return target box
3291 pResult = (*pTheMergeGroup)[ 0 ];
3294 return pResult;
3298 sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3300 sal_uInt16 nCol = 0;
3301 if( pActBand && pActBand->pTCs)
3303 for( sal_uInt16 iCol = 1; iCol <= nAktCol && iCol <= pActBand->nWwCols; ++iCol )
3305 if( !pActBand->pTCs[ iCol-1 ].bMerged )
3306 ++nCol;
3309 return nCol;
3312 // find name of numrule valid for current WW-COL
3313 const String& WW8TabDesc::GetNumRuleName() const
3315 sal_uInt16 nCol = GetLogicalWWCol();
3316 if (nCol < aNumRuleNames.size())
3317 return aNumRuleNames[nCol];
3318 else
3319 return aEmptyStr;
3322 void WW8TabDesc::SetNumRuleName( const String& rName )
3324 sal_uInt16 nCol = GetLogicalWWCol();
3325 for (sal_uInt16 nSize = static_cast< sal_uInt16 >(aNumRuleNames.size()); nSize <= nCol; ++nSize)
3326 aNumRuleNames.push_back(aEmptyStr);
3327 aNumRuleNames[nCol] = rName;
3330 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp)
3332 // Entering a table so make sure the FirstPara flag gets set
3333 bFirstPara = true;
3334 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3335 // Fussnote
3336 if (bReadNoTbl)
3337 return false;
3339 if (pTableDesc)
3340 maTableStack.push(pTableDesc);
3342 // #i33818# - determine absolute position object attributes,
3343 // if possible. It's needed for nested tables.
3344 WW8FlyPara* pTableWFlyPara( 0L );
3345 WW8SwFlyPara* pTableSFlyPara( 0L );
3346 // #i45301# - anchor nested table inside Writer fly frame
3347 // only at-character, if absolute position object attributes are available.
3348 // Thus, default anchor type is as-character anchored.
3349 RndStdIds eAnchor( FLY_AS_CHAR );
3350 if ( nInTable )
3352 WW8_TablePos* pNestedTabPos( 0L );
3353 WW8_TablePos aNestedTabPos;
3354 WW8PLCFxSave1 aSave;
3355 pPlcxMan->GetPap()->Save( aSave );
3356 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
3357 WW8_CP nMyStartCp = nStartCp;
3358 if ( SearchRowEnd( pPap, nMyStartCp, nInTable ) &&
3359 ParseTabPos( &aNestedTabPos, pPap ) )
3361 pNestedTabPos = &aNestedTabPos;
3363 pPlcxMan->GetPap()->Restore( aSave );
3364 if ( pNestedTabPos )
3366 ApoTestResults aApo = TestApo( nInTable + 1, false, pNestedTabPos );
3367 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3368 if ( pTableWFlyPara )
3370 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3371 // containing WW8 page top margin.
3372 pTableSFlyPara = new WW8SwFlyPara(*pPaM, *this, *pTableWFlyPara,
3373 maSectionManager.GetWWPageTopMargin(),
3374 maSectionManager.GetPageLeft(), maSectionManager.GetTextAreaWidth(),
3375 nIniFlyDx, nIniFlyDy);
3377 // #i45301# - anchor nested table Writer fly frame at-character
3378 eAnchor = FLY_AT_CHAR;
3383 pTableDesc = new WW8TabDesc( this, nStartCp );
3385 if( pTableDesc->Ok() )
3387 int nNewInTable = nInTable + 1;
3388 if (InEqualApo(nNewInTable))
3390 OSL_ENSURE(pSFlyPara->pFlyFmt,
3391 "how could we be in a local apo and have no apo");
3394 if ((eAnchor == FLY_AT_CHAR)
3395 && !maTableStack.empty() && !InEqualApo(nNewInTable) )
3397 pTableDesc->pParentPos = new SwPosition(*pPaM->GetPoint());
3398 SfxItemSet aItemSet(rDoc.GetAttrPool(),
3399 RES_FRMATR_BEGIN, RES_FRMATR_END-1);
3400 // #i33818# - anchor the Writer fly frame for the nested table at-character.
3401 // #i45301#
3402 SwFmtAnchor aAnchor( eAnchor );
3403 aAnchor.SetAnchor( pTableDesc->pParentPos );
3404 aItemSet.Put( aAnchor );
3405 pTableDesc->pFlyFmt = rDoc.MakeFlySection( eAnchor,
3406 pTableDesc->pParentPos, &aItemSet);
3407 OSL_ENSURE( pTableDesc->pFlyFmt->GetAnchor().GetAnchorId() == eAnchor,
3408 "Not the anchor type requested!" );
3409 MoveInsideFly(pTableDesc->pFlyFmt);
3411 pTableDesc->CreateSwTable();
3412 if (pTableDesc->pFlyFmt)
3414 pTableDesc->SetSizePosition(pTableDesc->pFlyFmt);
3415 // #i33818# - Use absolute position object attributes,
3416 // if existing, and apply them to the created Writer fly frame.
3417 if ( pTableWFlyPara && pTableSFlyPara )
3419 WW8FlySet aFlySet( *this, pTableWFlyPara, pTableSFlyPara, false );
3420 SwFmtAnchor aAnchor( FLY_AT_CHAR );
3421 aAnchor.SetAnchor( pTableDesc->pParentPos );
3422 aFlySet.Put( aAnchor );
3423 pTableDesc->pFlyFmt->SetFmtAttr( aFlySet );
3425 else
3427 SwFmtHoriOrient aHori =
3428 pTableDesc->pTable->GetFrmFmt()->GetHoriOrient();
3429 pTableDesc->pFlyFmt->SetFmtAttr(aHori);
3430 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtSurround( SURROUND_NONE ) );
3432 // #i33818# - The nested table doesn't have to leave
3433 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3434 pTableDesc->pFlyFmt->SetFmtAttr( SwFmtFollowTextFlow( sal_True ) );
3436 else
3437 pTableDesc->SetSizePosition(0);
3438 pTableDesc->UseSwTable();
3440 else
3441 PopTableDesc();
3443 // #i33818#
3444 delete pTableWFlyPara;
3445 delete pTableSFlyPara;
3447 return 0 != pTableDesc;
3450 void SwWW8ImplReader::TabCellEnd()
3452 if (nInTable && pTableDesc)
3453 pTableDesc->TableCellEnd();
3455 bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3456 bReadTable = false;
3457 mpTableEndPaM.reset();
3460 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16, const sal_uInt8* pData, short nLen)
3462 if( ( nLen > 0 ) && ( *pData == 1 ) )
3463 bWasTabCellEnd = true;
3466 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm25
3468 if( ( nLen > 0 ) && ( *pData == 1 ) )
3469 bWasTabRowEnd = true;
3472 void SwWW8ImplReader::PopTableDesc()
3474 if (pTableDesc && pTableDesc->pFlyFmt)
3476 MoveOutsideFly(pTableDesc->pFlyFmt,*pTableDesc->pParentPos);
3479 delete pTableDesc;
3480 if (maTableStack.empty())
3481 pTableDesc = 0;
3482 else
3484 pTableDesc = maTableStack.top();
3485 maTableStack.pop();
3489 void SwWW8ImplReader::StopTable()
3491 OSL_ENSURE(pTableDesc, "Panic, stop table with no table!");
3492 if (!pTableDesc)
3493 return;
3495 // We are leaving a table so make sure the next paragraph doesn't think
3496 // it's the first paragraph
3497 bFirstPara = false;
3499 pTableDesc->FinishSwTable();
3500 PopTableDesc();
3502 bReadTable = true;
3503 // #i101116# - Keep PaM on table end only for nested tables
3504 if ( nInTable > 1 )
3506 mpTableEndPaM.reset(new SwPaM(*pPaM));
3510 // GetTableLeft() is needed for graphic objects bound to paragraphs in tables.
3511 // For indented tables the base for WW is the margin that would be used without
3512 // the table; SW uses the left table margin.
3513 short SwWW8ImplReader::GetTableLeft()
3515 return (pTableDesc) ? pTableDesc->GetMinLeft() : 0;
3518 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3520 if( !pTableDesc )
3521 return false;
3523 const WW8_TCell* pCell = pTableDesc->GetAktWWCell();
3525 return !pTableDesc->IsValidCell( pTableDesc->GetAktCol() )
3526 || ( pCell
3527 && ( !pCell->bFirstMerged
3528 && ( pCell->bMerged
3529 || ( pCell->bVertMerge
3530 && !pCell->bVertRestart
3537 sal_uInt16 SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex ) const
3539 sal_uInt16 nRes = USHRT_MAX;
3540 if( !vColl.empty() )
3542 for(sal_uInt16 nI = 0; nI < pStyles->GetCount(); nI++ )
3543 if( vColl[ nI ].bValid
3544 && (nLFOIndex == vColl[ nI ].nLFOIndex) )
3545 nRes = nI;
3547 return nRes;
3550 const SwFmt* SwWW8ImplReader::GetStyleWithOrgWWName( String& rName ) const
3552 SwFmt* pRet = 0;
3553 if( !vColl.empty() )
3555 for(sal_uInt16 nI = 0; nI < pStyles->GetCount(); nI++ )
3556 if( vColl[ nI ].bValid
3557 && (rName.Equals( vColl[ nI ].GetOrgWWName())) )
3559 pRet = vColl[ nI ].pFmt;
3560 break;
3563 return pRet;
3566 //-----------------------------------------
3567 // class WW8RStyle
3568 //-----------------------------------------
3570 const sal_uInt8* WW8RStyle::HasParaSprm( sal_uInt16 nId ) const
3572 if( !pParaSprms || !nSprmsLen )
3573 return 0;
3575 return maSprmParser.findSprmData(nId, pParaSprms, nSprmsLen);
3578 void WW8RStyle::ImportSprms(sal_uInt8 *pSprms, short nLen, bool bPap)
3580 if (!nLen)
3581 return;
3583 if( bPap )
3585 pParaSprms = pSprms; // for HasParaSprms()
3586 nSprmsLen = nLen;
3589 WW8SprmIter aSprmIter(pSprms, nLen, maSprmParser);
3590 while (const sal_uInt8* pSprm = aSprmIter.GetSprms())
3592 pIo->ImportSprm(pSprm);
3593 aSprmIter.advance();
3596 pParaSprms = 0;
3597 nSprmsLen = 0;
3600 void WW8RStyle::ImportSprms(sal_Size nPosFc, short nLen, bool bPap)
3602 if (!nLen)
3603 return;
3605 if (checkSeek(*pStStrm, nPosFc))
3607 sal_uInt8 *pSprms = new sal_uInt8[nLen];
3608 nLen = pStStrm->Read(pSprms, nLen);
3609 ImportSprms(pSprms, nLen, bPap);
3610 delete[] pSprms;
3614 static inline short WW8SkipOdd(SvStream* pSt )
3616 if ( pSt->Tell() & 0x1 )
3618 sal_uInt8 c;
3619 return pSt->Read( &c, 1 );
3621 return 0;
3624 static inline short WW8SkipEven(SvStream* pSt )
3626 if (!(pSt->Tell() & 0x1))
3628 sal_uInt8 c;
3629 return pSt->Read( &c, 1 );
3631 return 0;
3634 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3636 if( 0 < nLen ) // Empty ?
3638 if (bOdd)
3639 nLen = nLen - WW8SkipEven( pStStrm );
3640 else
3641 nLen = nLen - WW8SkipOdd( pStStrm );
3643 sal_Int16 cbUPX(0);
3644 *pStStrm >> cbUPX;
3646 nLen-=2;
3648 if ( cbUPX > nLen )
3649 cbUPX = nLen; // shrink cbUPX to nLen
3651 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3653 if( bPAP )
3655 sal_uInt16 id;
3656 *pStStrm >> id;
3658 cbUPX-= 2;
3659 nLen-= 2;
3662 if( 0 < cbUPX )
3664 sal_Size nPos = pStStrm->Tell(); // if something is interpreted wrong,
3665 // this should make it work again
3666 ImportSprms( nPos, cbUPX, bPAP );
3668 if ( pStStrm->Tell() != nPos + cbUPX )
3669 pStStrm->Seek( nPos+cbUPX );
3671 nLen = nLen - cbUPX;
3675 return nLen;
3678 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3680 if( nLen <= 0 )
3681 return;
3682 if (bOdd)
3683 nLen = nLen - WW8SkipEven( pStStrm );
3684 else
3685 nLen = nLen - WW8SkipOdd( pStStrm );
3687 if( bPara ) // Grupx.Papx
3688 nLen = ImportUPX(nLen, true, bOdd);
3689 ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3692 WW8RStyle::WW8RStyle(WW8Fib& _rFib, SwWW8ImplReader* pI)
3693 : WW8Style(*pI->pTableStream, _rFib), maSprmParser(_rFib.GetFIBVersion()),
3694 pIo(pI), pStStrm(pI->pTableStream), pStyRule(0), nWwNumLevel(0)
3696 pIo->vColl.resize(cstd);
3699 void WW8RStyle::Set1StyleDefaults()
3701 // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3702 if (!bCJKFontChanged) // Style no CJK Font? set the default
3703 pIo->SetNewFontAttr(ftcFE, true, RES_CHRATR_CJK_FONT);
3705 if (!bCTLFontChanged) // Style no CTL Font? set the default
3706 pIo->SetNewFontAttr(ftcBi, true, RES_CHRATR_CTL_FONT);
3708 // western 2nd to make western charset conversion the default
3709 if (!bFontChanged) // Style has no Font? set the default,
3710 pIo->SetNewFontAttr(ftcAsci, true, RES_CHRATR_FONT);
3712 if( !pIo->bNoAttrImport )
3714 // Style has no text color set, winword default is auto
3715 if ( !bTxtColChanged )
3716 pIo->pAktColl->SetFmtAttr(SvxColorItem(Color(COL_AUTO), RES_CHRATR_COLOR));
3718 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3719 if( !bFSizeChanged )
3721 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3722 pIo->pAktColl->SetFmtAttr(aAttr);
3723 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3724 pIo->pAktColl->SetFmtAttr(aAttr);
3727 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3728 if( !bFCTLSizeChanged )
3730 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3731 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3732 pIo->pAktColl->SetFmtAttr(aAttr);
3735 if( pIo->pWDop->fWidowControl && !bWidowsChanged ) // Widows ?
3737 pIo->pAktColl->SetFmtAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS ) );
3738 pIo->pAktColl->SetFmtAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS ) );
3743 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3745 SwFmt* pColl;
3746 bool bStyExist;
3748 if (rSI.bColl)
3750 // Para-Style
3751 sw::util::ParaStyleMapper::StyleResult aResult =
3752 pIo->maParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3753 pColl = aResult.first;
3754 bStyExist = aResult.second;
3756 else
3758 // Char-Style
3759 sw::util::CharStyleMapper::StyleResult aResult =
3760 pIo->maCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti);
3761 pColl = aResult.first;
3762 bStyExist = aResult.second;
3765 bool bImport = !bStyExist || pIo->mbNewDoc; // import content ?
3767 // Do not override character styles the list import code created earlier.
3768 if (bImport && bStyExist && rSI.GetOrgWWName().SearchAscii("WW8Num") == 0)
3769 bImport = false;
3771 bool bOldNoImp = pIo->bNoAttrImport;
3772 rSI.bImportSkipped = !bImport;
3774 if( !bImport )
3775 pIo->bNoAttrImport = true;
3776 else
3778 if (bStyExist)
3780 pColl->ResetAllFmtAttr(); // #i73790# - method renamed
3782 pColl->SetAuto(false); // suggested by JP
3783 } // but changes the UI
3784 pIo->pAktColl = pColl;
3785 rSI.pFmt = pColl; // remember translation WW->SW
3786 rSI.bImportSkipped = !bImport;
3788 // Set Based on style
3789 sal_uInt16 j = rSI.nBase;
3790 if (j != nThisStyle && j < cstd )
3792 SwWW8StyInf* pj = &pIo->vColl[j];
3793 if (rSI.pFmt && pj->pFmt && rSI.bColl == pj->bColl)
3795 rSI.pFmt->SetDerivedFrom( pj->pFmt ); // ok, set Based on
3796 rSI.eLTRFontSrcCharSet = pj->eLTRFontSrcCharSet;
3797 rSI.eRTLFontSrcCharSet = pj->eRTLFontSrcCharSet;
3798 rSI.eCJKFontSrcCharSet = pj->eCJKFontSrcCharSet;
3799 rSI.n81Flags = pj->n81Flags;
3800 rSI.n81BiDiFlags = pj->n81BiDiFlags;
3801 rSI.nOutlineLevel = pj->nOutlineLevel;
3802 rSI.bParaAutoBefore = pj->bParaAutoBefore;
3803 rSI.bParaAutoAfter = pj->bParaAutoAfter;
3805 if (pj->pWWFly)
3806 rSI.pWWFly = new WW8FlyPara(pIo->bVer67, pj->pWWFly);
3809 else if( pIo->mbNewDoc && bStyExist )
3810 rSI.pFmt->SetDerivedFrom(0);
3812 rSI.nFollow = nNextStyle; // remember Follow
3814 pStyRule = 0; // recreate if necessary
3815 bTxtColChanged = bFontChanged = bCJKFontChanged = bCTLFontChanged =
3816 bFSizeChanged = bFCTLSizeChanged = bWidowsChanged = false;
3817 pIo->SetNAktColl( nThisStyle );
3818 pIo->bStyNormal = nThisStyle == 0;
3819 return bOldNoImp;
3822 void WW8RStyle::PostStyle(SwWW8StyInf &rSI, bool bOldNoImp)
3824 // Reset attribute flags, because there are no style-ends.
3826 pIo->bHasBorder = pIo->bShdTxtCol = pIo->bCharShdTxtCol
3827 = pIo->bSpec = pIo->bObj = pIo->bSymbol = false;
3828 pIo->nCharFmt = -1;
3830 // If Style basiert auf Nichts oder Basis ignoriert
3831 if ((rSI.nBase >= cstd || pIo->vColl[rSI.nBase].bImportSkipped) && rSI.bColl)
3833 // If Char-Styles does not work
3834 // -> set hard WW-Defaults
3835 Set1StyleDefaults();
3838 pStyRule = 0; // to be on the safe side
3839 pIo->bStyNormal = false;
3840 pIo->SetNAktColl( 0 );
3841 pIo->bNoAttrImport = bOldNoImp;
3842 // reset the list-remember-fields, if used when reading styles
3843 pIo->nLFOPosition = USHRT_MAX;
3844 pIo->nListLevel = WW8ListManager::nMaxLevel;
3847 void WW8RStyle::Import1Style( sal_uInt16 nNr )
3849 if (nNr >= pIo->vColl.size())
3850 return;
3852 SwWW8StyInf &rSI = pIo->vColl[nNr];
3854 if( rSI.bImported || !rSI.bValid )
3855 return;
3857 rSI.bImported = true; // set flag now to avoid endless loops
3859 // valid and not NUL and not yet imported
3861 if( rSI.nBase < cstd && !pIo->vColl[rSI.nBase].bImported )
3862 Import1Style( rSI.nBase );
3864 pStStrm->Seek( rSI.nFilePos );
3866 short nSkip, cbStd;
3867 String sName;
3869 boost::scoped_ptr<WW8_STD> xStd(Read1Style(nSkip, &sName, &cbStd));// read Style
3871 if (xStd)
3872 rSI.SetOrgWWIdent( sName, xStd->sti );
3874 // either no Name or unused Slot or unknown Style
3876 if ( !xStd || (0 == sName.Len()) || ((1 != xStd->sgc) && (2 != xStd->sgc)) )
3878 pStStrm->SeekRel( nSkip );
3879 return;
3882 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(xStd->sti), nNr, xStd->istdNext);
3884 // if something is interpreted wrong, this should make it work again
3885 long nPos = pStStrm->Tell();
3887 //Variable parts of the STD start at even byte offsets, but "inside
3888 //the STD", which I take to meaning even in relation to the starting
3889 //position of the STD, which matches findings in #89439#, generally it
3890 //doesn't matter as the STSHI starts off nearly always on an even
3891 //offset
3893 //Import of the Style Contents
3894 ImportGrupx(nSkip, xStd->sgc == 1, rSI.nFilePos & 1);
3896 PostStyle(rSI, bOldNoImp);
3898 pStStrm->Seek( nPos+nSkip );
3901 void WW8RStyle::RecursiveReg(sal_uInt16 nNr)
3903 if (nNr >= pIo->vColl.size())
3904 return;
3906 SwWW8StyInf &rSI = pIo->vColl[nNr];
3907 if( rSI.bImported || !rSI.bValid )
3908 return;
3910 rSI.bImported = true;
3912 if( rSI.nBase < cstd && !pIo->vColl[rSI.nBase].bImported )
3913 RecursiveReg(rSI.nBase);
3915 pIo->RegisterNumFmtOnStyle(nNr);
3920 After all styles are imported then we can recursively apply numbering
3921 styles to them, and change their tab stop settings if they turned out
3922 to have special first line indentation.
3924 void WW8RStyle::PostProcessStyles()
3926 sal_uInt16 i;
3928 Clear all imported flags so that we can recursively apply numbering
3929 formats and use it to mark handled ones
3931 for (i=0; i < cstd; ++i)
3932 pIo->vColl[i].bImported = false;
3935 Register the num formats and tabstop changes on the styles recursively.
3939 In the same loop apply the tabstop changes required because we need to
3940 change their location if theres a special indentation for the first line,
3941 By avoiding making use of each styles margins during reading of their
3942 tabstops we don't get problems with doubly adjusting tabstops that
3943 are inheritied.
3945 for (i=0; i < cstd; ++i)
3947 if (pIo->vColl[i].bValid)
3949 RecursiveReg(i);
3954 void WW8RStyle::ScanStyles() // investigate style dependencies
3955 { // and detect Filepos for each Style
3956 for (sal_uInt16 i = 0; i < cstd; ++i)
3958 short nSkip;
3959 SwWW8StyInf &rSI = pIo->vColl[i];
3961 rSI.nFilePos = pStStrm->Tell(); // remember FilePos
3962 WW8_STD* pStd = Read1Style( nSkip, 0, 0 ); // read STD
3963 rSI.bValid = (0 != pStd);
3964 if (rSI.bValid)
3966 rSI.nBase = pStd->istdBase; // remember Basis
3967 rSI.bColl = ( pStd->sgc == 1 ); // Para-Style
3969 else
3970 rSI = SwWW8StyInf();
3972 delete pStd;
3973 pStStrm->SeekRel( nSkip ); // skip Names and Sprms
3977 std::vector<sal_uInt8> ChpxToSprms(const Word2CHPX &rChpx)
3979 std::vector<sal_uInt8> aRet;
3981 aRet.push_back(60);
3982 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBold) );
3984 aRet.push_back(61);
3985 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalic) );
3987 aRet.push_back(62);
3988 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fStrike) );
3990 aRet.push_back(63);
3991 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fOutline) );
3993 aRet.push_back(65);
3994 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fSmallCaps) );
3996 aRet.push_back(66);
3997 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fCaps) );
3999 aRet.push_back(67);
4000 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fVanish) );
4002 if (rChpx.fsFtc)
4004 aRet.push_back(68);
4005 SVBT16 a;
4006 ShortToSVBT16(rChpx.ftc, a);
4007 aRet.push_back(a[1]);
4008 aRet.push_back(a[0]);
4011 if (rChpx.fsKul)
4013 aRet.push_back(69);
4014 aRet.push_back(rChpx.kul);
4017 if (rChpx.fsLid)
4019 aRet.push_back(72);
4020 SVBT16 a;
4021 ShortToSVBT16(rChpx.lid, a);
4022 aRet.push_back(a[1]);
4023 aRet.push_back(a[0]);
4026 if (rChpx.fsIco)
4028 aRet.push_back(73);
4029 aRet.push_back(rChpx.ico);
4032 if (rChpx.fsHps)
4034 aRet.push_back(74);
4036 SVBT16 a;
4037 ShortToSVBT16(rChpx.hps, a);
4038 aRet.push_back(a[0]);
4041 if (rChpx.fsPos)
4043 aRet.push_back(76);
4044 aRet.push_back(rChpx.hpsPos);
4047 aRet.push_back(80);
4048 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBoldBi) );
4050 aRet.push_back(81);
4051 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalicBi) );
4053 if (rChpx.fsFtcBi)
4055 aRet.push_back(82);
4056 SVBT16 a;
4057 ShortToSVBT16(rChpx.fsFtcBi, a);
4058 aRet.push_back(a[1]);
4059 aRet.push_back(a[0]);
4062 if (rChpx.fsLidBi)
4064 aRet.push_back(83);
4065 SVBT16 a;
4066 ShortToSVBT16(rChpx.lidBi, a);
4067 aRet.push_back(a[1]);
4068 aRet.push_back(a[0]);
4071 if (rChpx.fsIcoBi)
4073 aRet.push_back(84);
4074 aRet.push_back(rChpx.icoBi);
4077 if (rChpx.fsHpsBi)
4079 aRet.push_back(85);
4080 SVBT16 a;
4081 ShortToSVBT16(rChpx.hpsBi, a);
4082 aRet.push_back(a[1]);
4083 aRet.push_back(a[0]);
4086 return aRet;
4089 Word2CHPX ReadWord2Chpx(SvStream &rSt, sal_Size nOffset, sal_uInt8 nSize)
4091 Word2CHPX aChpx;
4093 if (!nSize)
4094 return aChpx;
4096 rSt.Seek(nOffset);
4098 sal_uInt8 nCount=0;
4100 while (1)
4102 sal_uInt8 nFlags8;
4103 rSt >> nFlags8;
4104 nCount++;
4106 aChpx.fBold = nFlags8 & 0x01;
4107 aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4108 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4109 aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4110 aChpx.fFldVanish = (nFlags8 & 0x10) >> 4;
4111 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4112 aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4113 aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4115 if (nCount >= nSize) break;
4116 rSt >> nFlags8;
4117 nCount++;
4119 aChpx.fRMark = nFlags8 & 0x01;
4120 aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4121 aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4122 aChpx.fObj = (nFlags8 & 0x08) >> 3;
4123 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4124 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4125 aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4126 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4128 if (nCount >= nSize) break;
4129 rSt >> nFlags8;
4130 nCount++;
4132 aChpx.fsIco = nFlags8 & 0x01;
4133 aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4134 aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4135 aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4136 aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4137 aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4138 aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4139 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4141 if (nCount >= nSize) break;
4142 rSt >> nFlags8;
4143 nCount++;
4145 aChpx.fsFtcBi = nFlags8 & 0x01;
4146 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4147 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4149 if (nCount >= nSize) break;
4150 rSt >> aChpx.ftc;
4151 nCount+=2;
4153 if (nCount >= nSize) break;
4154 rSt >> aChpx.hps;
4155 nCount+=2;
4157 if (nCount >= nSize) break;
4158 rSt >> nFlags8;
4159 nCount++;
4161 aChpx.qpsSpace = nFlags8 & 0x3F;
4162 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4163 aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4165 if (nCount >= nSize) break;
4166 rSt >> nFlags8;
4167 nCount++;
4169 aChpx.ico = nFlags8 & 0x1F;
4170 aChpx.kul = (nFlags8 & 0xE0) >> 5;
4172 if (nCount >= nSize) break;
4173 rSt >> aChpx.hpsPos;
4174 nCount++;
4176 if (nCount >= nSize) break;
4177 rSt >> aChpx.icoBi;
4178 nCount++;
4180 if (nCount >= nSize) break;
4181 rSt >> aChpx.lid;
4182 nCount+=2;
4184 if (nCount >= nSize) break;
4185 rSt >> aChpx.ftcBi;
4186 nCount+=2;
4188 if (nCount >= nSize) break;
4189 rSt >> aChpx.hpsBi;
4190 nCount+=2;
4192 if (nCount >= nSize) break;
4193 rSt >> aChpx.lidBi;
4194 nCount+=2;
4196 if (nCount >= nSize) break;
4197 rSt >> aChpx.fcPic;
4198 nCount+=4;
4200 break;
4203 rSt.SeekRel(nSize-nCount);
4204 return aChpx;
4207 namespace
4209 struct pxoffset { sal_Size mnOffset; sal_uInt8 mnSize; };
4212 void WW8RStyle::ImportOldFormatStyles()
4214 for (sal_uInt16 i=0; i < cstd; ++i)
4216 pIo->vColl[i].bColl = true;
4217 //every chain must end eventually at the null style (style code 222)
4218 pIo->vColl[i].nBase = 222;
4221 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4222 pIo->pWwFib->chseTables);
4224 sal_uInt16 cstcStd;
4225 rSt >> cstcStd;
4227 sal_uInt16 cbName;
4228 rSt >> cbName;
4229 sal_uInt16 nByteCount = 2;
4230 sal_uInt16 stcp=0;
4231 while (nByteCount < cbName)
4233 sal_uInt8 nCount;
4234 rSt >> nCount;
4235 nByteCount++;
4237 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4238 if (stc >=pIo->vColl.size())
4239 continue;
4241 SwWW8StyInf &rSI = pIo->vColl[stc];
4242 if (nCount != 0xFF) // undefined style
4244 String sName;
4245 if (nCount == 0) // inbuilt style
4247 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4248 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4249 sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4250 else
4251 sName = OUString("Unknown");
4253 else // user style
4255 OString aTmp = read_uInt8s_ToOString(rSt, nCount);
4256 nByteCount += aTmp.getLength();
4257 sName = OStringToOUString(aTmp, eStructChrSet);
4259 rSI.SetOrgWWIdent(sName, stc);
4260 rSI.bImported = true;
4262 else
4264 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4265 if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4267 String sName = String(pStr, RTL_TEXTENCODING_ASCII_US);
4268 rSI.SetOrgWWIdent(sName, stc);
4271 stcp++;
4274 sal_uInt16 nStyles=stcp;
4276 std::vector<pxoffset> aCHPXOffsets(stcp);
4277 sal_uInt16 cbChpx;
4278 rSt >> cbChpx;
4279 nByteCount = 2;
4280 stcp=0;
4281 std::vector< std::vector<sal_uInt8> > aConvertedChpx;
4282 while (nByteCount < cbChpx)
4284 sal_uInt8 cb;
4285 rSt >> cb;
4286 nByteCount++;
4288 aCHPXOffsets[stcp].mnSize = 0;
4290 if (cb != 0xFF)
4292 sal_uInt8 nRemainder = cb;
4294 aCHPXOffsets[stcp].mnOffset = rSt.Tell();
4295 aCHPXOffsets[stcp].mnSize = nRemainder;
4297 Word2CHPX aChpx = ReadWord2Chpx(rSt, aCHPXOffsets[stcp].mnOffset,
4298 aCHPXOffsets[stcp].mnSize);
4299 aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4301 nByteCount += nRemainder;
4303 else
4304 aConvertedChpx.push_back( std::vector<sal_uInt8>() );
4306 stcp++;
4307 if (stcp == nStyles)
4309 rSt.SeekRel(cbChpx-nByteCount);
4310 nByteCount += cbChpx-nByteCount;
4314 std::vector<pxoffset> aPAPXOffsets(stcp);
4315 sal_uInt16 cbPapx;
4316 rSt >> cbPapx;
4317 nByteCount = 2;
4318 stcp=0;
4319 while (nByteCount < cbPapx)
4321 sal_uInt8 cb;
4322 rSt >> cb;
4323 nByteCount++;
4325 aPAPXOffsets[stcp].mnSize = 0;
4327 if (cb != 0xFF)
4329 sal_uInt8 stc2;
4330 rSt >> stc2;
4331 rSt.SeekRel(6);
4332 nByteCount+=7;
4333 sal_uInt8 nRemainder = cb-7;
4335 aPAPXOffsets[stcp].mnOffset = rSt.Tell();
4336 aPAPXOffsets[stcp].mnSize = nRemainder;
4338 rSt.SeekRel(nRemainder);
4339 nByteCount += nRemainder;
4342 stcp++;
4344 if (stcp == nStyles)
4346 rSt.SeekRel(cbPapx-nByteCount);
4347 nByteCount += cbPapx-nByteCount;
4351 sal_uInt16 iMac;
4352 rSt >> iMac;
4354 if (iMac > nStyles) iMac = nStyles;
4356 for (stcp = 0; stcp < iMac; ++stcp)
4358 sal_uInt8 stcNext, stcBase;
4359 rSt >> stcNext;
4360 rSt >> stcBase;
4362 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4365 #i64557# style based on itself
4366 every chain must end eventually at the null style (style code 222)
4368 if (stc == stcBase)
4369 stcBase = 222;
4371 SwWW8StyInf &rSI = pIo->vColl[stc];
4372 rSI.nBase = stcBase;
4374 ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4376 if (eSti == ww::stiNil)
4377 continue;
4379 rSI.bValid = true;
4381 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4382 pIo->vColl[stc].bColl = false;
4384 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4386 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4387 true);
4389 if (aConvertedChpx[stcp].size() > 0)
4390 ImportSprms(&(aConvertedChpx[stcp][0]),
4391 static_cast< short >(aConvertedChpx[stcp].size()),
4392 false);
4394 PostStyle(rSI, bOldNoImp);
4398 void WW8RStyle::ImportNewFormatStyles()
4400 ScanStyles(); // Scan Based On
4402 for (sal_uInt16 i = 0; i < cstd; ++i) // import Styles
4403 if (pIo->vColl[i].bValid)
4404 Import1Style( i );
4407 void WW8RStyle::ImportStyles()
4409 if (ww::eWW2 == pIo->pWwFib->GetFIBVersion())
4410 ImportOldFormatStyles();
4411 else
4412 ImportNewFormatStyles();
4415 void WW8RStyle::Import()
4417 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4418 pIo->pStandardFmtColl =
4419 pIo->rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
4421 if( pIo->nIniFlags & WW8FL_NO_STYLES )
4422 return;
4424 ImportStyles();
4426 for (sal_uInt16 i = 0; i < cstd; ++i)
4428 // Follow chain
4429 SwWW8StyInf* pi = &pIo->vColl[i];
4430 sal_uInt16 j = pi->nFollow;
4431 if( j < cstd )
4433 SwWW8StyInf* pj = &pIo->vColl[j];
4434 if ( j != i // rational Index ?
4435 && pi->pFmt // Format ok ?
4436 && pj->pFmt // Derived-Format ok ?
4437 && pi->bColl // only possible for paragraph templates (WW)
4438 && pj->bColl ){ // identical Typ ?
4439 ( (SwTxtFmtColl*)pi->pFmt )->SetNextTxtFmtColl(
4440 *(SwTxtFmtColl*)pj->pFmt ); // ok, register
4445 // Missing special handling for default character template
4446 // "Absatz-Standardschriftart" ( Style-ID 65 ).
4447 // That is empty by default ( WW6 dt and US ) and not changeable
4448 // via WW-UI so this does not matter.
4449 // This could be done by:
4450 // if( bNew ) rDoc.SetDefault( pDefCharFmt->GetAttrSet() );
4452 // for e.g. tables an always valid Std-Style is necessary
4454 if( pIo->StyleExists(0) && !pIo->vColl.empty() &&
4455 pIo->vColl[0].pFmt && pIo->vColl[0].bColl && pIo->vColl[0].bValid )
4456 pIo->pDfltTxtFmtColl = (SwTxtFmtColl*)pIo->vColl[0].pFmt;
4457 else
4458 pIo->pDfltTxtFmtColl = pIo->rDoc.GetDfltTxtFmtColl();
4461 // set Hyphenation flag on BASIC para-style
4462 if (pIo->mbNewDoc && pIo->pStandardFmtColl)
4464 if (pIo->pWDop->fAutoHyphen
4465 && SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(
4466 RES_PARATR_HYPHENZONE, false) )
4468 SvxHyphenZoneItem aAttr(true, RES_PARATR_HYPHENZONE);
4469 aAttr.GetMinLead() = 2;
4470 aAttr.GetMinTrail() = 2;
4471 aAttr.GetMaxHyphens() = 0;
4473 pIo->pStandardFmtColl->SetFmtAttr( aAttr );
4477 Word defaults to ltr not from environment like writer. Regardless of
4478 the page/sections rtl setting the standard style lack of rtl still
4479 means ltr
4481 if (SFX_ITEM_SET != pIo->pStandardFmtColl->GetItemState(RES_FRAMEDIR,
4482 false))
4484 pIo->pStandardFmtColl->SetFmtAttr(
4485 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR));
4489 // we do not read styles anymore:
4490 pIo->pAktColl = 0;
4493 CharSet SwWW8StyInf::GetCharSet() const
4495 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4496 return eRTLFontSrcCharSet;
4497 return eLTRFontSrcCharSet;
4500 CharSet SwWW8StyInf::GetCJKCharSet() const
4502 if ((pFmt) && (pFmt->GetFrmDir().GetValue() == FRMDIR_HORI_RIGHT_TOP))
4503 return eRTLFontSrcCharSet;
4504 return eCJKFontSrcCharSet;
4507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */