1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
22 #include <comphelper/string.hxx>
23 #include <tools/solar.h>
24 #include <vcl/vclenum.hxx>
25 #include <vcl/font.hxx>
26 #include <hintids.hxx>
27 #include <editeng/colritem.hxx>
28 #include <editeng/orphitem.hxx>
29 #include <editeng/widwitem.hxx>
30 #include <editeng/brushitem.hxx>
31 #include <editeng/boxitem.hxx>
32 #include <editeng/lrspitem.hxx>
33 #include <editeng/ulspitem.hxx>
34 #include <editeng/fhgtitem.hxx>
35 #include <editeng/hyphenzoneitem.hxx>
36 #include <editeng/frmdiritem.hxx>
37 #include <editeng/langitem.hxx>
38 #include <editeng/charrotateitem.hxx>
39 #include <editeng/pgrditem.hxx>
40 #include <msfilter.hxx>
43 #include <IDocumentStylePoolAccess.hxx>
47 #include <poolfmt.hxx>
48 #include <swtable.hxx>
51 #include <fmtpdsc.hxx>
56 #include <fmtlsplt.hxx>
57 #include <charfmt.hxx>
58 #include <SwStyleNameMapper.hxx>
59 #include <fltshell.hxx>
60 #include <fmtanchr.hxx>
61 #include <fmtrowsplt.hxx>
62 #include <fmtfollowtextflow.hxx>
63 #include <numrule.hxx>
64 #include <sprmids.hxx>
65 #include <wwstyles.hxx>
66 #include "writerhelper.hxx"
67 #include "ww8struc.hxx"
69 #include "ww8par2.hxx"
76 using namespace ::com::sun::star
;
78 // Gets filled in WW8TabDesc::MergeCells().
79 // Algorithm must ensure proper row and column order in WW8SelBoxInfo!
83 std::vector
<std::vector
<SwTableBox
*> > m_vRows
;
85 WW8SelBoxInfo(WW8SelBoxInfo
const&) = delete;
86 WW8SelBoxInfo
& operator=(WW8SelBoxInfo
const&) = delete;
93 WW8SelBoxInfo(short nXCenter
, short nWidth
)
94 : nGroupXStart( nXCenter
), nGroupWidth( nWidth
), bGroupLocked(false)
100 for (auto& it
: m_vRows
)
101 nResult
+= it
.size();
105 size_t rowsCount() const { return m_vRows
.size(); }
107 const std::vector
<SwTableBox
*>& row( size_t nIndex
) { return m_vRows
[nIndex
]; }
109 void push_back( SwTableBox
* pBox
)
112 for (auto& iRow
: m_vRows
)
113 if (iRow
[0]->GetUpper() == pBox
->GetUpper())
115 iRow
.push_back(pBox
);
121 const size_t sz
= m_vRows
.size();
122 m_vRows
.resize(sz
+1);
123 m_vRows
[sz
].push_back(pBox
);
128 WW8TabBandDesc::WW8TabBandDesc()
130 memset(this, 0, sizeof(*this));
131 for (sal_uInt16
& rn
: maDirections
)
135 WW8TabBandDesc::~WW8TabBandDesc()
144 std::vector
<OUString
> m_aNumRuleNames
;
145 sw::util::RedlineStack
*mpOldRedlineStack
;
147 SwWW8ImplReader
* m_pIo
;
149 WW8TabBandDesc
* m_pFirstBand
;
150 WW8TabBandDesc
* m_pActBand
;
152 SwPosition
* m_pTmpPos
;
154 SwTableNode
* m_pTableNd
; // table node
155 const SwTableLines
* m_pTabLines
; // row array of node
156 SwTableLine
* m_pTabLine
; // current row
157 SwTableBoxes
* m_pTabBoxes
; // boxes array in current row
158 SwTableBox
* m_pTabBox
; // current cell
160 std::vector
<std::unique_ptr
<WW8SelBoxInfo
>> m_MergeGroups
; // list of all cells to be merged
162 WW8_TCell
* m_pAktWWCell
;
165 short m_nDefaultSwCols
;
168 short m_nConvertedLeft
;
171 short m_nPreferredWidth
;
175 bool m_bClaimLineFormat
;
178 // 2. common admin info
180 short m_nAktBandRow
; // SW: row of current band
181 // 3. admin info for writer
184 sal_uInt16 m_nRowsToRepeat
;
188 sal_uInt16
GetLogicalWWCol() const;
189 void SetTabBorders( SwTableBox
* pBox
, short nIdx
);
190 void SetTabShades( SwTableBox
* pBox
, short nWwIdx
);
191 void SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
);
192 void SetTabDirection( SwTableBox
* pBox
, short nWwIdx
);
194 void SetPamInCell(short nWwCol
, bool bPam
);
195 void InsertCells( short nIns
);
196 void AdjustNewBand();
198 WW8SelBoxInfo
* FindMergeGroup(short nX1
, short nWidth
, bool bExact
);
200 // single box - maybe used in a merge group
201 // (the merge groups are processed later at once)
202 void UpdateTableMergeGroup(WW8_TCell
& rCell
,
203 WW8SelBoxInfo
* pActGroup
, SwTableBox
* pActBox
, sal_uInt16 nCol
);
204 void StartMiserableHackForUnsupportedDirection(short nWwCol
);
205 void EndMiserableHackForUnsupportedDirection(short nWwCol
);
207 WW8TabDesc(WW8TabDesc
const&) = delete;
208 WW8TabDesc
& operator=(WW8TabDesc
const&) = delete;
211 const SwTable
* m_pTable
; // table
212 SwPosition
* m_pParentPos
;
213 SwFlyFrameFormat
* m_pFlyFormat
;
214 SfxItemSet m_aItemSet
;
215 bool IsValidCell(short nCol
) const;
216 bool InFirstParaInCell() const;
218 WW8TabDesc( SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
);
219 bool Ok() const { return m_bOk
; }
220 void CreateSwTable();
222 void SetSizePosition(SwFrameFormat
* pFrameFormat
);
224 void MoveOutsideTable();
226 void FinishSwTable();
228 short GetMinLeft() const { return m_nConvertedLeft
; }
231 const WW8_TCell
* GetAktWWCell() const { return m_pAktWWCell
; }
232 short GetAktCol() const { return m_nAktCol
; }
233 // find name of numrule valid for current WW-COL
234 OUString
GetNumRuleName() const;
235 void SetNumRuleName( const OUString
& rName
);
237 sw::util::RedlineStack
* getOldRedlineStack(){ return mpOldRedlineStack
; }
240 void sw::util::RedlineStack::close( const SwPosition
& rPos
,
241 RedlineType_t eType
, WW8TabDesc
* pTabDesc
)
243 // If the redline type is not found in the redline stack, we have to check if there has been
244 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
245 if( !close( rPos
, eType
) )
247 if( pTabDesc
&& pTabDesc
->getOldRedlineStack() )
250 pTabDesc
->getOldRedlineStack()->close(rPos
, eType
);
251 OSL_ENSURE( bResult
, "close without open!");
252 (void) bResult
; // unused in non-debug
257 void wwSectionManager::SetCurrentSectionHasFootnote()
259 OSL_ENSURE(!maSegments
.empty(),
260 "should not be possible, must be at least one segment");
261 if (!maSegments
.empty())
262 maSegments
.back().mbHasFootnote
= true;
265 void wwSectionManager::SetCurrentSectionVerticalAdjustment(const drawing::TextVerticalAdjust nVA
)
267 OSL_ENSURE(!maSegments
.empty(),
268 "should not be possible, must be at least one segment");
269 if ( !maSegments
.empty() )
270 maSegments
.back().mnVerticalAdjustment
= nVA
;
273 bool wwSectionManager::CurrentSectionIsVertical() const
275 OSL_ENSURE(!maSegments
.empty(),
276 "should not be possible, must be at least one segment");
277 if (!maSegments
.empty())
278 return maSegments
.back().IsVertical();
282 bool wwSectionManager::CurrentSectionIsProtected() const
284 OSL_ENSURE(!maSegments
.empty(),
285 "should not be possible, must be at least one segment");
286 if (!maSegments
.empty())
287 return SectionIsProtected(maSegments
.back());
291 sal_uInt32
wwSectionManager::GetPageLeft() const
293 return !maSegments
.empty() ? maSegments
.back().nPgLeft
: 0;
296 sal_uInt32
wwSectionManager::GetPageRight() const
298 return !maSegments
.empty() ? maSegments
.back().nPgRight
: 0;
301 sal_uInt32
wwSectionManager::GetPageWidth() const
303 return !maSegments
.empty() ? maSegments
.back().GetPageWidth() : 0;
306 sal_uInt32
wwSectionManager::GetTextAreaWidth() const
308 return !maSegments
.empty() ? maSegments
.back().GetTextAreaWidth() : 0;
311 sal_uInt32
wwSectionManager::GetWWPageTopMargin() const
313 return !maSegments
.empty() ? maSegments
.back().maSep
.dyaTop
: 0;
316 sal_uInt16
SwWW8ImplReader::End_Footnote()
319 Ignoring Footnote outside of the normal Text. People will put footnotes
320 into field results and field commands.
323 m_pPaM
->GetPoint()->nNode
< m_rDoc
.GetNodes().GetEndOfExtras().GetIndex())
328 OSL_ENSURE(!m_aFootnoteStack
.empty(), "footnote end without start");
329 if (m_aFootnoteStack
.empty())
332 bool bFtEdOk
= false;
333 const FootnoteDescriptor
&rDesc
= m_aFootnoteStack
.back();
335 //Get the footnote character and remove it from the txtnode. We'll
336 //replace it with the footnote
337 SwTextNode
* pText
= m_pPaM
->GetNode().GetTextNode();
338 sal_Int32 nPos
= m_pPaM
->GetPoint()->nContent
.GetIndex();
341 SwTextAttr
* pFN
= nullptr;
342 //There should have been a footnote char, we will replace this.
345 sChar
+= OUStringLiteral1(pText
->GetText()[--nPos
]);
347 --m_pPaM
->GetMark()->nContent
;
348 m_rDoc
.getIDocumentContentOperations().DeleteRange( *m_pPaM
);
349 m_pPaM
->DeleteMark();
350 SwFormatFootnote
aFootnote(rDesc
.meType
== MAN_EDN
);
351 pFN
= pText
->InsertItem(aFootnote
, nPos
, nPos
);
353 OSL_ENSURE(pFN
, "Probleme beim Anlegen des Fussnoten-Textes");
357 SwPosition
aTmpPos( *m_pPaM
->GetPoint() ); // remember old cursor position
358 WW8PLCFxSaveAll aSave
;
359 m_pPlcxMan
->SaveAllPLCFx( aSave
);
360 WW8PLCFMan
* pOldPlcxMan
= m_pPlcxMan
;
362 const SwNodeIndex
* pSttIdx
= static_cast<SwTextFootnote
*>(pFN
)->GetStartNode();
363 OSL_ENSURE(pSttIdx
, "Probleme beim Anlegen des Fussnoten-Textes");
365 static_cast<SwTextFootnote
*>(pFN
)->SetSeqNo( m_rDoc
.GetFootnoteIdxs().size() );
367 bool bOld
= m_bFootnoteEdn
;
368 m_bFootnoteEdn
= true;
370 // read content of Ft-/End-Note
371 Read_HdFtFootnoteText( pSttIdx
, rDesc
.mnStartCp
, rDesc
.mnLen
, rDesc
.meType
);
373 m_bFootnoteEdn
= bOld
;
375 OSL_ENSURE(sChar
.getLength()==1 && ((rDesc
.mbAutoNum
== (sChar
[0] == 2))),
376 "footnote autonumbering must be 0x02, and everything else must not be");
378 // If no automatic numbering use the following char from the main text
379 // as the footnote number
380 if (!rDesc
.mbAutoNum
)
381 static_cast<SwTextFootnote
*>(pFN
)->SetNumber(0, sChar
);
384 Delete the footnote char from the footnote if its at the beginning
385 as usual. Might not be if the user has already deleted it, e.g.
388 SwNodeIndex
& rNIdx
= m_pPaM
->GetPoint()->nNode
;
389 rNIdx
= pSttIdx
->GetIndex() + 1;
390 SwTextNode
* pTNd
= rNIdx
.GetNode().GetTextNode();
391 if (pTNd
&& !pTNd
->GetText().isEmpty() && !sChar
.isEmpty())
393 const OUString
&rText
= pTNd
->GetText();
394 if (rText
[0] == sChar
[0])
396 m_pPaM
->GetPoint()->nContent
.Assign( pTNd
, 0 );
398 // Strip out tabs we may have inserted on export #i24762#
399 if (rText
.getLength() > 1 && rText
[1] == 0x09)
400 ++m_pPaM
->GetMark()->nContent
;
401 ++m_pPaM
->GetMark()->nContent
;
402 m_pReffingStck
->Delete(*m_pPaM
);
403 m_rDoc
.getIDocumentContentOperations().DeleteRange( *m_pPaM
);
404 m_pPaM
->DeleteMark();
408 *m_pPaM
->GetPoint() = aTmpPos
; // restore Cursor
410 m_pPlcxMan
= pOldPlcxMan
; // Restore attributes
411 m_pPlcxMan
->RestoreAllPLCFx( aSave
);
415 m_aSectionManager
.SetCurrentSectionHasFootnote();
417 m_aFootnoteStack
.pop_back();
421 long SwWW8ImplReader::Read_Footnote(WW8PLCFManResult
* pRes
)
424 Ignoring Footnote outside of the normal Text. People will put footnotes
425 into field results and field commands.
428 m_pPaM
->GetPoint()->nNode
< m_rDoc
.GetNodes().GetEndOfExtras().GetIndex())
433 FootnoteDescriptor aDesc
;
434 aDesc
.mbAutoNum
= true;
435 if (eEDN
== pRes
->nSprmId
)
437 aDesc
.meType
= MAN_EDN
;
438 WW8PLCFx_SubDoc
* pEndNote
= m_pPlcxMan
->GetEdn();
439 if (const void* pData
= pEndNote
? pEndNote
->GetData() : nullptr)
440 aDesc
.mbAutoNum
= 0 != *static_cast<short const*>(pData
);
444 aDesc
.meType
= MAN_FTN
;
445 WW8PLCFx_SubDoc
* pFootNote
= m_pPlcxMan
->GetFootnote();
446 if (const void* pData
= pFootNote
? pFootNote
->GetData() : nullptr)
447 aDesc
.mbAutoNum
= 0 != *static_cast<short const*>(pData
);
450 aDesc
.mnStartCp
= pRes
->nCp2OrIdx
;
451 aDesc
.mnLen
= pRes
->nMemLen
;
453 m_aFootnoteStack
.push_back(aDesc
);
458 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP
* pPap
, WW8_CP
&rStartCp
,
462 aRes
.pMemPos
= nullptr;
463 aRes
.nEndPos
= rStartCp
;
464 bool bReadRes(false);
465 WW8PLCFxDesc aPrevRes
;
467 while (pPap
->HasFkp() && rStartCp
!= WW8_CP_MAX
)
469 if (pPap
->Where() != WW8_CP_MAX
)
471 const sal_uInt8
* pB
= pPap
->HasSprm(TabRowSprm(nLevel
));
474 const sal_uInt8
*pLevel
= nullptr;
475 if (nullptr != (pLevel
= pPap
->HasSprm(0x6649)))
477 if (nLevel
+ 1 == *pLevel
)
482 OSL_ENSURE(!nLevel
|| pLevel
, "sublevel without level sprm");
483 return true; // RowEnd found
488 aRes
.nStartPos
= aRes
.nEndPos
;
489 aRes
.pMemPos
= nullptr;
490 //Seek to our next block of properties
491 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
493 aRes
.nEndPos
= WW8_CP_MAX
;
494 pPap
->SetDirty(true);
496 pPap
->GetSprms(&aRes
);
497 pPap
->SetDirty(false);
498 if (bReadRes
&& aRes
.nEndPos
== aPrevRes
.nEndPos
&& aRes
.nStartPos
== aPrevRes
.nStartPos
)
500 SAL_WARN("sw.ww8", "SearchRowEnd, loop in paragraph property chain");
505 //Update our aRes to get the new starting point of the next properties
506 rStartCp
= aRes
.nEndPos
;
512 bool SwWW8ImplReader::SearchTableEnd(WW8PLCFx_Cp_FKP
* pPap
) const
515 // The below SPRM is for WW8 only.
519 aRes
.pMemPos
= nullptr;
520 aRes
.nEndPos
= pPap
->Where();
521 bool bReadRes(false);
522 WW8PLCFxDesc aPrevRes
;
524 while (pPap
->HasFkp() && pPap
->Where() != WW8_CP_MAX
)
526 // See if the current pap is outside the table.
527 const sal_uInt8
* pB
= pPap
->HasSprm(NS_sprm::LN_PFInTable
);
529 // Yes, this is the position after the end of the table.
532 // It is, so seek to the next pap.
533 aRes
.nStartPos
= aRes
.nEndPos
;
534 aRes
.pMemPos
= nullptr;
535 if (!pPap
->SeekPos(aRes
.nStartPos
))
538 // Read the sprms and make sure we moved forward to avoid infinite loops.
539 pPap
->GetSprms(&aRes
);
540 if (bReadRes
&& aRes
.nEndPos
== aPrevRes
.nEndPos
&& aRes
.nStartPos
== aPrevRes
.nStartPos
)
550 ApoTestResults
SwWW8ImplReader::TestApo(int nCellLevel
, bool bTableRowEnd
,
551 const WW8_TablePos
*pTabPos
)
553 const WW8_TablePos
*pTopLevelTable
= nCellLevel
<= 1 ? pTabPos
: nullptr;
555 // Frame in Style Definition (word appears to ignore them if inside an
557 sal_uInt16
const nStyle(m_pPlcxMan
->GetColl());
558 if (!m_bTxbxFlySection
&& nStyle
< m_vColl
.size())
559 aRet
.mpStyleApo
= StyleExists(nStyle
) ? m_vColl
[nStyle
].m_xWWFly
.get() : nullptr;
563 If I have a table and apply a style to one of its frames that should cause
564 a paragraph that it is applied to it to only exist as a separate floating
565 frame, then the behaviour depends on which cell that it has been applied
566 to. If it is the first cell of a row then the whole table row jumps into the
567 new frame, if it isn't then the paragraph attributes are applied
568 "except" for the floating frame stuff. i.e. it's ignored. So if there's a
569 table, and we're not in the first cell then we ignore the fact that the
570 paragraph style wants to be in a different frame.
572 This sort of mindbending inconsistency is surely why frames are deprecated
573 in word 97 onwards and hidden away from the user
576 If we are already a table in a frame then we must grab the para properties
577 to see if we are still in that frame.
580 aRet
.m_bHasSprm37
= m_pPlcxMan
->HasParaSprm( m_bVer67
? 37 : 0x2423 );
581 const sal_uInt8
*pSrpm29
= m_pPlcxMan
->HasParaSprm( m_bVer67
? 29 : 0x261B );
582 aRet
.m_bHasSprm29
= pSrpm29
!= nullptr;
583 aRet
.m_nSprm29
= pSrpm29
? *pSrpm29
: 0;
585 // Is there some frame data here
586 bool bNowApo
= aRet
.HasFrame() || pTopLevelTable
;
589 if (WW8FlyPara
*pTest
= ConstructApo(aRet
, pTabPos
))
595 bool bTestAllowed
= !m_bTxbxFlySection
&& !bTableRowEnd
;
598 //Test is allowed if there is no table.
599 //Otherwise only allowed if we are in the
600 //first paragraph of the first cell of a row.
601 //(And only if the row we are inside is at the
602 //same level as the previous row, think tables
604 if (nCellLevel
== m_nInTable
)
613 OSL_ENSURE(m_pTableDesc
, "What!");
614 bTestAllowed
= false;
619 // If current cell isn't valid, the test is allowed.
620 // The cell isn't valid, if e.g. there is a new row
621 // <pTableDesc->nAktRow> >= <pTableDesc->pTabLines->Count()>
623 m_pTableDesc
->GetAktCol() == 0 &&
624 ( !m_pTableDesc
->IsValidCell( m_pTableDesc
->GetAktCol() ) ||
625 m_pTableDesc
->InFirstParaInCell() );
634 aRet
.mbStartApo
= bNowApo
&& !InEqualOrHigherApo(1); // APO-start
635 aRet
.mbStopApo
= InEqualOrHigherApo(nCellLevel
) && !bNowApo
; // APO-end
637 //If it happens that we are in a table, then if it's not the first cell
638 //then any attributes that might otherwise cause the contents to jump
639 //into another frame don't matter, a table row sticks together as one
640 //unit no matter what else happens. So if we are not in a table at
641 //all, or if we are in the first cell then test that the last frame
642 //data is the same as the current one
643 if (bNowApo
&& InEqualApo(nCellLevel
))
645 // two bordering eachother
646 if (!TestSameApo(aRet
, pTabPos
))
647 aRet
.mbStopApo
= aRet
.mbStartApo
= true;
653 // helper methods for outline, numbering and bullets
655 static void SetBaseAnlv(SwNumFormat
&rNum
, WW8_ANLV
const &rAV
, sal_uInt8 nSwLevel
)
657 static const SvxExtNumType eNumA
[8] = { SVX_NUM_ARABIC
, SVX_NUM_ROMAN_UPPER
, SVX_NUM_ROMAN_LOWER
,
658 SVX_NUM_CHARS_UPPER_LETTER_N
, SVX_NUM_CHARS_LOWER_LETTER_N
, SVX_NUM_ARABIC
,
659 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
};
661 static const SvxAdjust eAdjA
[4] = { SVX_ADJUST_LEFT
,
662 SVX_ADJUST_RIGHT
, SVX_ADJUST_LEFT
, SVX_ADJUST_LEFT
};
664 rNum
.SetNumberingType( static_cast< sal_Int16
>(eNumA
[ rAV
.nfc
] ));
666 sal_Int16 nType
= style::NumberingType::ARABIC
;
669 case 19:nType
= style::NumberingType::FULLWIDTH_ARABIC
; break;
670 case 30:nType
= style::NumberingType::TIAN_GAN_ZH
; break;
671 case 31:nType
= style::NumberingType::DI_ZI_ZH
; break;
676 nType
= style::NumberingType::NUMBER_LOWER_ZH
; break;
677 case 34:nType
= style::NumberingType::NUMBER_UPPER_ZH_TW
;break;
678 case 38:nType
= style::NumberingType::NUMBER_UPPER_ZH
; break;
681 nType
= style::NumberingType::NUMBER_TRADITIONAL_JA
;break;
682 case 20:nType
= style::NumberingType::AIU_FULLWIDTH_JA
;break;
683 case 12:nType
= style::NumberingType::AIU_HALFWIDTH_JA
;break;
684 case 21:nType
= style::NumberingType::IROHA_FULLWIDTH_JA
;break;
685 case 13:nType
= style::NumberingType::IROHA_HALFWIDTH_JA
;break;
686 case 24:nType
= style::NumberingType::HANGUL_SYLLABLE_KO
;break;
687 case 25:nType
= style::NumberingType::HANGUL_JAMO_KO
;break;
688 case 41:nType
= style::NumberingType::NUMBER_HANGUL_KO
;break;
691 case 44:nType
= style::NumberingType::NUMBER_UPPER_KO
; break;
693 nType
= style::NumberingType::ARABIC
;break;
695 rNum
.SetNumberingType( nType
);
698 if ((rAV
.aBits1
& 0x4) >> 2)
700 rNum
.SetIncludeUpperLevels(nSwLevel
+ 1);
702 rNum
.SetStart( SVBT16ToShort( rAV
.iStartAt
) );
703 rNum
.SetNumAdjust( eAdjA
[ rAV
.aBits1
& 0x3] );
705 rNum
.SetCharTextDistance( SVBT16ToShort( rAV
.dxaSpace
) );
706 sal_Int16 nIndent
= std::abs((sal_Int16
)SVBT16ToShort( rAV
.dxaIndent
));
707 if( rAV
.aBits1
& 0x08 ) //fHang
709 rNum
.SetFirstLineOffset( -nIndent
);
710 rNum
.SetAbsLSpace( nIndent
);
713 rNum
.SetCharTextDistance( nIndent
); // width of number is missing
715 if( rAV
.nfc
== 5 || rAV
.nfc
== 7 )
717 OUString sP
= "." + rNum
.GetSuffix();
718 rNum
.SetSuffix( sP
); // ordinal number
722 void SwWW8ImplReader::SetAnlvStrings(SwNumFormat
&rNum
, WW8_ANLV
const &rAV
,
723 const sal_uInt8
* pText
, size_t nStart
, size_t nElements
, bool bOutline
)
725 if (nStart
> nElements
)
731 bool bInsert
= false; // Default
732 rtl_TextEncoding eCharSet
= m_eStructCharSet
;
734 const WW8_FFN
* pF
= m_pFonts
->GetFont(SVBT16ToShort(rAV
.ftc
)); // FontInfo
735 bool bListSymbol
= pF
&& ( pF
->chs
== 2 ); // Symbol/WingDings/...
738 sal_uInt32 nLen
= rAV
.cbTextBefore
+ rAV
.cbTextAfter
;
741 if (nLen
> nElements
)
743 SAL_WARN("sw.ww8", "SetAnlvStrings: ignoring out of range "
744 << nLen
<< " vs " << nElements
<< " max");
747 sText
= OUString(reinterpret_cast<char const *>(pText
), nLen
, eCharSet
);
751 if (nLen
> nElements
/ 2)
753 SAL_WARN("sw.ww8", "SetAnlvStrings: ignoring out of range "
754 << nLen
<< " vs " << nElements
/ 2 << " max");
757 for(sal_uInt32 i
= 0; i
< nLen
; ++i
, pText
+= 2)
759 sText
+= OUStringLiteral1(SVBT16ToShort(*reinterpret_cast<SVBT16
const *>(pText
)));
765 if( !rNum
.GetIncludeUpperLevels() // there are <= 1 number to show
766 || rNum
.GetNumberingType() == SVX_NUM_NUMBER_NONE
) // or this level has none
768 // if self defined digits
769 bInsert
= true; // then apply character
771 // replace by simple Bullet ?
774 // use cBulletChar for correct mapping on MAC
776 comphelper::string::padToLength(aBuf
, rAV
.cbTextBefore
777 + rAV
.cbTextAfter
, cBulletChar
);
778 sText
= aBuf
.makeStringAndClear();
783 { // numbering / bullets
791 if( GetFontParams( SVBT16ToShort( rAV
.ftc
), eFamily
, aName
,
792 ePitch
, eCharSet
) ){
795 aFont
.SetFamilyName( aName
);
796 aFont
.SetFamily( eFamily
);
798 aFont
.SetCharSet( eCharSet
);
799 rNum
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
801 rNum
.SetBulletFont( &aFont
);
803 // take only the very first character
804 if (rAV
.cbTextBefore
|| rAV
.cbTextAfter
)
805 rNum
.SetBulletChar( sText
[ 0 ] );
807 rNum
.SetBulletChar( 0x2190 );
813 if (rAV
.cbTextBefore
)
815 OUString
sP( sText
.copy( 0, rAV
.cbTextBefore
) );
816 rNum
.SetPrefix( sP
);
818 if( rAV
.cbTextAfter
)
820 OUString
sP( rNum
.GetSuffix() );
821 sP
+= sText
.copy( rAV
.cbTextBefore
, rAV
.cbTextAfter
);
822 rNum
.SetSuffix( sP
);
824 // The characters before and after multipe digits do not apply because
825 // those are handled different by the writer and the result is in most
826 // cases worse than without.
830 // SetAnld gets a WW-ANLD-Descriptor and a Level and modifies the NumRules
831 // which are provided by pNumR. This is used for everything beside
832 // outline inside the text.
833 void SwWW8ImplReader::SetAnld(SwNumRule
* pNumR
, WW8_ANLD
const * pAD
, sal_uInt8 nSwLevel
,
838 { // there is a Anld-Sprm
839 m_bAktAND_fNumberAcross
= 0 != pAD
->fNumberAcross
;
840 WW8_ANLV
const &rAV
= pAD
->eAnlv
;
841 SetBaseAnlv(aNF
, rAV
, nSwLevel
); // set the base format
842 SetAnlvStrings(aNF
, rAV
, pAD
->rgchAnld
, 0, SAL_N_ELEMENTS(pAD
->rgchAnld
), bOutLine
); // set the rest
844 pNumR
->Set(nSwLevel
, aNF
);
847 // chapter numbering and bullets
849 // Chapter numbering happens in the style definition.
850 // Sprm 13 provides the level, Sprm 12 the content.
852 SwNumRule
* SwWW8ImplReader::GetStyRule()
854 if( m_pStyles
->pStyRule
) // Bullet-Style already present
855 return m_pStyles
->pStyRule
;
857 const OUString
aBaseName("WW8StyleNum");
858 const OUString
aName( m_rDoc
.GetUniqueNumRuleName( &aBaseName
, false) );
861 sal_uInt16 nRul
= m_rDoc
.MakeNumRule( aName
, nullptr, false,
862 SvxNumberFormat::LABEL_ALIGNMENT
);
863 m_pStyles
->pStyRule
= m_rDoc
.GetNumRuleTable()[nRul
];
864 // Auto == false-> Nummerierungsvorlage
865 m_pStyles
->pStyRule
->SetAutoRule(false);
867 return m_pStyles
->pStyRule
;
871 void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
873 m_nSwNumLevel
= 0xff; // Default: invalid
881 // only for SwTextFormatColl, not CharFormat
882 // WW: 0 = no Numbering
883 SwWW8StyInf
* pColl
= GetStyle(m_nAktColl
);
884 if (pColl
!= nullptr && pColl
->m_bColl
&& *pData
)
886 // Range WW:1..9 -> SW:0..8 no bullets / numbering
888 if (*pData
<= MAXLEVEL
&& *pData
<= 9)
890 m_nSwNumLevel
= *pData
- 1;
891 if (!m_bNoAttrImport
)
892 static_cast<SwTextFormatColl
*>(m_pAktColl
)->AssignToListLevelOfOutlineStyle( m_nSwNumLevel
);
893 // For WW-NoNumbering also NO_NUMBERING could be used.
894 // ( For normal numberierung NO_NUM has to be used:
895 // NO_NUM : pauses numbering,
896 // NO_NUMBERING : no numbering at all )
899 else if( *pData
== 10 || *pData
== 11 )
901 // remember type, the rest happens at Sprm 12
902 m_pStyles
->nWwNumLevel
= *pData
;
910 StartAnl(pData
); // begin of outline / bullets
915 void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16
, const sal_uInt8
* pData
, short nLen
) // Sprm 12
917 SwWW8StyInf
* pStyInf
= GetStyle(m_nAktColl
);
918 if( !m_pAktColl
|| nLen
<= 0 // only for Styledef
919 || (pStyInf
&& !pStyInf
->m_bColl
) // ignore CharFormat ->
920 || ( m_nIniFlags
& WW8FL_NO_OUTLINE
) )
922 m_nSwNumLevel
= 0xff;
926 if (static_cast<size_t>(nLen
) < sizeof(WW8_ANLD
))
928 SAL_WARN("sw.ww8", "ANLevelDesc property is " << nLen
<< " long, needs to be at least " << sizeof(WW8_ANLD
));
929 m_nSwNumLevel
= 0xff;
933 if( m_nSwNumLevel
<= MAXLEVEL
// Value range mapping WW:1..9 -> SW:0..8
934 && m_nSwNumLevel
<= 9 ){ // No Bullets or Numbering
936 // If NumRuleItems were set, either directly or through inheritance, disable them now
937 m_pAktColl
->SetFormatAttr( SwNumRuleItem() );
939 const OUString
aName("Outline");
940 SwNumRule
aNR( m_rDoc
.GetUniqueNumRuleName( &aName
),
941 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
943 aNR
= *m_rDoc
.GetOutlineNumRule();
945 SetAnld(&aNR
, reinterpret_cast<WW8_ANLD
const *>(pData
), m_nSwNumLevel
, true);
947 // Missing Levels need not be replenished
948 m_rDoc
.SetOutlineNumRule( aNR
);
949 }else if( m_pStyles
->nWwNumLevel
== 10 || m_pStyles
->nWwNumLevel
== 11 ){
950 SwNumRule
* pNR
= GetStyRule();
951 SetAnld(pNR
, reinterpret_cast<WW8_ANLD
const *>(pData
), 0, false);
952 m_pAktColl
->SetFormatAttr( SwNumRuleItem( pNR
->GetName() ) );
954 pStyInf
= GetStyle(m_nAktColl
);
955 if (pStyInf
!= nullptr)
956 pStyInf
->m_bHasStyNumRule
= true;
960 // Numbering / Bullets
962 // SetNumOlst() carries the Numrules for this cell to SwNumFormat.
963 // For this the info is fetched from OLST and not from ANLD ( see later )
964 // ( only for outline inside text; Bullets / numbering use ANLDs )
965 void SwWW8ImplReader::SetNumOlst(SwNumRule
* pNumR
, WW8_OLST
* pO
, sal_uInt8 nSwLevel
)
968 WW8_ANLV
&rAV
= pO
->rganlv
[nSwLevel
];
969 SetBaseAnlv(aNF
, rAV
, nSwLevel
);
970 // ... and then the Strings
973 WW8_ANLV
* pAV1
; // search String-Positions
974 for (i
= 0, pAV1
= pO
->rganlv
; i
< nSwLevel
; ++i
, ++pAV1
)
975 nTextOfs
+= pAV1
->cbTextBefore
+ pAV1
->cbTextAfter
;
979 SetAnlvStrings(aNF
, rAV
, pO
->rgch
, nTextOfs
, SAL_N_ELEMENTS(pO
->rgch
), true); // and apply
980 pNumR
->Set(nSwLevel
, aNF
);
983 // The OLST is at the beginning of each section that contains outlines.
984 // The ANLDs that are connected to each outline-line contain only nonsense,
985 // so the OLSTs are remembered for the section to have usable information
986 // when outline-paragraphs occur.
987 void SwWW8ImplReader::Read_OLST( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
992 m_pNumOlst
= nullptr;
996 if (static_cast<size_t>(nLen
) < sizeof(WW8_OLST
))
998 SAL_WARN("sw.ww8", "WW8_OLST property is " << nLen
<< " long, needs to be at least " << sizeof(WW8_OLST
));
999 m_pNumOlst
= nullptr;
1003 m_pNumOlst
= new WW8_OLST
;
1004 if( nLen
< sal::static_int_cast
< sal_Int32
>(sizeof( WW8_OLST
)) ) // fill if to short
1005 memset( m_pNumOlst
, 0, sizeof( *m_pNumOlst
) );
1006 *m_pNumOlst
= *reinterpret_cast<WW8_OLST
const *>(pData
);
1009 WW8LvlType
GetNumType(sal_uInt8 nWwLevelNo
)
1011 WW8LvlType nRet
= WW8_None
;
1012 if( nWwLevelNo
== 12 )
1014 else if( nWwLevelNo
== 10 )
1015 nRet
= WW8_Numbering
;
1016 else if( nWwLevelNo
== 11 )
1017 nRet
= WW8_Sequence
;
1018 else if( nWwLevelNo
> 0 && nWwLevelNo
<= 9 )
1023 SwNumRule
*ANLDRuleMap::GetNumRule(SwDoc
& rDoc
, sal_uInt8 nNumType
)
1025 const OUString
& rNumRule
= WW8_Numbering
== nNumType
? msNumberingNumRule
: msOutlineNumRule
;
1026 if (rNumRule
.isEmpty())
1028 return rDoc
.FindNumRulePtr(rNumRule
);
1031 void ANLDRuleMap::SetNumRule(const OUString
& rNumRule
, sal_uInt8 nNumType
)
1033 if (WW8_Numbering
== nNumType
)
1034 msNumberingNumRule
= rNumRule
;
1036 msOutlineNumRule
= rNumRule
;
1039 // StartAnl is called at the beginning of a row area that contains
1040 // outline / numbering / bullets
1041 void SwWW8ImplReader::StartAnl(const sal_uInt8
* pSprm13
)
1043 m_bAktAND_fNumberAcross
= false;
1045 sal_uInt8 nT
= static_cast< sal_uInt8
>(GetNumType(*pSprm13
));
1046 if (nT
== WW8_Pause
|| nT
== WW8_None
)
1050 SwNumRule
*pNumRule
= m_aANLDRules
.GetNumRule(m_rDoc
, m_nWwNumType
);
1052 // check for COL numbering:
1053 const sal_uInt8
* pS12
= nullptr;// sprmAnld
1058 sNumRule
= m_pTableDesc
->GetNumRuleName();
1059 if (!sNumRule
.isEmpty())
1061 pNumRule
= m_rDoc
.FindNumRulePtr(sNumRule
);
1066 // this is ROW numbering ?
1067 pS12
= m_pPlcxMan
->HasParaSprm(m_bVer67
? 12 : 0xC63E); // sprmAnld
1068 if (pS12
&& 0 != reinterpret_cast<WW8_ANLD
const *>(pS12
)->fNumberAcross
)
1074 SwWW8StyInf
* pStyInf
= GetStyle(m_nAktColl
);
1075 if (sNumRule
.isEmpty() && pStyInf
!= nullptr && pStyInf
->m_bHasStyNumRule
)
1077 sNumRule
= pStyInf
->m_pFormat
->GetNumRule().GetValue();
1078 pNumRule
= m_rDoc
.FindNumRulePtr(sNumRule
);
1083 if (sNumRule
.isEmpty())
1088 pNumRule
= m_rDoc
.GetNumRuleTable()[
1089 m_rDoc
.MakeNumRule( sNumRule
, nullptr, false,
1090 SvxNumberFormat::LABEL_ALIGNMENT
) ];
1095 pS12
= m_pPlcxMan
->HasParaSprm(m_bVer67
? 12 : 0xC63E); // sprmAnld
1096 if (!pS12
|| !reinterpret_cast<WW8_ANLD
const *>(pS12
)->fNumberAcross
)
1097 m_pTableDesc
->SetNumRuleName(pNumRule
->GetName());
1103 sNumRule
= pNumRule
? pNumRule
->GetName() : OUString();
1104 // set NumRules via stack
1105 m_pCtrlStck
->NewAttr(*m_pPaM
->GetPoint(),
1106 SfxStringItem(RES_FLTR_NUMRULE
, sNumRule
));
1108 m_aANLDRules
.SetNumRule(sNumRule
, m_nWwNumType
);
1111 // NextAnlLine() is called once for every row of a
1112 // outline / numbering / bullet
1113 void SwWW8ImplReader::NextAnlLine(const sal_uInt8
* pSprm13
)
1118 SwNumRule
*pNumRule
= m_aANLDRules
.GetNumRule(m_rDoc
, m_nWwNumType
);
1120 // pNd->UpdateNum ohne Regelwerk gibt GPF spaetestens beim Speichern als
1123 // WW:10 = numberierung -> SW:0 & WW:11 = bullets -> SW:0
1124 if (*pSprm13
== 10 || *pSprm13
== 11)
1127 if (pNumRule
&& !pNumRule
->GetNumFormat(m_nSwNumLevel
))
1131 const sal_uInt8
* pS12
= m_pPlcxMan
->HasParaSprm(m_bVer67
? 12 : 0xC63E);
1132 SetAnld(pNumRule
, reinterpret_cast<WW8_ANLD
const *>(pS12
), m_nSwNumLevel
, false);
1135 else if( *pSprm13
> 0 && *pSprm13
<= MAXLEVEL
) // range WW:1..9 -> SW:0..8
1137 m_nSwNumLevel
= *pSprm13
- 1; // outline
1139 if (pNumRule
&& !pNumRule
->GetNumFormat(m_nSwNumLevel
))
1141 if (m_pNumOlst
) // there was a OLST
1143 //Assure upper levels are set, #i9556#
1144 for (sal_uInt8 nI
= 0; nI
< m_nSwNumLevel
; ++nI
)
1146 if (!pNumRule
->GetNumFormat(nI
))
1147 SetNumOlst(pNumRule
, m_pNumOlst
, nI
);
1150 SetNumOlst(pNumRule
, m_pNumOlst
, m_nSwNumLevel
);
1152 else // no Olst -> use Anld
1155 const sal_uInt8
* pS12
= m_pPlcxMan
->HasParaSprm(m_bVer67
? 12 : 0xC63E);
1156 SetAnld(pNumRule
, reinterpret_cast<WW8_ANLD
const *>(pS12
), m_nSwNumLevel
, false);
1161 m_nSwNumLevel
= 0xff; // no number
1163 SwTextNode
* pNd
= m_pPaM
->GetNode().GetTextNode();
1164 if (m_nSwNumLevel
< MAXLEVEL
)
1165 pNd
->SetAttrListLevel( m_nSwNumLevel
);
1168 pNd
->SetAttrListLevel(0);
1169 pNd
->SetCountedInList( false );
1173 void SwWW8ImplReader::StopAllAnl(bool bGoBack
)
1175 //Of course we're not restarting, but we'll make use of our knowledge
1176 //of the implementation to do it.
1177 StopAnlToRestart(WW8_None
, bGoBack
);
1180 void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType
, bool bGoBack
)
1184 SwPosition
aTmpPos(*m_pPaM
->GetPoint());
1185 m_pPaM
->Move(fnMoveBackward
, GoInContent
);
1186 m_pCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1187 *m_pPaM
->GetPoint() = aTmpPos
;
1190 m_pCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1192 m_aANLDRules
.msNumberingNumRule
.clear();
1195 my take on this problem is that moving either way from an outline to a
1196 numbering doesn't halt the outline, while the numbering is always halted
1198 bool bNumberingNotStopOutline
=
1199 (((m_nWwNumType
== WW8_Outline
) && (nNewType
== WW8_Numbering
)) ||
1200 ((m_nWwNumType
== WW8_Numbering
) && (nNewType
== WW8_Outline
)));
1201 if (!bNumberingNotStopOutline
)
1202 m_aANLDRules
.msOutlineNumRule
.clear();
1204 m_nSwNumLevel
= 0xff;
1205 m_nWwNumType
= WW8_None
;
1209 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc
& rBand
)
1214 pTCs
= new WW8_TCell
[nWwCols
];
1215 memcpy( pTCs
, rBand
.pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1219 pSHDs
= new WW8_SHD
[nWwCols
];
1220 memcpy( pSHDs
, rBand
.pSHDs
, nWwCols
* sizeof( WW8_SHD
) );
1222 if( rBand
.pNewSHDs
)
1224 pNewSHDs
= new sal_uInt32
[nWwCols
];
1225 memcpy(pNewSHDs
, rBand
.pNewSHDs
, nWwCols
* sizeof(sal_uInt32
));
1227 memcpy(aDefBrcs
, rBand
.aDefBrcs
, sizeof(aDefBrcs
));
1230 // ReadDef reads the cell position and the borders of a band
1231 void WW8TabBandDesc::ReadDef(bool bVer67
, const sal_uInt8
* pS
)
1236 short nLen
= (sal_Int16
)SVBT16ToShort( pS
- 2 ); // not beautiful
1238 sal_uInt8 nCols
= *pS
; // number of cells
1239 short nOldCols
= nWwCols
;
1241 if( nCols
> MAX_COL
)
1246 const sal_uInt8
* pT
= &pS
[1];
1249 for(i
=0; i
<=nCols
; i
++, pT
+=2 )
1250 nCenter
[i
] = (sal_Int16
)SVBT16ToShort( pT
); // X-borders
1251 nLen
-= 2 * ( nCols
+ 1 );
1252 if( nCols
!= nOldCols
) // different column count
1262 short nFileCols
= nLen
/ ( bVer67
? 10 : 20 ); // really saved
1267 pTCs
= new WW8_TCell
[nCols
];
1268 setcelldefaults(pTCs
,nCols
);
1271 short nColsToRead
= nFileCols
;
1272 if (nColsToRead
> nCols
)
1273 nColsToRead
= nCols
;
1280 Attention: Beginning with Ver8 there is an extra ushort per TC
1281 added and the size of the border code is doubled.
1282 Because of this a simple copy (pTCs[i] = *pTc;)
1285 Advantage: The work structure suits better.
1287 WW8_TCell
* pAktTC
= pTCs
;
1290 WW8_TCellVer6
const * pTc
= reinterpret_cast<WW8_TCellVer6
const *>(pT
);
1291 for(i
=0; i
<nColsToRead
; i
++, ++pAktTC
,++pTc
)
1293 if( i
< nColsToRead
)
1295 sal_uInt8 aBits1
= pTc
->aBits1Ver6
;
1296 pAktTC
->bFirstMerged
= sal_uInt8( ( aBits1
& 0x01 ) != 0 );
1297 pAktTC
->bMerged
= sal_uInt8( ( aBits1
& 0x02 ) != 0 );
1298 pAktTC
->rgbrc
[ WW8_TOP
]
1299 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_TOP
] ));
1300 pAktTC
->rgbrc
[ WW8_LEFT
]
1301 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_LEFT
] ));
1302 pAktTC
->rgbrc
[ WW8_BOT
]
1303 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_BOT
] ));
1304 pAktTC
->rgbrc
[ WW8_RIGHT
]
1305 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_RIGHT
] ));
1306 if( ( pAktTC
->bMerged
)
1309 // Cell merged -> remember
1310 //bWWMergedVer6[i] = true;
1311 pTCs
[i
-1].rgbrc
[ WW8_RIGHT
]
1312 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_RIGHT
] ));
1313 // apply right border to previous cell
1314 // bExist must not be set to false, because WW
1315 // does not count this cells in text boxes....
1322 WW8_TCellVer8
const * pTc
= reinterpret_cast<WW8_TCellVer8
const *>(pT
);
1323 for (int k
= 0; k
< nColsToRead
; ++k
, ++pAktTC
, ++pTc
)
1325 sal_uInt16 aBits1
= SVBT16ToShort( pTc
->aBits1Ver8
);
1326 pAktTC
->bFirstMerged
= sal_uInt8( ( aBits1
& 0x0001 ) != 0 );
1327 pAktTC
->bMerged
= sal_uInt8( ( aBits1
& 0x0002 ) != 0 );
1328 pAktTC
->bVertical
= sal_uInt8( ( aBits1
& 0x0004 ) != 0 );
1329 pAktTC
->bBackward
= sal_uInt8( ( aBits1
& 0x0008 ) != 0 );
1330 pAktTC
->bRotateFont
= sal_uInt8( ( aBits1
& 0x0010 ) != 0 );
1331 pAktTC
->bVertMerge
= sal_uInt8( ( aBits1
& 0x0020 ) != 0 );
1332 pAktTC
->bVertRestart
= sal_uInt8( ( aBits1
& 0x0040 ) != 0 );
1333 pAktTC
->nVertAlign
= ( ( aBits1
& 0x0180 ) >> 7 );
1334 // note: in aBits1 there are 7 bits unused,
1335 // followed by another 16 unused bits
1337 pAktTC
->rgbrc
[ WW8_TOP
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_TOP
]);
1338 pAktTC
->rgbrc
[ WW8_LEFT
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_LEFT
]);
1339 pAktTC
->rgbrc
[ WW8_BOT
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_BOT
]);
1340 pAktTC
->rgbrc
[ WW8_RIGHT
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_RIGHT
]);
1344 // #i25071 In '97 text direction appears to be only set using TC properties
1345 // not with sprmTTextFlow so we need to cycle through the maDirections and
1346 // double check any non-default directions
1347 for (int k
= 0; k
< nCols
; ++k
)
1349 if(maDirections
[k
] == 4)
1351 if(pTCs
[k
].bVertical
)
1353 if(pTCs
[k
].bBackward
)
1354 maDirections
[k
] = 3;
1356 maDirections
[k
] = 1;
1363 void WW8TabBandDesc::ProcessSprmTSetBRC(int nBrcVer
, const sal_uInt8
* pParamsTSetBRC
)
1365 if( pParamsTSetBRC
&& pTCs
) // set one or more cell border(s)
1367 sal_uInt8 nitcFirst
= pParamsTSetBRC
[0];// first col to be changed
1368 sal_uInt8 nitcLim
= pParamsTSetBRC
[1];// (last col to be changed)+1
1369 sal_uInt8 nFlag
= *(pParamsTSetBRC
+2);
1371 if (nitcFirst
>= nWwCols
)
1374 if (nitcLim
> nWwCols
)
1377 bool bChangeRight
= (nFlag
& 0x08) != 0;
1378 bool bChangeBottom
= (nFlag
& 0x04) != 0;
1379 bool bChangeLeft
= (nFlag
& 0x02) != 0;
1380 bool bChangeTop
= (nFlag
& 0x01) != 0;
1382 WW8_TCell
* pAktTC
= pTCs
+ nitcFirst
;
1383 WW8_BRCVer9 brcVer9
;
1385 brcVer9
= WW8_BRCVer9(WW8_BRC(*reinterpret_cast<WW8_BRCVer6
const *>(pParamsTSetBRC
+3)));
1386 else if( nBrcVer
== 8 )
1387 brcVer9
= WW8_BRCVer9(*reinterpret_cast<WW8_BRC
const *>(pParamsTSetBRC
+3));
1389 brcVer9
= *reinterpret_cast<WW8_BRCVer9
const *>(pParamsTSetBRC
+3);
1391 for( int i
= nitcFirst
; i
< nitcLim
; ++i
, ++pAktTC
)
1394 pAktTC
->rgbrc
[ WW8_TOP
] = brcVer9
;
1396 pAktTC
->rgbrc
[ WW8_LEFT
] = brcVer9
;
1398 pAktTC
->rgbrc
[ WW8_BOT
] = brcVer9
;
1400 pAktTC
->rgbrc
[ WW8_RIGHT
] = brcVer9
;
1405 void WW8TabBandDesc::ProcessSprmTTableBorders(int nBrcVer
, const sal_uInt8
* pParams
)
1407 // sprmTTableBorders
1410 WW8_BRCVer6
const *pVer6
= reinterpret_cast<WW8_BRCVer6
const *>(pParams
);
1411 for (int i
= 0; i
< 6; ++i
)
1412 aDefBrcs
[i
] = WW8_BRCVer9(WW8_BRC(pVer6
[i
]));
1414 else if ( nBrcVer
== 8 )
1416 static_assert(sizeof (WW8_BRC
) == 4, "this has to match the msword size");
1417 for( int i
= 0; i
< 6; ++i
)
1418 aDefBrcs
[i
] = WW8_BRCVer9(reinterpret_cast<WW8_BRC
const *>(pParams
)[i
]);
1421 memcpy( aDefBrcs
, pParams
, sizeof( aDefBrcs
) );
1424 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8
* pParamsTDxaCol
)
1426 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1427 // whose index is within a certain range to be a certain value.
1429 if( nWwCols
&& pParamsTDxaCol
) // set one or more cell length(s)
1431 sal_uInt8 nitcFirst
= pParamsTDxaCol
[0]; // first col to be changed
1432 sal_uInt8 nitcLim
= pParamsTDxaCol
[1]; // (last col to be changed)+1
1433 short nDxaCol
= (sal_Int16
)SVBT16ToShort( pParamsTDxaCol
+ 2 );
1435 for( int i
= nitcFirst
; (i
< nitcLim
) && (i
< nWwCols
); i
++ )
1437 const short nOrgWidth
= nCenter
[i
+1] - nCenter
[i
];
1438 const short nDelta
= nDxaCol
- nOrgWidth
;
1439 for( int j
= i
+1; j
<= nWwCols
; j
++ )
1441 nCenter
[j
] = nCenter
[j
] + nDelta
;
1447 void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8
* pParamsTInsert
)
1449 if( nWwCols
&& pParamsTInsert
) // set one or more cell length(s)
1451 sal_uInt8 nitcInsert
= pParamsTInsert
[0]; // position at which to insert
1452 if (nitcInsert
>= MAX_COL
) // cannot insert into cell outside max possible index
1454 sal_uInt8 nctc
= pParamsTInsert
[1]; // number of cells
1455 sal_uInt16 ndxaCol
= SVBT16ToShort( pParamsTInsert
+2 );
1458 if (nitcInsert
> nWwCols
)
1460 nNewWwCols
= nitcInsert
+nctc
;
1461 //if new count would be outside max possible count, clip it, and calc a new replacement
1463 if (nNewWwCols
> MAX_COL
)
1465 nNewWwCols
= MAX_COL
;
1466 nctc
= ::sal::static_int_cast
<sal_uInt8
>(nNewWwCols
-nitcInsert
);
1471 nNewWwCols
= nWwCols
+nctc
;
1472 //if new count would be outside max possible count, clip it, and calc a new replacement
1474 if (nNewWwCols
> MAX_COL
)
1476 nNewWwCols
= MAX_COL
;
1477 nctc
= ::sal::static_int_cast
<sal_uInt8
>(nNewWwCols
-nWwCols
);
1481 WW8_TCell
*pTC2s
= new WW8_TCell
[nNewWwCols
];
1482 setcelldefaults(pTC2s
, nNewWwCols
);
1486 memcpy( pTC2s
, pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1491 //If we have to move some cells
1492 if (nitcInsert
<= nWwCols
)
1494 // adjust the left x-position of the dummy at the very end
1495 nCenter
[nWwCols
+ nctc
] = nCenter
[nWwCols
]+nctc
*ndxaCol
;
1496 for( int i
= nWwCols
-1; i
>= nitcInsert
; i
--)
1498 // adjust the left x-position
1499 nCenter
[i
+ nctc
] = nCenter
[i
]+nctc
*ndxaCol
;
1501 // adjust the cell's borders
1502 pTCs
[i
+ nctc
] = pTCs
[i
];
1506 //if itcMac is larger than full size, fill in missing ones first
1507 for( int i
= nWwCols
; i
> nitcInsert
+nWwCols
; i
--)
1508 nCenter
[i
] = i
? (nCenter
[i
- 1]+ndxaCol
) : 0;
1510 //now add in our new cells
1511 for( int j
= 0;j
< nctc
; j
++)
1512 nCenter
[j
+ nitcInsert
] = (j
+ nitcInsert
) ? (nCenter
[j
+ nitcInsert
-1]+ndxaCol
) : 0;
1514 nWwCols
= nNewWwCols
;
1518 void WW8TabBandDesc::ProcessDirection(const sal_uInt8
* pParams
)
1520 sal_uInt8 nStartCell
= *pParams
++;
1521 sal_uInt8 nEndCell
= *pParams
++;
1522 sal_uInt16 nCode
= SVBT16ToShort(pParams
);
1524 OSL_ENSURE(nStartCell
< nEndCell
, "not as I thought");
1525 OSL_ENSURE(nEndCell
< MAX_COL
+ 1, "not as I thought");
1526 if (nStartCell
> MAX_COL
)
1528 if (nEndCell
> MAX_COL
+ 1)
1529 nEndCell
= MAX_COL
+ 1;
1531 for (;nStartCell
< nEndCell
; ++nStartCell
)
1532 maDirections
[nStartCell
] = nCode
;
1535 void WW8TabBandDesc::ProcessSpacing(const sal_uInt8
* pParams
)
1537 sal_uInt8 nLen
= pParams
? *(pParams
- 1) : 0;
1538 OSL_ENSURE(nLen
== 6, "Unexpected spacing len");
1542 #if OSL_DEBUG_LEVEL > 0
1543 sal_uInt8 nWhichCell
= *pParams
;
1544 OSL_ENSURE(nWhichCell
== 0, "Expected cell to be 0!");
1546 ++pParams
; //Skip which cell
1547 ++pParams
; //unknown byte
1549 sal_uInt8 nSideBits
= *pParams
++;
1550 OSL_ENSURE(nSideBits
< 0x10, "Unexpected value for nSideBits");
1551 ++pParams
; //unknown byte
1552 sal_uInt16 nValue
= SVBT16ToShort( pParams
);
1553 for (int i
= wwTOP
; i
<= wwRIGHT
; i
++)
1555 switch (nSideBits
& (1 << i
))
1558 mnDefaultTop
= nValue
;
1561 mnDefaultLeft
= nValue
;
1564 mnDefaultBottom
= nValue
;
1567 mnDefaultRight
= nValue
;
1572 OSL_ENSURE(false, "Impossible");
1578 void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8
* pParams
)
1580 sal_uInt8 nLen
= pParams
? *(pParams
- 1) : 0;
1581 OSL_ENSURE(nLen
== 6, "Unexpected spacing len");
1584 sal_uInt8 nWhichCell
= *pParams
++;
1585 OSL_ENSURE(nWhichCell
< MAX_COL
+ 1, "Cell out of range in spacings");
1586 if (nWhichCell
>= MAX_COL
+ 1)
1589 ++pParams
; //unknown byte
1590 sal_uInt8 nSideBits
= *pParams
++;
1591 OSL_ENSURE(nSideBits
< 0x10, "Unexpected value for nSideBits");
1592 nOverrideSpacing
[nWhichCell
] |= nSideBits
;
1594 OSL_ENSURE(nOverrideSpacing
[nWhichCell
] < 0x10,
1595 "Unexpected value for nSideBits");
1596 #if OSL_DEBUG_LEVEL > 0
1597 sal_uInt8 nUnknown2
= *pParams
;
1598 OSL_ENSURE(nUnknown2
== 0x3, "Unexpected value for spacing2");
1601 sal_uInt16 nValue
= SVBT16ToShort( pParams
);
1603 for (int i
=0; i
< 4; i
++)
1605 if (nSideBits
& (1 << i
))
1606 nOverrideValues
[nWhichCell
][i
] = nValue
;
1610 void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8
* pParamsTDelete
)
1612 if( nWwCols
&& pParamsTDelete
) // set one or more cell length(s)
1614 sal_uInt8 nitcFirst
= pParamsTDelete
[0]; // first col to be deleted
1615 if (nitcFirst
>= nWwCols
) // first index to delete from doesn't exist
1617 sal_uInt8 nitcLim
= pParamsTDelete
[1]; // (last col to be deleted)+1
1618 if (nitcLim
<= nitcFirst
) // second index to delete to is not greater than first index
1622 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1623 * greater than or equal to itcLim to be moved
1625 int nShlCnt
= nWwCols
- nitcLim
; // count of cells to be shifted
1627 if (nShlCnt
>= 0) //There exist entries whose index is greater than or equal to itcLim
1629 WW8_TCell
* pAktTC
= pTCs
+ nitcFirst
;
1631 while( i
< nShlCnt
)
1633 // adjust the left x-position
1634 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1636 // adjust the cell's borders
1637 *pAktTC
= pTCs
[ nitcLim
+ i
];
1642 // adjust the left x-position of the dummy at the very end
1643 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1646 short nCellsDeleted
= nitcLim
- nitcFirst
;
1647 //clip delete request to available number of cells
1648 if (nCellsDeleted
> nWwCols
)
1649 nCellsDeleted
= nWwCols
;
1650 nWwCols
-= nCellsDeleted
;
1654 // ReadShd reads the background color of a cell
1655 // ReadDef must be called before
1656 void WW8TabBandDesc::ReadShd(const sal_uInt8
* pS
)
1658 sal_uInt8 nLen
= pS
? *(pS
- 1) : 0;
1664 pSHDs
= new WW8_SHD
[nWwCols
];
1665 memset( pSHDs
, 0, nWwCols
* sizeof( WW8_SHD
) );
1668 short nCount
= nLen
>> 1;
1669 if (nCount
> nWwCols
)
1672 SVBT16
const * pShd
;
1674 for(i
=0, pShd
= reinterpret_cast<SVBT16
const *>(pS
); i
<nCount
; i
++, pShd
++ )
1675 pSHDs
[i
].SetWWValue( *pShd
);
1678 void WW8TabBandDesc::ReadNewShd(const sal_uInt8
* pS
, bool bVer67
)
1680 sal_uInt8 nLen
= pS
? *(pS
- 1) : 0;
1685 pNewSHDs
= new sal_uInt32
[nWwCols
];
1687 short nCount
= nLen
/ 10; //10 bytes each
1688 if (nCount
> nWwCols
)
1693 pNewSHDs
[i
++] = SwWW8ImplReader::ExtractColour(pS
, bVer67
);
1696 pNewSHDs
[i
++] = COL_AUTO
;
1699 void WW8TabBandDesc::setcelldefaults(WW8_TCell
*pCells
, short nCols
)
1701 memset( pCells
, 0, nCols
* sizeof( WW8_TCell
) );
1704 const sal_uInt8
*HasTabCellSprm(WW8PLCFx_Cp_FKP
* pPap
, bool bVer67
)
1706 const sal_uInt8
*pParams
;
1708 pParams
= pPap
->HasSprm(24);
1711 if (nullptr == (pParams
= pPap
->HasSprm(0x244B)))
1712 pParams
= pPap
->HasSprm(0x2416);
1721 sprmTTableWidth
, sprmTTextFlow
, sprmTFCantSplit
, sprmTJc
, sprmTFBiDi
,
1722 sprmTDefTable
, sprmTDyaRowHeight
, sprmTDefTableShd
, sprmTDxaLeft
,
1723 sprmTSetBrc
, sprmTSetBrc90
, sprmTDxaCol
, sprmTInsert
, sprmTDelete
,
1724 sprmTTableHeader
, sprmTDxaGapHalf
, sprmTTableBorders
, sprmTTableBorders90
,
1725 sprmTDefTableNewShd
, sprmTCellPadding
, sprmTCellPaddingDefault
1728 wwTableSprm
GetTableSprm(sal_uInt16 nId
, ww::WordVersion eVer
)
1735 case NS_sprm::LN_TTableWidth
:
1736 return sprmTTableWidth
;
1737 case NS_sprm::LN_TTextFlow
:
1738 return sprmTTextFlow
;
1739 case NS_sprm::LN_TTableHeader
:
1740 return sprmTTableHeader
;
1741 case NS_sprm::LN_TFCantSplit
:
1742 return sprmTFCantSplit
;
1743 case NS_sprm::LN_TJc90
:
1745 case NS_sprm::LN_TFBiDi
:
1747 case NS_sprm::LN_TDelete
:
1749 case NS_sprm::LN_TInsert
:
1751 case NS_sprm::LN_TDxaCol
:
1753 case NS_sprm::LN_TDyaRowHeight
:
1754 return sprmTDyaRowHeight
;
1755 case NS_sprm::LN_TDxaLeft
:
1756 return sprmTDxaLeft
;
1757 case NS_sprm::LN_TDxaGapHalf
:
1758 return sprmTDxaGapHalf
;
1759 case NS_sprm::LN_TTableBorders80
:
1760 return sprmTTableBorders
;
1761 case NS_sprm::LN_TDefTable
:
1762 return sprmTDefTable
;
1763 case NS_sprm::LN_TDefTableShd80
:
1764 return sprmTDefTableShd
;
1765 case NS_sprm::LN_TDefTableShd
:
1766 return sprmTDefTableNewShd
;
1767 case NS_sprm::LN_TTableBorders
:
1768 return sprmTTableBorders90
;
1769 case NS_sprm::LN_TSetBrc80
:
1771 case NS_sprm::LN_TSetBrc
:
1772 return sprmTSetBrc90
;
1773 case NS_sprm::LN_TCellPadding
:
1774 return sprmTCellPadding
;
1775 case NS_sprm::LN_TCellPaddingDefault
:
1776 return sprmTCellPaddingDefault
;
1786 return sprmTDxaLeft
;
1788 return sprmTDxaGapHalf
;
1790 return sprmTTableHeader
;
1792 return sprmTTableBorders
;
1794 return sprmTDyaRowHeight
;
1796 return sprmTDefTable
;
1798 return sprmTDefTableShd
;
1816 return sprmTDxaLeft
;
1818 return sprmTDxaGapHalf
;
1820 return sprmTDyaRowHeight
;
1822 return sprmTDefTable
;
1824 return sprmTDefTableShd
;
1839 WW8TabDesc::WW8TabDesc(SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
) :
1840 mpOldRedlineStack(nullptr),
1842 m_pFirstBand(nullptr),
1843 m_pActBand(nullptr),
1845 m_pTableNd(nullptr),
1846 m_pTabLines(nullptr),
1847 m_pTabLine(nullptr),
1848 m_pTabBoxes(nullptr),
1850 m_pAktWWCell(nullptr),
1852 m_nDefaultSwCols(0),
1855 m_nConvertedLeft(0),
1858 m_nPreferredWidth(0),
1861 m_bClaimLineFormat(false),
1862 m_eOri(text::HoriOrientation::NONE
),
1869 m_pParentPos(nullptr),
1870 m_pFlyFormat(nullptr),
1871 m_aItemSet(m_pIo
->m_rDoc
.GetAttrPool(),RES_FRMATR_BEGIN
,RES_FRMATR_END
-1)
1873 m_pIo
->m_bAktAND_fNumberAcross
= false;
1875 static const sal_Int16 aOriArr
[] =
1877 text::HoriOrientation::LEFT
, text::HoriOrientation::CENTER
, text::HoriOrientation::RIGHT
, text::HoriOrientation::CENTER
1880 bool bOldVer
= ww::IsSevenMinus(m_pIo
->GetFib().GetFIBVersion());
1881 WW8_TablePos aTabPos
;
1883 WW8PLCFxSave1 aSave
;
1884 m_pIo
->m_pPlcxMan
->GetPap()->Save( aSave
);
1886 WW8PLCFx_Cp_FKP
* pPap
= m_pIo
->m_pPlcxMan
->GetPapPLCF();
1888 m_eOri
= text::HoriOrientation::LEFT
;
1890 WW8TabBandDesc
* pNewBand
= new WW8TabBandDesc
;
1892 wwSprmParser
aSprmParser(m_pIo
->GetFib());
1894 // process pPap until end of table found
1897 short nTabeDxaNew
= SHRT_MAX
;
1898 bool bTabRowJustRead
= false;
1899 const sal_uInt8
* pShadeSprm
= nullptr;
1900 const sal_uInt8
* pNewShadeSprm
= nullptr;
1901 const sal_uInt8
* pTableBorders
= nullptr;
1902 const sal_uInt8
* pTableBorders90
= nullptr;
1903 std::vector
<const sal_uInt8
*> aTSetBrcs
, aTSetBrc90s
;
1904 WW8_TablePos
*pTabPos
= nullptr;
1906 // search end of a tab row
1907 if(!(m_pIo
->SearchRowEnd(pPap
, nStartCp
, m_pIo
->m_nInTable
)))
1913 // Get the SPRM chains:
1914 // first from PAP and then from PCD (of the Piece Table)
1916 pPap
->GetSprms( &aDesc
);
1917 WW8SprmIter
aSprmIter(aDesc
.pMemPos
, aDesc
.nSprmsLen
, aSprmParser
);
1919 for (int nLoop
= 0; nLoop
< 2; ++nLoop
)
1921 bool bRepeatedSprm
= false;
1922 const sal_uInt8
* pParams
;
1923 while (aSprmIter
.GetSprms() && nullptr != (pParams
= aSprmIter
.GetAktParams()))
1925 sal_uInt16 nId
= aSprmIter
.GetAktId();
1926 wwTableSprm eSprm
= GetTableSprm(nId
, m_pIo
->GetFib().GetFIBVersion());
1929 case sprmTTableWidth
:
1931 const sal_uInt8 b0
= pParams
[0];
1932 const sal_uInt8 b1
= pParams
[1];
1933 const sal_uInt8 b2
= pParams
[2];
1934 if (b0
== 3) // Twips
1935 m_nPreferredWidth
= b2
* 0x100 + b1
;
1939 pNewBand
->ProcessDirection(pParams
);
1941 case sprmTFCantSplit
:
1942 pNewBand
->bCantSplit
= *pParams
;
1943 m_bClaimLineFormat
= true;
1945 case sprmTTableBorders
:
1946 pTableBorders
= pParams
; // process at end
1948 case sprmTTableBorders90
:
1949 pTableBorders90
= pParams
; // process at end
1951 case sprmTTableHeader
:
1955 bRepeatedSprm
= true;
1959 // sprmTJc - Justification Code
1961 m_eOri
= aOriArr
[*pParams
& 0x3];
1964 m_bIsBiDi
= SVBT16ToShort(pParams
) != 0;
1966 case sprmTDxaGapHalf
:
1967 pNewBand
->nGapHalf
= (sal_Int16
)SVBT16ToShort( pParams
);
1969 case sprmTDyaRowHeight
:
1970 pNewBand
->nLineHeight
= (sal_Int16
)SVBT16ToShort( pParams
);
1971 m_bClaimLineFormat
= true;
1974 pNewBand
->ReadDef(bOldVer
, pParams
);
1975 bTabRowJustRead
= true;
1977 case sprmTDefTableShd
:
1978 pShadeSprm
= pParams
;
1980 case sprmTDefTableNewShd
:
1981 pNewShadeSprm
= pParams
;
1984 // our Writer cannot shift single table lines
1985 // horizontally so we have to find the smallest
1986 // parameter (meaning the left-most position) and then
1987 // shift the whole table to that margin (see below)
1989 short nDxaNew
= (sal_Int16
)SVBT16ToShort( pParams
);
1990 m_nOrgDxaLeft
= nDxaNew
;
1991 if( nDxaNew
< nTabeDxaNew
)
1992 nTabeDxaNew
= nDxaNew
;
1996 aTSetBrcs
.push_back(pParams
); // process at end
1999 aTSetBrc90s
.push_back(pParams
); // process at end
2002 pNewBand
->ProcessSprmTDxaCol(pParams
);
2005 pNewBand
->ProcessSprmTInsert(pParams
);
2008 pNewBand
->ProcessSprmTDelete(pParams
);
2010 case sprmTCellPaddingDefault
:
2011 pNewBand
->ProcessSpacing(pParams
);
2013 case sprmTCellPadding
:
2014 pNewBand
->ProcessSpecificSpacing(pParams
);
2019 aSprmIter
.advance();
2024 pPap
->GetPCDSprms( aDesc
);
2025 aSprmIter
.SetSprms( aDesc
.pMemPos
, aDesc
.nSprmsLen
);
2029 // WW-Tables can contain Fly-changes. For this abort tables here
2030 // and start again. *pPap is still before TabRowEnd, so TestApo()
2031 // can be called with the last parameter set to false and therefore
2034 if (bTabRowJustRead
)
2036 // Some SPRMs need to be processed *after* ReadDef is called
2037 // so they were saved up until here
2039 pNewBand
->ReadShd(pShadeSprm
);
2041 pNewBand
->ReadNewShd(pNewShadeSprm
, bOldVer
);
2042 if (pTableBorders90
)
2043 pNewBand
->ProcessSprmTTableBorders(9, pTableBorders90
);
2044 else if (pTableBorders
)
2045 pNewBand
->ProcessSprmTTableBorders(bOldVer
? 6 : 8,
2047 std::vector
<const sal_uInt8
*>::const_iterator iter
;
2048 for (iter
= aTSetBrcs
.begin(); iter
!= aTSetBrcs
.end(); ++iter
)
2049 pNewBand
->ProcessSprmTSetBRC(bOldVer
? 6 : 8, *iter
);
2050 for (iter
= aTSetBrc90s
.begin(); iter
!= aTSetBrc90s
.end(); ++iter
)
2051 pNewBand
->ProcessSprmTSetBRC(9, *iter
);
2054 if( nTabeDxaNew
< SHRT_MAX
)
2056 short* pCenter
= pNewBand
->nCenter
;
2057 short firstDxaCenter
= *pCenter
;
2058 for( int i
= 0; i
< pNewBand
->nWwCols
; i
++, ++pCenter
)
2060 // #i30298# Use sprmTDxaLeft to adjust the left indent
2061 // #i40461# Use dxaGapHalf during calculation
2063 (nTabeDxaNew
- (firstDxaCenter
+ pNewBand
->nGapHalf
));
2068 m_pActBand
= m_pFirstBand
= pNewBand
;
2071 m_pActBand
->pNextBand
= pNewBand
;
2072 m_pActBand
= pNewBand
;
2076 pNewBand
= new WW8TabBandDesc
;
2079 m_pActBand
->nRows
++;
2081 //Seek our pap to its next block of properties
2083 aRes
.pMemPos
= nullptr;
2084 aRes
.nStartPos
= nStartCp
;
2086 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2088 aRes
.nEndPos
= WW8_CP_MAX
;
2089 pPap
->SetDirty(true);
2091 pPap
->GetSprms(&aRes
);
2092 pPap
->SetDirty(false);
2094 //Are we at the end of available properties
2096 !pPap
->HasFkp() || pPap
->Where() == WW8_CP_MAX
||
2097 aRes
.nStartPos
== WW8_CP_MAX
2104 //Are we still in a table cell
2105 const sal_uInt8
* pParams
= HasTabCellSprm(pPap
, bOldVer
);
2106 const sal_uInt8
*pLevel
= pPap
->HasSprm(0x6649);
2108 if (!pParams
|| (1 != *pParams
) ||
2109 (pLevel
&& (*pLevel
<= m_pIo
->m_nInTable
)))
2114 //Get the end of row new table positioning data
2115 WW8_CP nMyStartCp
=nStartCp
;
2116 if (m_pIo
->SearchRowEnd(pPap
, nMyStartCp
, m_pIo
->m_nInTable
))
2117 if (m_pIo
->ParseTabPos(&aTabPos
, pPap
))
2120 //Move back to this cell
2121 aRes
.pMemPos
= nullptr;
2122 aRes
.nStartPos
= nStartCp
;
2124 // PlcxMan currently points too far ahead so we need to bring
2125 // it back to where we are trying to make a table
2126 m_pIo
->m_pPlcxMan
->GetPap()->nOrigStartPos
= aRes
.nStartPos
;
2127 m_pIo
->m_pPlcxMan
->GetPap()->nCpOfs
= aRes
.nCpOfs
;
2128 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2130 aRes
.nEndPos
= WW8_CP_MAX
;
2131 pPap
->SetDirty(true);
2133 pPap
->GetSprms(&aRes
);
2134 pPap
->SetDirty(false);
2136 //Does this row match up with the last row closely enough to be
2137 //considered part of the same table
2138 ApoTestResults aApo
= m_pIo
->TestApo(m_pIo
->m_nInTable
+ 1, false, pTabPos
);
2141 ##513##, #79474# If this is not sufficient, then we should look at
2142 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2143 part of this table, but instead is an absolutely positioned table
2148 if (aApo
.mbStartApo
)
2150 //if there really is a fly here, and not a "null" fly then break.
2151 WW8FlyPara
*pNewFly
= m_pIo
->ConstructApo(aApo
, pTabPos
);
2158 nStartCp
= aRes
.nEndPos
;
2164 if( m_pActBand
->nRows
> 1 )
2166 // last band has more than 1 cell
2168 pNewBand
= new WW8TabBandDesc( *m_pActBand
); // create new
2169 m_pActBand
->nRows
--; // wegen Sonderbehandlung Raender-Defaults
2170 pNewBand
->nRows
= 1;
2171 m_pActBand
->pNextBand
= pNewBand
; // am Ende einschleifen
2173 pNewBand
= nullptr; // do not delete
2179 m_pIo
->m_pPlcxMan
->GetPap()->Restore( aSave
);
2182 WW8TabDesc::~WW8TabDesc()
2184 WW8TabBandDesc
* pR
= m_pFirstBand
;
2187 WW8TabBandDesc
* pR2
= pR
->pNextBand
;
2192 delete m_pParentPos
;
2195 void WW8TabDesc::CalcDefaults()
2197 short nMinCols
= SHRT_MAX
;
2200 m_nMinLeft
= SHRT_MAX
;
2201 m_nMaxRight
= SHRT_MIN
;
2204 If we are an honestly inline centered table, then the normal rules of
2205 engagement for left and right margins do not apply. The multiple rows are
2206 centered regardless of the actual placement of rows, so we cannot have
2207 mismatched rows as is possible in other configurations.
2209 e.g. change the example bugdoc in word from text wrapping of none (inline)
2210 to around (in frame (bApo)) and the table splits into two very disjoint
2211 rows as the beginning point of each row are very different
2213 if ((!m_pIo
->InLocalApo()) && (m_eOri
== text::HoriOrientation::CENTER
))
2215 for (pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2216 for( short i
= pR
->nWwCols
; i
>= 0; --i
)
2217 pR
->nCenter
[i
] = pR
->nCenter
[i
] - pR
->nCenter
[0];
2220 // 1. Durchlauf: aeusserste L- und R-Grenzen finden
2221 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2223 if( pR
->nCenter
[0] < m_nMinLeft
)
2224 m_nMinLeft
= pR
->nCenter
[0];
2226 // Following adjustment moves a border and then uses it to find width
2227 // of next cell, so collect current widths, to avoid situation when width
2228 // adjustment to too narrow cell makes next cell have negative width
2229 short nOrigWidth
[MAX_COL
+ 1];
2230 for( short i
= 0; i
< pR
->nWwCols
; i
++ )
2232 nOrigWidth
[i
] = pR
->nCenter
[i
+1] - pR
->nCenter
[i
];
2235 for( short i
= 0; i
< pR
->nWwCols
; i
++ )
2238 If the margins are so large as to make the displayable
2239 area inside them smaller than the minimum allowed then adjust the
2240 width to fit. But only do it if the two cells are not the exact
2241 same value, if they are then the cell does not really exist and will
2242 be blended together into the same cell through the use of the
2244 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2246 int nCellWidth
= pR
->nCenter
[i
+1] - pR
->nCenter
[i
];
2247 if (nCellWidth
!= nOrigWidth
[i
])
2249 if (nOrigWidth
[i
] == 0)
2250 nCellWidth
= 0; // restore zero-width "cell"
2251 else if ((pR
->nGapHalf
>= nCellWidth
) && (pR
->nGapHalf
< nOrigWidth
[i
]))
2252 nCellWidth
= pR
->nGapHalf
+ 1; // avoid false ignore
2253 else if ((nCellWidth
<= 0) && (nOrigWidth
[i
] > 0))
2254 nCellWidth
= 1; // minimal non-zero width to minimize distortion
2256 if (nCellWidth
&& ((nCellWidth
- pR
->nGapHalf
*2) < MINLAY
) && pR
->nGapHalf
< nCellWidth
)
2258 nCellWidth
= MINLAY
+ pR
->nGapHalf
* 2;
2260 pR
->nCenter
[i
+ 1] = pR
->nCenter
[i
] + nCellWidth
;
2263 if( pR
->nCenter
[pR
->nWwCols
] > m_nMaxRight
)
2264 m_nMaxRight
= pR
->nCenter
[pR
->nWwCols
];
2266 m_nSwWidth
= m_nMaxRight
- m_nMinLeft
;
2268 // If the table is right aligned we need to align all rows to the
2269 // row that has the furthest right point
2271 if(m_eOri
== text::HoriOrientation::RIGHT
)
2273 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2275 int adjust
= m_nMaxRight
- pR
->nCenter
[pR
->nWwCols
];
2276 for( short i
= 0; i
< pR
->nWwCols
+ 1; i
++ )
2278 pR
->nCenter
[i
] = static_cast< short >(pR
->nCenter
[i
] + adjust
);
2284 // 2. pass: Detect number of writer columns. This can exceed the count
2285 // of columns in WW by 2, because SW in constrast to WW does not provide
2286 // fringed left and right borders and has to fill with empty boxes.
2287 // Non existent cells can reduce the number of columns.
2289 // 3. pass: Replace border with defaults if needed
2290 m_nConvertedLeft
= m_nMinLeft
;
2292 short nLeftMaxThickness
= 0, nRightMaxThickness
=0;
2293 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2297 pR
->pTCs
= new WW8_TCell
[ pR
->nWwCols
];
2298 memset( pR
->pTCs
, 0, pR
->nWwCols
* sizeof( WW8_TCell
) );
2300 for (int k
= 0; k
< pR
->nWwCols
; ++k
)
2302 WW8_TCell
* pT
= &pR
->pTCs
[k
];
2304 for( i
= 0; i
< 4; i
++ )
2306 if (pT
->rgbrc
[i
].brcType()==0)
2308 // if shadow is set, its invalid
2313 // outer top / horizontally inside
2314 j
= (pR
== m_pFirstBand
) ? 0 : 4;
2317 // outer left / vertically inside
2321 // outer bottom / horizontally inside
2322 j
= pR
->pNextBand
? 4 : 2;
2325 // outer right / vertically inside
2326 j
= (k
== pR
->nWwCols
- 1) ? 3 : 5;
2329 // mangel mit Defaults ueber
2330 pT
->rgbrc
[i
] = pR
->aDefBrcs
[j
];
2337 Similar to graphics and other elements word does not totally
2338 factor the width of the border into its calculations of size, we
2339 do so we must adjust out widths and other dimensions to fit. It
2340 appears that what occurs is that the last cell's right margin if
2341 the margin width that is not calculated into winwords table
2342 dimensions, so in that case increase the table to include the
2343 extra width of the right margin.
2345 if ( ! pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].fShadow() )
2347 short nThickness
= pR
->pTCs
[pR
->nWwCols
-1].rgbrc
[3].
2348 DetermineBorderProperties();
2349 pR
->nCenter
[pR
->nWwCols
] = pR
->nCenter
[pR
->nWwCols
] + nThickness
;
2350 if (nThickness
> nRightMaxThickness
)
2351 nRightMaxThickness
= nThickness
;
2355 The left space of the table is in nMinLeft, but again this
2356 does not consider the margin thickness to its left in the
2357 placement value, so get the thickness of the left border,
2358 half is placed to the left of the nominal left side, and
2361 if ( ! pR
->pTCs
[0].rgbrc
[1].fShadow() )
2363 short nThickness
= pR
->pTCs
[0].rgbrc
[1].
2364 DetermineBorderProperties();
2365 if (nThickness
> nLeftMaxThickness
)
2366 nLeftMaxThickness
= nThickness
;
2370 m_nSwWidth
= m_nSwWidth
+ nRightMaxThickness
;
2371 m_nMaxRight
= m_nMaxRight
+ nRightMaxThickness
;
2372 m_nConvertedLeft
= m_nMinLeft
-(nLeftMaxThickness
/2);
2374 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2376 pR
->nSwCols
= pR
->nWwCols
;
2377 pR
->bLEmptyCol
= pR
->nCenter
[0] - m_nMinLeft
>= MINLAY
;
2378 pR
->bREmptyCol
= (m_nMaxRight
- pR
->nCenter
[pR
->nWwCols
] - nRightMaxThickness
) >= MINLAY
;
2380 short nAddCols
= short(pR
->bLEmptyCol
) + short(pR
->bREmptyCol
);
2382 sal_uInt16 j
= ( pR
->bLEmptyCol
) ? 1 : 0;
2383 for (i
= 0; i
< pR
->nWwCols
; ++i
)
2385 pR
->nTransCell
[i
] = (sal_Int8
)j
;
2386 if ( pR
->nCenter
[i
] < pR
->nCenter
[i
+1] )
2388 pR
->bExist
[i
] = true;
2393 pR
->bExist
[i
] = false;
2398 OSL_ENSURE(i
,"no columns in row ?");
2401 If the last cell was "false" then there is no valid cell following it,
2402 so the default mapping forward won't work. So map it (and
2403 contiguous invalid cells backwards to the last valid cell instead.)
2405 if (i
&& !pR
->bExist
[i
-1])
2408 while (k
&& !pR
->bExist
[k
])
2410 for (sal_uInt16 n
=k
+1;n
<i
;n
++)
2411 pR
->nTransCell
[n
] = pR
->nTransCell
[k
];
2414 pR
->nTransCell
[i
++] = (sal_Int8
)(j
++); // Can exceed by 2 among other
2415 pR
->nTransCell
[i
] = (sal_Int8
)j
; // things because of bREmptyCol
2417 pR
->nSwCols
= pR
->nSwCols
+ nAddCols
;
2418 if( pR
->nSwCols
< nMinCols
)
2419 nMinCols
= pR
->nSwCols
;
2424 Find the largest of the borders on cells that adjoin top bottom and remove
2425 the val from the top and put in on the bottom cell. I can't seem to make
2426 disjoint upper and lowers to see what happens there.
2429 if ((m_nMinLeft
&& !m_bIsBiDi
&& text::HoriOrientation::LEFT
== m_eOri
) ||
2430 (m_nMinLeft
!= -108 && m_bIsBiDi
&& text::HoriOrientation::RIGHT
== m_eOri
)) // Word sets the first nCenter value to -108 when no indent is used
2431 m_eOri
= text::HoriOrientation::LEFT_AND_WIDTH
; // absolutely positioned
2433 m_nDefaultSwCols
= nMinCols
; // because inserting cells is cheaper than merging
2434 if( m_nDefaultSwCols
== 0 )
2436 m_pActBand
= m_pFirstBand
;
2438 OSL_ENSURE( m_pActBand
, "pActBand ist 0" );
2441 void WW8TabDesc::SetSizePosition(SwFrameFormat
* pFrameFormat
)
2443 SwFrameFormat
* pApply
= pFrameFormat
;
2445 pApply
= m_pTable
->GetFrameFormat();
2446 OSL_ENSURE(pApply
,"No frame");
2447 pApply
->SetFormatAttr(m_aItemSet
);
2450 SwFormatFrameSize aSize
= pFrameFormat
->GetFrameSize();
2451 aSize
.SetHeightSizeType(ATT_MIN_SIZE
);
2452 aSize
.SetHeight(MINLAY
);
2453 pFrameFormat
->SetFormatAttr(aSize
);
2454 m_pTable
->GetFrameFormat()->SetFormatAttr(SwFormatHoriOrient(0,text::HoriOrientation::FULL
));
2458 void wwSectionManager::PrependedInlineNode(const SwPosition
&rPos
,
2459 const SwNode
&rNode
)
2461 OSL_ENSURE(!maSegments
.empty(),
2462 "should not be possible, must be at least one segment");
2463 if ((!maSegments
.empty()) && (maSegments
.back().maStart
== rPos
.nNode
))
2464 maSegments
.back().maStart
.Assign(rNode
);
2467 void WW8TabDesc::CreateSwTable()
2469 ::SetProgressState(m_pIo
->m_nProgress
, m_pIo
->m_pDocShell
); // Update
2471 // if there is already some content on the Node append new node to ensure
2472 // that this content remains ABOVE the table
2473 SwPosition
* pPoint
= m_pIo
->m_pPaM
->GetPoint();
2474 bool bInsNode
= pPoint
->nContent
.GetIndex() != 0;
2475 bool bSetMinHeight
= false;
2479 Set fly anchor to its anchor pos, so that if a table starts immediately
2480 at this position a new node will be inserted before inserting the table.
2482 if (!bInsNode
&& m_pIo
->m_pFormatOfJustInsertedApo
)
2484 const SwPosition
* pAPos
=
2485 m_pIo
->m_pFormatOfJustInsertedApo
->GetAnchor().GetContentAnchor();
2486 if (pAPos
&& &pAPos
->nNode
.GetNode() == &pPoint
->nNode
.GetNode())
2489 bSetMinHeight
= true;
2491 SwFormatSurround
aSur(m_pIo
->m_pFormatOfJustInsertedApo
->GetSurround());
2492 aSur
.SetAnchorOnly(true);
2493 m_pIo
->m_pFormatOfJustInsertedApo
->SetFormatAttr(aSur
);
2499 // minimize Fontsize to minimize height growth of the header/footer
2500 // set font size to 1 point to minimize y-growth of Hd/Ft
2501 SvxFontHeightItem
aSz(20, 100, RES_CHRATR_FONTSIZE
);
2502 m_pIo
->NewAttr( aSz
);
2503 m_pIo
->m_pCtrlStck
->SetAttr(*pPoint
, RES_CHRATR_FONTSIZE
);
2507 m_pIo
->AppendTextNode(*pPoint
);
2509 m_pTmpPos
= new SwPosition( *m_pIo
->m_pPaM
->GetPoint() );
2511 // The table is small: The number of columns is the lowest count of
2512 // columns of the origin, because inserting is faster than deleting.
2513 // The number of rows is the count of bands because (identically)
2514 // rows of a band can be duplicated easy.
2515 m_pTable
= m_pIo
->m_rDoc
.InsertTable(
2516 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER
, 0 ),
2517 *m_pTmpPos
, m_nBands
, m_nDefaultSwCols
, m_eOri
);
2519 OSL_ENSURE(m_pTable
&& m_pTable
->GetFrameFormat(), "insert table failed");
2520 if (!m_pTable
|| !m_pTable
->GetFrameFormat())
2523 SwTableNode
* pTableNode
= m_pTable
->GetTableNode();
2524 OSL_ENSURE(pTableNode
, "no table node!");
2527 m_pIo
->m_aSectionManager
.PrependedInlineNode(*m_pIo
->m_pPaM
->GetPoint(),
2531 // Check if the node into which the table should be inserted already
2532 // contains a Pagedesc. If so that Pagedesc would be moved to the
2533 // row after the table, whats wrong. So delete and
2534 // set later to the table format.
2535 if (SwTextNode
*const pNd
= m_pTmpPos
->nNode
.GetNode().GetTextNode())
2537 if (const SfxItemSet
* pSet
= pNd
->GetpSwAttrSet())
2539 SfxPoolItem
*pSetAttr
= nullptr;
2540 const SfxPoolItem
* pItem
;
2541 if (SfxItemState::SET
== pSet
->GetItemState(RES_BREAK
, false, &pItem
))
2543 pSetAttr
= new SvxFormatBreakItem( *static_cast<const SvxFormatBreakItem
*>(pItem
) );
2544 pNd
->ResetAttr( RES_BREAK
);
2547 // eventually set the PageDesc/Break now to the table
2550 m_aItemSet
.Put(*pSetAttr
);
2556 // total width of table
2557 if( m_nMaxRight
- m_nMinLeft
> MINLAY
* m_nDefaultSwCols
)
2559 m_pTable
->GetFrameFormat()->SetFormatAttr(SwFormatFrameSize(ATT_FIX_SIZE
, m_nSwWidth
));
2560 m_aItemSet
.Put(SwFormatFrameSize(ATT_FIX_SIZE
, m_nSwWidth
));
2563 SvxFrameDirectionItem
aDirection(
2564 m_bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
, RES_FRAMEDIR
);
2565 m_pTable
->GetFrameFormat()->SetFormatAttr(aDirection
);
2567 if (text::HoriOrientation::LEFT_AND_WIDTH
== m_eOri
)
2569 if (!m_pIo
->m_nInTable
&& m_pIo
->InLocalApo() && m_pIo
->m_pSFlyPara
->pFlyFormat
&&
2572 //If we are inside a frame and we have a border, the frames
2573 //placement does not consider the tables border, which word
2574 //displays outside the frame, so adjust here.
2575 SwFormatHoriOrient
aHori(m_pIo
->m_pSFlyPara
->pFlyFormat
->GetHoriOrient());
2576 sal_Int16 eHori
= aHori
.GetHoriOrient();
2577 if ((eHori
== text::HoriOrientation::NONE
) || (eHori
== text::HoriOrientation::LEFT
) ||
2578 (eHori
== text::HoriOrientation::LEFT_AND_WIDTH
))
2580 //With multiple table, use last table settings. Perhaps
2581 //the maximum is what word does ?
2582 aHori
.SetPos(m_pIo
->m_pSFlyPara
->nXPos
+ GetMinLeft());
2583 aHori
.SetHoriOrient(text::HoriOrientation::NONE
);
2584 m_pIo
->m_pSFlyPara
->pFlyFormat
->SetFormatAttr(aHori
);
2589 //If bApo is set, then this table is being placed in a floating
2590 //frame, and the frame matches the left and right *lines* of the
2591 //table, so the space to the left of the table isn't to be used
2592 //inside the frame, in word the dialog involved greys out the
2593 //ability to set the margin.
2594 SvxLRSpaceItem
aL( RES_LR_SPACE
);
2595 // set right to original DxaLeft (i28656)
2599 nLeft
= GetMinLeft();
2602 if (m_nPreferredWidth
)
2604 nLeft
= m_pIo
->m_aSectionManager
.GetTextAreaWidth();
2605 nLeft
= nLeft
- m_nPreferredWidth
- m_nOrgDxaLeft
;
2608 nLeft
= -GetMinLeft();
2617 mpOldRedlineStack
= m_pIo
->m_pRedlineStack
;
2618 m_pIo
->m_pRedlineStack
= new sw::util::RedlineStack(m_pIo
->m_rDoc
);
2621 void WW8TabDesc::UseSwTable()
2624 m_pTabLines
= &m_pTable
->GetTabLines();
2625 m_nAktRow
= m_nAktCol
= m_nAktBandRow
= 0;
2627 m_pTableNd
= const_cast<SwTableNode
*>((*m_pTabLines
)[0]->GetTabBoxes()[0]->
2628 GetSttNd()->FindTableNode());
2629 OSL_ENSURE( m_pTableNd
, "wo ist mein TabellenNode" );
2631 // #i69519# - Restrict rows to repeat to a decent value
2632 if ( m_nRowsToRepeat
== static_cast<sal_uInt16
>(m_nRows
) )
2633 m_nRowsToRepeat
= 1;
2635 m_pTableNd
->GetTable().SetRowsToRepeat( m_nRowsToRepeat
);
2636 // insert extra cells if needed and something like this
2639 WW8DupProperties
aDup(m_pIo
->m_rDoc
,m_pIo
->m_pCtrlStck
);
2640 m_pIo
->m_pCtrlStck
->SetAttr(*m_pIo
->m_pPaM
->GetPoint(), 0, false);
2642 // now set the correct PaM and prepare first merger group if any
2643 SetPamInCell(m_nAktCol
, true);
2644 aDup
.Insert(*m_pIo
->m_pPaM
->GetPoint());
2646 m_pIo
->m_bWasTabRowEnd
= false;
2647 m_pIo
->m_bWasTabCellEnd
= false;
2650 void WW8TabDesc::MergeCells()
2654 for (m_pActBand
=m_pFirstBand
, nRow
=0; m_pActBand
; m_pActBand
=m_pActBand
->pNextBand
)
2656 // insert current box into merge group if appropriate.
2657 // The algorithm must ensure proper row and column order in WW8SelBoxInfo!
2658 if( m_pActBand
->pTCs
)
2660 for( short j
= 0; j
< m_pActBand
->nRows
; j
++, nRow
++ )
2661 for( short i
= 0; i
< m_pActBand
->nWwCols
; i
++ )
2663 WW8SelBoxInfo
* pActMGroup
= nullptr;
2665 // start a new merge group if appropriate
2667 OSL_ENSURE(nRow
< (sal_uInt16
)m_pTabLines
->size(),
2668 "Too few lines, table ended early");
2669 if (nRow
>= (sal_uInt16
)m_pTabLines
->size())
2671 m_pTabLine
= (*m_pTabLines
)[ nRow
];
2672 m_pTabBoxes
= &m_pTabLine
->GetTabBoxes();
2674 sal_uInt16 nCol
= m_pActBand
->nTransCell
[ i
];
2675 if (!m_pActBand
->bExist
[i
])
2677 OSL_ENSURE(nCol
< m_pTabBoxes
->size(),
2678 "Too few columns, table ended early");
2679 if (nCol
>= m_pTabBoxes
->size())
2681 m_pTabBox
= (*m_pTabBoxes
)[nCol
];
2682 WW8_TCell
& rCell
= m_pActBand
->pTCs
[ i
];
2683 // is this the left upper cell of a merge group ?
2685 bool bMerge
= false;
2686 if ( rCell
.bVertRestart
&& !rCell
.bMerged
)
2688 else if (rCell
.bFirstMerged
&& m_pActBand
->bExist
[i
])
2690 // Some tests to avoid merging cells which previously were
2691 // declared invalid because of sharing the exact same dimensions
2692 // as their previous cell
2694 //If theres anything underneath/above we're ok.
2695 if (rCell
.bVertMerge
|| rCell
.bVertRestart
)
2699 //If it's a hori merge only, and the only things in
2700 //it are invalid cells then it's already taken care
2701 //of, so don't merge.
2702 for (sal_uInt16 i2
= i
+1; i2
< m_pActBand
->nWwCols
; i2
++ )
2703 if (m_pActBand
->pTCs
[ i2
].bMerged
&&
2704 !m_pActBand
->pTCs
[ i2
].bFirstMerged
)
2706 if (m_pActBand
->bExist
[i2
])
2719 short nX1
= m_pActBand
->nCenter
[ i
];
2720 short nWidth
= m_pActBand
->nWidth
[ i
];
2722 // 2. create current merge group
2723 pActMGroup
= new WW8SelBoxInfo( nX1
, nWidth
);
2725 // determine size of new merge group
2726 // before inserted the new merge group.
2727 // Needed to correctly locked previously created merge groups.
2728 // Calculate total width and set
2729 short nSizCell
= m_pActBand
->nWidth
[ i
];
2730 for (sal_uInt16 i2
= i
+1; i2
< m_pActBand
->nWwCols
; i2
++ )
2731 if (m_pActBand
->pTCs
[ i2
].bMerged
&&
2732 !m_pActBand
->pTCs
[ i2
].bFirstMerged
)
2734 nSizCell
= nSizCell
+ m_pActBand
->nWidth
[ i2
];
2738 pActMGroup
->nGroupWidth
= nSizCell
;
2740 // locked previously created merge groups,
2741 // after determining the size for the new merge group.
2742 // 1. If necessary close old merge group(s) that overlap
2743 // the X-area of the new group
2746 WW8SelBoxInfo
* p
= FindMergeGroup(
2747 nX1
, pActMGroup
->nGroupWidth
, false );
2752 p
->bGroupLocked
= true;
2755 // 3. push to group array
2756 m_MergeGroups
.push_back(std::unique_ptr
<WW8SelBoxInfo
>(pActMGroup
));
2759 // if necessary add the current box to a merge group
2760 // (that can be a newly created or another group)
2761 UpdateTableMergeGroup( rCell
, pActMGroup
, m_pTabBox
, i
);
2767 //There is a limbo area in word at the end of the row marker
2768 //where properties can live in word, there is no location in
2769 //writer equivalent, so try and park the cursor in the best
2770 //match, see #i23022#/#i18644#
2771 void WW8TabDesc::ParkPaM()
2773 SwTableBox
*pTabBox2
= nullptr;
2774 short nRow
= m_nAktRow
+ 1;
2775 if (nRow
< (sal_uInt16
)m_pTabLines
->size())
2777 if (SwTableLine
*pLine
= (*m_pTabLines
)[nRow
])
2779 SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
2780 pTabBox2
= rBoxes
.empty() ? nullptr : rBoxes
.front();
2784 if (!pTabBox2
|| !pTabBox2
->GetSttNd())
2790 sal_uLong nSttNd
= pTabBox2
->GetSttIdx() + 1,
2791 nEndNd
= pTabBox2
->GetSttNd()->EndOfSectionIndex();
2793 if (m_pIo
->m_pPaM
->GetPoint()->nNode
!= nSttNd
)
2797 m_pIo
->m_pPaM
->GetPoint()->nNode
= nSttNd
;
2799 while (m_pIo
->m_pPaM
->GetNode().GetNodeType() != SwNodeType::Text
&& ++nSttNd
< nEndNd
);
2801 m_pIo
->m_pPaM
->GetPoint()->nContent
.Assign(m_pIo
->m_pPaM
->GetContentNode(), 0);
2802 m_pIo
->m_rDoc
.SetTextFormatColl(*m_pIo
->m_pPaM
, const_cast<SwTextFormatColl
*>(m_pIo
->m_pDfltTextFormatColl
));
2806 void WW8TabDesc::MoveOutsideTable()
2808 OSL_ENSURE(m_pTmpPos
&& m_pIo
, "I've forgotten where the table is anchored");
2809 if (m_pTmpPos
&& m_pIo
)
2810 *m_pIo
->m_pPaM
->GetPoint() = *m_pTmpPos
;
2813 void WW8TabDesc::FinishSwTable()
2815 m_pIo
->m_pRedlineStack
->closeall(*m_pIo
->m_pPaM
->GetPoint());
2816 delete m_pIo
->m_pRedlineStack
;
2817 m_pIo
->m_pRedlineStack
= mpOldRedlineStack
;
2818 mpOldRedlineStack
= nullptr;
2820 WW8DupProperties
aDup(m_pIo
->m_rDoc
,m_pIo
->m_pCtrlStck
);
2821 m_pIo
->m_pCtrlStck
->SetAttr( *m_pIo
->m_pPaM
->GetPoint(), 0, false);
2825 m_pTmpPos
= nullptr;
2827 aDup
.Insert(*m_pIo
->m_pPaM
->GetPoint());
2829 m_pIo
->m_bWasTabRowEnd
= false;
2830 m_pIo
->m_bWasTabCellEnd
= false;
2832 m_pIo
->m_aInsertedTables
.InsertTable(*m_pTableNd
, *m_pIo
->m_pPaM
);
2836 // if needed group cells together that should be merged
2837 if (!m_MergeGroups
.empty())
2839 // process all merge groups one by one
2840 for (auto const& groupIt
: m_MergeGroups
)
2842 if((1 < groupIt
->size()) && groupIt
->row(0)[0])
2844 SwFrameFormat
* pNewFormat
= groupIt
->row(0)[0]->ClaimFrameFormat();
2845 pNewFormat
->SetFormatAttr(SwFormatFrameSize(ATT_VAR_SIZE
, groupIt
->nGroupWidth
, 0));
2846 const sal_uInt16 nRowSpan
= groupIt
->rowsCount();
2847 for (sal_uInt16 n
= 0; n
< nRowSpan
; ++n
)
2849 auto& rRow
= groupIt
->row(n
);
2850 for (size_t i
= 0; i
<rRow
.size(); ++i
)
2852 const long nRowSpanSet
= (n
== 0) && (i
== 0) ?
2854 ((-1) * (nRowSpan
- n
));
2855 SwTableBox
* pCurrentBox
= rRow
[i
];
2856 pCurrentBox
->setRowSpan(nRowSpanSet
);
2859 pCurrentBox
->ChgFrameFormat(static_cast<SwTableBoxFormat
*>(pNewFormat
));
2862 SwFrameFormat
* pFormat
= pCurrentBox
->ClaimFrameFormat();
2863 pFormat
->SetFormatAttr(SwFormatFrameSize(ATT_VAR_SIZE
, 0, 0));
2869 m_pIo
->m_pFormatOfJustInsertedApo
= nullptr;
2870 m_MergeGroups
.clear();
2874 // browse m_MergeGroups, detect the index of the first fitting group or -1 otherwise
2876 // Parameter: nXcenter = center position of asking box
2877 // nWidth = width of asking box
2878 // bExact = flag, if box has to fit into group
2879 // or only has to touch
2881 WW8SelBoxInfo
* WW8TabDesc::FindMergeGroup(short nX1
, short nWidth
, bool bExact
)
2883 if (!m_MergeGroups
.empty())
2885 // still valid area near the boundery
2886 const short nToleranz
= 4;
2888 short nX2
= nX1
+ nWidth
;
2889 // approximate group boundery
2893 // improvement: search backwards
2894 for (short iGr
= m_MergeGroups
.size() - 1; iGr
>= 0; --iGr
)
2896 // the currently inspected group
2897 WW8SelBoxInfo
& rActGroup
= *m_MergeGroups
[ iGr
];
2898 if (!rActGroup
.bGroupLocked
)
2900 // approximate group boundery with room (tolerance) to the *outside*
2901 nGrX1
= rActGroup
.nGroupXStart
- nToleranz
;
2902 nGrX2
= rActGroup
.nGroupXStart
2903 +rActGroup
.nGroupWidth
+ nToleranz
;
2905 // If box fits report success
2907 if( ( nX1
> nGrX1
) && ( nX2
< nGrX2
) )
2912 // does the box share areas with the group?
2916 // successful if nX1 *or* nX2 are inside the group
2917 if( ( ( nX1
> nGrX1
)
2918 && ( nX1
< nGrX2
- 2*nToleranz
) )
2919 || ( ( nX2
> nGrX1
+ 2*nToleranz
)
2920 && ( nX2
< nGrX2
) )
2921 // or nX1 and nX2 surround the group
2922 || ( ( nX1
<=nGrX1
)
2923 && ( nX2
>=nGrX2
) ) )
2934 bool WW8TabDesc::IsValidCell(short nCol
) const
2936 return (static_cast<size_t>(nCol
) < SAL_N_ELEMENTS(m_pActBand
->bExist
)) &&
2937 m_pActBand
->bExist
[nCol
] &&
2938 (sal_uInt16
)m_nAktRow
< m_pTabLines
->size();
2941 bool WW8TabDesc::InFirstParaInCell() const
2944 if (!m_pTabBox
|| !m_pTabBox
->GetSttNd())
2946 OSL_FAIL("Problem with table");
2950 if (!IsValidCell(GetAktCol()))
2953 if (m_pIo
->m_pPaM
->GetPoint()->nNode
== m_pTabBox
->GetSttIdx() + 1)
2959 void WW8TabDesc::StartMiserableHackForUnsupportedDirection(short nWwCol
)
2961 OSL_ENSURE(m_pActBand
, "Impossible");
2962 if (m_pActBand
&& m_pActBand
->maDirections
[nWwCol
] == 3)
2964 m_pIo
->m_pCtrlStck
->NewAttr(*m_pIo
->m_pPaM
->GetPoint(),
2965 SvxCharRotateItem(900, false, RES_CHRATR_ROTATE
));
2969 void WW8TabDesc::EndMiserableHackForUnsupportedDirection(short nWwCol
)
2971 OSL_ENSURE(m_pActBand
, "Impossible");
2972 if (m_pActBand
&& m_pActBand
->maDirections
[nWwCol
] == 3)
2973 m_pIo
->m_pCtrlStck
->SetAttr(*m_pIo
->m_pPaM
->GetPoint(), RES_CHRATR_ROTATE
);
2976 void WW8TabDesc::SetPamInCell(short nWwCol
, bool bPam
)
2978 OSL_ENSURE( m_pActBand
, "pActBand ist 0" );
2982 sal_uInt16 nCol
= m_pActBand
->transCell(nWwCol
);
2984 if ((sal_uInt16
)m_nAktRow
>= m_pTabLines
->size())
2986 OSL_ENSURE(false, "Actual row bigger than expected." );
2992 m_pTabLine
= (*m_pTabLines
)[m_nAktRow
];
2993 m_pTabBoxes
= &m_pTabLine
->GetTabBoxes();
2995 if (nCol
>= m_pTabBoxes
->size())
2999 // The first paragraph in a cell with upper autospacing has upper
3002 m_pIo
->m_bParaAutoBefore
&& m_pIo
->m_bFirstPara
&&
3003 !m_pIo
->m_pWDop
->fDontUseHTMLAutoSpacing
3006 m_pIo
->SetUpperSpacing(*m_pIo
->m_pPaM
, 0);
3009 // The last paragraph in a cell with lower autospacing has lower
3011 if (m_pIo
->m_bParaAutoAfter
&& !m_pIo
->m_pWDop
->fDontUseHTMLAutoSpacing
)
3012 m_pIo
->SetLowerSpacing(*m_pIo
->m_pPaM
, 0);
3018 m_pTabBox
= (*m_pTabBoxes
)[nCol
];
3019 if( !m_pTabBox
->GetSttNd() )
3021 OSL_ENSURE(m_pTabBox
->GetSttNd(), "Probleme beim Aufbau der Tabelle");
3028 m_pAktWWCell
= &m_pActBand
->pTCs
[ nWwCol
];
3030 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
3031 if(m_pIo
->m_bParaAutoBefore
&& m_pIo
->m_bFirstPara
&& !m_pIo
->m_pWDop
->fDontUseHTMLAutoSpacing
)
3032 m_pIo
->SetUpperSpacing(*m_pIo
->m_pPaM
, 0);
3034 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
3035 if(m_pIo
->m_bParaAutoAfter
&& !m_pIo
->m_pWDop
->fDontUseHTMLAutoSpacing
)
3036 m_pIo
->SetLowerSpacing(*m_pIo
->m_pPaM
, 0);
3038 //We need to set the pPaM on the first cell, invalid
3039 //or not so that we can collect paragraph properties over
3040 //all the cells, but in that case on the valid cell we do not
3041 //want to reset the fmt properties
3042 sal_uLong nSttNd
= m_pTabBox
->GetSttIdx() + 1,
3043 nEndNd
= m_pTabBox
->GetSttNd()->EndOfSectionIndex();
3044 if (m_pIo
->m_pPaM
->GetPoint()->nNode
!= nSttNd
)
3048 m_pIo
->m_pPaM
->GetPoint()->nNode
= nSttNd
;
3050 while (m_pIo
->m_pPaM
->GetNode().GetNodeType() != SwNodeType::Text
&& ++nSttNd
< nEndNd
);
3051 m_pIo
->m_pPaM
->GetPoint()->nContent
.Assign(m_pIo
->m_pPaM
->GetContentNode(), 0);
3052 // Precautionally set now, otherwise the style is not set for cells
3053 // that are inserted for margin balancing.
3054 m_pIo
->m_rDoc
.SetTextFormatColl(*m_pIo
->m_pPaM
, const_cast<SwTextFormatColl
*>(m_pIo
->m_pDfltTextFormatColl
));
3055 // because this cells are invisible helper constructions only to simulate
3056 // the frayed view of WW-tables we do NOT need SetTextFormatCollAndListLevel()
3059 // Better to turn Snap to Grid off for all paragraphs in tables
3060 if(SwTextNode
*pNd
= m_pIo
->m_pPaM
->GetNode().GetTextNode())
3062 const SfxPoolItem
&rItm
= pNd
->SwContentNode::GetAttr(RES_PARATR_SNAPTOGRID
);
3063 const SvxParaGridItem
&rSnapToGrid
= static_cast<const SvxParaGridItem
&>(rItm
);
3065 if(rSnapToGrid
.GetValue())
3067 SvxParaGridItem
aGridItem( rSnapToGrid
);
3068 aGridItem
.SetValue(false);
3070 SwPosition
* pGridPos
= m_pIo
->m_pPaM
->GetPoint();
3072 const sal_Int32 nEnd
= pGridPos
->nContent
.GetIndex();
3073 pGridPos
->nContent
.Assign(m_pIo
->m_pPaM
->GetContentNode(), 0);
3074 m_pIo
->m_pCtrlStck
->NewAttr(*pGridPos
, aGridItem
);
3075 pGridPos
->nContent
.Assign(m_pIo
->m_pPaM
->GetContentNode(), nEnd
);
3076 m_pIo
->m_pCtrlStck
->SetAttr(*pGridPos
, RES_PARATR_SNAPTOGRID
);
3080 StartMiserableHackForUnsupportedDirection(nWwCol
);
3084 void WW8TabDesc::InsertCells( short nIns
)
3086 m_pTabLine
= (*m_pTabLines
)[m_nAktRow
];
3087 m_pTabBoxes
= &m_pTabLine
->GetTabBoxes();
3088 m_pTabBox
= (*m_pTabBoxes
)[0];
3090 m_pIo
->m_rDoc
.GetNodes().InsBoxen( m_pTableNd
, m_pTabLine
, static_cast<SwTableBoxFormat
*>(m_pTabBox
->GetFrameFormat()),
3091 const_cast<SwTextFormatColl
*>(m_pIo
->m_pDfltTextFormatColl
), nullptr, m_pTabBoxes
->size(), nIns
);
3092 // The third parameter contains the FrameFormat of the boxes.
3093 // Here it is possible to optimize to save (reduce) FrameFormats.
3096 void WW8TabDesc::SetTabBorders(SwTableBox
* pBox
, short nWwIdx
)
3098 if( nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3099 return; // faked cells -> no border
3101 SvxBoxItem
aFormatBox( RES_BOX
);
3102 if (m_pActBand
->pTCs
) // neither Cell Border nor Default Border defined ?
3104 WW8_TCell
* pT
= &m_pActBand
->pTCs
[nWwIdx
];
3105 if (SwWW8ImplReader::IsBorder(pT
->rgbrc
))
3106 SwWW8ImplReader::SetBorder(aFormatBox
, pT
->rgbrc
);
3109 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwTOP
))
3111 aFormatBox
.SetDistance(
3112 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwTOP
],
3113 SvxBoxItemLine::TOP
);
3116 aFormatBox
.SetDistance(m_pActBand
->mnDefaultTop
, SvxBoxItemLine::TOP
);
3117 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwBOTTOM
))
3119 aFormatBox
.SetDistance(
3120 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwBOTTOM
],
3121 SvxBoxItemLine::BOTTOM
);
3124 aFormatBox
.SetDistance(m_pActBand
->mnDefaultBottom
,SvxBoxItemLine::BOTTOM
);
3126 // nGapHalf for WW is a *horizontal* gap between table cell and content.
3128 m_pActBand
->mbHasSpacing
? m_pActBand
->mnDefaultLeft
: m_pActBand
->nGapHalf
;
3130 m_pActBand
->mbHasSpacing
? m_pActBand
->mnDefaultRight
: m_pActBand
->nGapHalf
;
3131 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwLEFT
))
3133 aFormatBox
.SetDistance(
3134 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwLEFT
],
3135 SvxBoxItemLine::LEFT
);
3138 aFormatBox
.SetDistance(nLeftDist
, SvxBoxItemLine::LEFT
);
3139 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwRIGHT
))
3141 aFormatBox
.SetDistance(
3142 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwRIGHT
],
3143 SvxBoxItemLine::RIGHT
);
3146 aFormatBox
.SetDistance(nRightDist
,SvxBoxItemLine::RIGHT
);
3148 pBox
->GetFrameFormat()->SetFormatAttr(aFormatBox
);
3151 void WW8TabDesc::SetTabShades( SwTableBox
* pBox
, short nWwIdx
)
3153 if( nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3154 return; // faked cells -> no color
3157 if (m_pActBand
->pNewSHDs
&& m_pActBand
->pNewSHDs
[nWwIdx
] != COL_AUTO
)
3159 Color
aColor(m_pActBand
->pNewSHDs
[nWwIdx
]);
3160 pBox
->GetFrameFormat()->SetFormatAttr(SvxBrushItem(aColor
, RES_BACKGROUND
));
3164 //If there was no new shades, or no new shade setting
3165 if (m_pActBand
->pSHDs
&& !bFound
)
3167 WW8_SHD
& rSHD
= m_pActBand
->pSHDs
[nWwIdx
];
3168 if (!rSHD
.GetValue()) // auto
3171 SwWW8Shade
aSh( m_pIo
->m_bVer67
, rSHD
);
3172 pBox
->GetFrameFormat()->SetFormatAttr(SvxBrushItem(aSh
.aColor
, RES_BACKGROUND
));
3176 SvxFrameDirection
MakeDirection(sal_uInt16 nCode
, bool bIsBiDi
)
3178 SvxFrameDirection eDir
= FRMDIR_ENVIRONMENT
;
3179 // 1: Asian layout with rotated CJK characters
3181 // 3: Western layout rotated by 90 degrees
3182 // 4: Western layout
3186 OSL_ENSURE(eDir
== 4, "unknown direction code, maybe it's a bitfield");
3189 eDir
= bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
; // #i38158# - Consider RTL tables
3192 eDir
= FRMDIR_VERT_TOP_RIGHT
;
3195 eDir
= FRMDIR_VERT_TOP_RIGHT
;
3198 eDir
= bIsBiDi
? FRMDIR_HORI_RIGHT_TOP
: FRMDIR_HORI_LEFT_TOP
; // #i38158# - Consider RTL tables
3204 void WW8TabDesc::SetTabDirection(SwTableBox
* pBox
, short nWwIdx
)
3206 if (nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3208 SvxFrameDirectionItem
aItem(MakeDirection(m_pActBand
->maDirections
[nWwIdx
], m_bIsBiDi
), RES_FRAMEDIR
);
3209 pBox
->GetFrameFormat()->SetFormatAttr(aItem
);
3212 void WW8TabDesc::SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
)
3214 if( nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3217 sal_Int16 eVertOri
=text::VertOrientation::TOP
;
3219 if( m_pActBand
->pTCs
)
3221 WW8_TCell
* pT
= &m_pActBand
->pTCs
[nWwIdx
];
3222 switch (pT
->nVertAlign
)
3226 eVertOri
= text::VertOrientation::TOP
;
3229 eVertOri
= text::VertOrientation::CENTER
;
3232 eVertOri
= text::VertOrientation::BOTTOM
;
3237 pBox
->GetFrameFormat()->SetFormatAttr( SwFormatVertOrient(0,eVertOri
) );
3240 void WW8TabDesc::AdjustNewBand()
3242 if( m_pActBand
->nSwCols
> m_nDefaultSwCols
) // split cells
3243 InsertCells( m_pActBand
->nSwCols
- m_nDefaultSwCols
);
3245 SetPamInCell( 0, false);
3246 OSL_ENSURE( m_pTabBoxes
&& m_pTabBoxes
->size() == (sal_uInt16
)m_pActBand
->nSwCols
,
3247 "Falsche Spaltenzahl in Tabelle" );
3249 if( m_bClaimLineFormat
)
3251 m_pTabLine
->ClaimFrameFormat(); // necessary because of cell height
3252 SwFormatFrameSize
aF( ATT_MIN_SIZE
, 0, 0 ); // default
3254 if (m_pActBand
->nLineHeight
== 0) // 0 = Auto
3255 aF
.SetHeightSizeType( ATT_VAR_SIZE
);
3258 if (m_pActBand
->nLineHeight
< 0) // positive = min, negative = exact
3260 aF
.SetHeightSizeType(ATT_FIX_SIZE
);
3261 m_pActBand
->nLineHeight
= -m_pActBand
->nLineHeight
;
3263 if (m_pActBand
->nLineHeight
< MINLAY
) // invalid cell height
3264 m_pActBand
->nLineHeight
= MINLAY
;
3266 aF
.SetHeight(m_pActBand
->nLineHeight
);// set min/exact height
3268 m_pTabLine
->GetFrameFormat()->SetFormatAttr(aF
);
3271 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3272 //we can split the row
3273 bool bSetCantSplit
= m_pActBand
->bCantSplit
;
3274 m_pTabLine
->GetFrameFormat()->SetFormatAttr(SwFormatRowSplit(!bSetCantSplit
));
3276 // if table is only a single row, and row is set as don't split, set the same value for the whole table.
3277 if( bSetCantSplit
&& m_pTabLines
->size() == 1 )
3278 m_pTable
->GetFrameFormat()->SetFormatAttr(SwFormatLayoutSplit( !bSetCantSplit
));
3280 short i
; // SW-Index
3281 short j
; // WW-Index
3283 SwFormatFrameSize
aFS( ATT_FIX_SIZE
);
3284 j
= m_pActBand
->bLEmptyCol
? -1 : 0;
3286 for( i
= 0; i
< m_pActBand
->nSwCols
; i
++ )
3290 nW
= m_pActBand
->nCenter
[0] - m_nMinLeft
;
3293 //Set j to first non invalid cell
3294 while ((j
< m_pActBand
->nWwCols
) && (!m_pActBand
->bExist
[j
]))
3297 if( j
< m_pActBand
->nWwCols
)
3298 nW
= m_pActBand
->nCenter
[j
+1] - m_pActBand
->nCenter
[j
];
3300 nW
= m_nMaxRight
- m_pActBand
->nCenter
[j
];
3301 m_pActBand
->nWidth
[ j
] = nW
;
3304 SwTableBox
* pBox
= (*m_pTabBoxes
)[i
];
3305 // could be reduced further by intelligent moving of FrameFormats
3306 pBox
->ClaimFrameFormat();
3308 SetTabBorders(pBox
, j
);
3310 // #i18128# word has only one line between adjoining vertical cells
3311 // we have to mimic this in the filter by picking the larger of the
3312 // sides and using that one on one side of the line (right)
3313 SvxBoxItem
aCurrentBox(sw::util::ItemGet
<SvxBoxItem
>(*(pBox
->GetFrameFormat()), RES_BOX
));
3316 SwTableBox
* pBox2
= (*m_pTabBoxes
)[i
-1];
3317 SvxBoxItem
aOldBox(sw::util::ItemGet
<SvxBoxItem
>(*(pBox2
->GetFrameFormat()), RES_BOX
));
3318 if( aOldBox
.CalcLineWidth(SvxBoxItemLine::RIGHT
) > aCurrentBox
.CalcLineWidth(SvxBoxItemLine::LEFT
) )
3319 aCurrentBox
.SetLine(aOldBox
.GetLine(SvxBoxItemLine::RIGHT
), SvxBoxItemLine::LEFT
);
3321 aOldBox
.SetLine(nullptr, SvxBoxItemLine::RIGHT
);
3322 pBox2
->GetFrameFormat()->SetFormatAttr(aOldBox
);
3325 pBox
->GetFrameFormat()->SetFormatAttr(aCurrentBox
);
3327 SetTabVertAlign(pBox
, j
);
3328 SetTabDirection(pBox
, j
);
3329 if( m_pActBand
->pSHDs
|| m_pActBand
->pNewSHDs
)
3330 SetTabShades(pBox
, j
);
3334 pBox
->GetFrameFormat()->SetFormatAttr( aFS
);
3336 // skip non existing cells
3337 while( ( j
< m_pActBand
->nWwCols
) && !m_pActBand
->bExist
[j
] )
3339 m_pActBand
->nWidth
[j
] = m_pActBand
->nCenter
[j
+1] - m_pActBand
->nCenter
[j
];
3345 void WW8TabDesc::TableCellEnd()
3347 ::SetProgressState(m_pIo
->m_nProgress
, m_pIo
->m_pDocShell
); // Update
3349 EndMiserableHackForUnsupportedDirection(m_nAktCol
);
3352 if( m_pIo
->m_bWasTabRowEnd
)
3354 // bWasTabRowEnd will be deactivated in
3355 // SwWW8ImplReader::ProcessSpecial()
3357 sal_uInt16 iCol
= GetLogicalWWCol();
3358 if (iCol
< m_aNumRuleNames
.size())
3360 m_aNumRuleNames
.erase(m_aNumRuleNames
.begin() + iCol
,
3361 m_aNumRuleNames
.end());
3367 OSL_ENSURE( m_pActBand
, "pActBand ist 0" );
3370 if( m_nAktRow
>= m_nRows
) // nothing to at end of table
3373 bool bNewBand
= m_nAktBandRow
>= m_pActBand
->nRows
;
3375 { // new band needed ?
3376 m_pActBand
= m_pActBand
->pNextBand
;
3378 OSL_ENSURE( m_pActBand
, "pActBand ist 0" );
3383 SwTableBox
* pBox
= (*m_pTabBoxes
)[0];
3385 m_pIo
->m_rDoc
.InsertRow( SwTable::SelLineFromBox( pBox
, aBoxes
) );
3390 { // new column ( cell )
3393 SetPamInCell(m_nAktCol
, true);
3395 // finish Annotated Level Numbering ?
3396 if (m_pIo
->m_bAnl
&& !m_pIo
->m_bAktAND_fNumberAcross
&& m_pActBand
)
3397 m_pIo
->StopAllAnl(IsValidCell(m_nAktCol
));
3400 // if necessary register the box for the merge group for this column
3401 void WW8TabDesc::UpdateTableMergeGroup( WW8_TCell
& rCell
,
3402 WW8SelBoxInfo
* pActGroup
,
3403 SwTableBox
* pActBox
,
3406 // check if the box has to be merged
3407 // If cell is the first one to be merged, a new merge group has to be provided.
3408 // E.g., it could be that a cell is the first one to be merged, but no
3409 // new merge group is provided, because the potential other cell to be merged
3410 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3411 if ( m_pActBand
->bExist
[ nCol
] &&
3412 ( ( rCell
.bFirstMerged
&& pActGroup
) ||
3415 rCell
.bVertRestart
) )
3417 // detect appropriate merge group
3418 WW8SelBoxInfo
* pTheMergeGroup
= nullptr;
3421 pTheMergeGroup
= pActGroup
;
3425 pTheMergeGroup
= FindMergeGroup(
3426 m_pActBand
->nCenter
[ nCol
], m_pActBand
->nWidth
[ nCol
], true );
3428 if( pTheMergeGroup
)
3430 // add current box to merge group
3431 pTheMergeGroup
->push_back(pActBox
);
3436 sal_uInt16
WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3438 sal_uInt16 nCol
= 0;
3439 if( m_pActBand
&& m_pActBand
->pTCs
)
3441 for( sal_uInt16 iCol
= 1; iCol
<= m_nAktCol
&& iCol
<= m_pActBand
->nWwCols
; ++iCol
)
3443 if( !m_pActBand
->pTCs
[ iCol
-1 ].bMerged
)
3450 // find name of numrule valid for current WW-COL
3451 OUString
WW8TabDesc::GetNumRuleName() const
3453 sal_uInt16 nCol
= GetLogicalWWCol();
3454 if (nCol
< m_aNumRuleNames
.size())
3455 return m_aNumRuleNames
[nCol
];
3459 void WW8TabDesc::SetNumRuleName( const OUString
& rName
)
3461 sal_uInt16 nCol
= GetLogicalWWCol();
3462 for (sal_uInt16 nSize
= static_cast< sal_uInt16
>(m_aNumRuleNames
.size()); nSize
<= nCol
; ++nSize
)
3463 m_aNumRuleNames
.push_back(OUString());
3464 m_aNumRuleNames
[nCol
] = rName
;
3467 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp
)
3469 // Entering a table so make sure the FirstPara flag gets set
3470 m_bFirstPara
= true;
3471 // keine rekursiven Tabellen Nicht bei EinfuegenDatei in Tabelle oder
3477 m_aTableStack
.push(m_pTableDesc
);
3479 // #i33818# - determine absolute position object attributes,
3480 // if possible. It's needed for nested tables.
3481 WW8FlyPara
* pTableWFlyPara( nullptr );
3482 WW8SwFlyPara
* pTableSFlyPara( nullptr );
3483 // #i45301# - anchor nested table inside Writer fly frame
3484 // only at-character, if absolute position object attributes are available.
3485 // Thus, default anchor type is as-character anchored.
3486 RndStdIds
eAnchor( FLY_AS_CHAR
);
3489 WW8_TablePos
* pNestedTabPos( nullptr );
3490 WW8_TablePos aNestedTabPos
;
3491 WW8PLCFxSave1 aSave
;
3492 m_pPlcxMan
->GetPap()->Save( aSave
);
3493 WW8PLCFx_Cp_FKP
* pPap
= m_pPlcxMan
->GetPapPLCF();
3494 WW8_CP nMyStartCp
= nStartCp
;
3495 if ( SearchRowEnd( pPap
, nMyStartCp
, m_nInTable
) &&
3496 ParseTabPos( &aNestedTabPos
, pPap
) )
3498 pNestedTabPos
= &aNestedTabPos
;
3500 m_pPlcxMan
->GetPap()->Restore( aSave
);
3501 if ( pNestedTabPos
)
3503 ApoTestResults aApo
= TestApo( m_nInTable
+ 1, false, pNestedTabPos
);
3504 pTableWFlyPara
= ConstructApo( aApo
, pNestedTabPos
);
3505 if ( pTableWFlyPara
)
3507 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3508 // containing WW8 page top margin.
3509 pTableSFlyPara
= new WW8SwFlyPara(*m_pPaM
, *this, *pTableWFlyPara
,
3510 m_aSectionManager
.GetWWPageTopMargin(),
3511 m_aSectionManager
.GetPageLeft(), m_aSectionManager
.GetTextAreaWidth(),
3512 m_nIniFlyDx
, m_nIniFlyDy
);
3514 // #i45301# - anchor nested table Writer fly frame at-character
3515 eAnchor
= FLY_AT_CHAR
;
3519 // if first paragraph in table has break-before-page, transfer that setting to the table itself.
3520 else if( StyleExists(m_nAktColl
) )
3522 const SwFormat
* pStyleFormat
= m_vColl
[m_nAktColl
].m_pFormat
;
3523 if( pStyleFormat
&& pStyleFormat
->GetBreak().GetBreak() == SvxBreak::PageBefore
)
3524 NewAttr( pStyleFormat
->GetBreak() );
3527 m_pTableDesc
= new WW8TabDesc( this, nStartCp
);
3529 if( m_pTableDesc
->Ok() )
3531 int nNewInTable
= m_nInTable
+ 1;
3533 if ((eAnchor
== FLY_AT_CHAR
)
3534 && !m_aTableStack
.empty() && !InEqualApo(nNewInTable
) )
3536 m_pTableDesc
->m_pParentPos
= new SwPosition(*m_pPaM
->GetPoint());
3537 SfxItemSet
aItemSet(m_rDoc
.GetAttrPool(),
3538 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1);
3539 // #i33818# - anchor the Writer fly frame for the nested table at-character.
3541 SwFormatAnchor
aAnchor( eAnchor
);
3542 aAnchor
.SetAnchor( m_pTableDesc
->m_pParentPos
);
3543 aItemSet
.Put( aAnchor
);
3544 m_pTableDesc
->m_pFlyFormat
= m_rDoc
.MakeFlySection( eAnchor
,
3545 m_pTableDesc
->m_pParentPos
, &aItemSet
);
3546 OSL_ENSURE( m_pTableDesc
->m_pFlyFormat
->GetAnchor().GetAnchorId() == eAnchor
,
3547 "Not the anchor type requested!" );
3548 MoveInsideFly(m_pTableDesc
->m_pFlyFormat
);
3550 m_pTableDesc
->CreateSwTable();
3551 if (m_pTableDesc
->m_pFlyFormat
)
3553 m_pTableDesc
->SetSizePosition(m_pTableDesc
->m_pFlyFormat
);
3554 // #i33818# - Use absolute position object attributes,
3555 // if existing, and apply them to the created Writer fly frame.
3556 if ( pTableWFlyPara
&& pTableSFlyPara
)
3558 WW8FlySet
aFlySet( *this, pTableWFlyPara
, pTableSFlyPara
, false );
3559 SwFormatAnchor
aAnchor( FLY_AT_CHAR
);
3560 aAnchor
.SetAnchor( m_pTableDesc
->m_pParentPos
);
3561 aFlySet
.Put( aAnchor
);
3562 m_pTableDesc
->m_pFlyFormat
->SetFormatAttr( aFlySet
);
3566 SwFormatHoriOrient aHori
=
3567 m_pTableDesc
->m_pTable
->GetFrameFormat()->GetHoriOrient();
3568 m_pTableDesc
->m_pFlyFormat
->SetFormatAttr(aHori
);
3569 m_pTableDesc
->m_pFlyFormat
->SetFormatAttr( SwFormatSurround( SURROUND_NONE
) );
3571 // #i33818# - The nested table doesn't have to leave
3572 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3573 m_pTableDesc
->m_pFlyFormat
->SetFormatAttr( SwFormatFollowTextFlow( true ) );
3576 m_pTableDesc
->SetSizePosition(nullptr);
3577 m_pTableDesc
->UseSwTable();
3583 delete pTableWFlyPara
;
3584 delete pTableSFlyPara
;
3586 return nullptr != m_pTableDesc
;
3589 void SwWW8ImplReader::TabCellEnd()
3591 if (m_nInTable
&& m_pTableDesc
)
3592 m_pTableDesc
->TableCellEnd();
3594 m_bFirstPara
= true; // We have come to the end of a cell so FirstPara flag
3595 m_bReadTable
= false;
3596 m_pTableEndPaM
.reset();
3599 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
3601 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3602 m_bWasTabCellEnd
= true;
3605 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16
, const sal_uInt8
* pData
, short nLen
) // Sprm25
3607 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3608 m_bWasTabRowEnd
= true;
3611 void SwWW8ImplReader::PopTableDesc()
3613 if (m_pTableDesc
&& m_pTableDesc
->m_pFlyFormat
)
3615 MoveOutsideFly(m_pTableDesc
->m_pFlyFormat
,*m_pTableDesc
->m_pParentPos
);
3618 delete m_pTableDesc
;
3619 if (m_aTableStack
.empty())
3620 m_pTableDesc
= nullptr;
3623 m_pTableDesc
= m_aTableStack
.top();
3624 m_aTableStack
.pop();
3628 void SwWW8ImplReader::StopTable()
3630 OSL_ENSURE(m_pTableDesc
, "Panic, stop table with no table!");
3634 // We are leaving a table so make sure the next paragraph doesn't think
3635 // it's the first paragraph
3636 m_bFirstPara
= false;
3638 m_pTableDesc
->FinishSwTable();
3641 m_bReadTable
= true;
3642 // #i101116# - Keep PaM on table end only for nested tables
3643 if ( m_nInTable
> 1 )
3645 m_pTableEndPaM
.reset(new SwPaM(*m_pPaM
, m_pPaM
));
3649 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3654 const WW8_TCell
* pCell
= m_pTableDesc
->GetAktWWCell();
3656 return !m_pTableDesc
->IsValidCell( m_pTableDesc
->GetAktCol() )
3658 && ( !pCell
->bFirstMerged
3660 || ( pCell
->bVertMerge
3661 && !pCell
->bVertRestart
3668 sal_uInt16
SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex
) const
3670 sal_uInt16 nRes
= USHRT_MAX
;
3671 if( !m_vColl
.empty() )
3673 for(sal_uInt16 nI
= 0; nI
< m_pStyles
->GetCount(); nI
++ )
3674 if( m_vColl
[ nI
].m_bValid
3675 && (nLFOIndex
== m_vColl
[ nI
].m_nLFOIndex
) )
3681 const SwFormat
* SwWW8ImplReader::GetStyleWithOrgWWName( OUString
& rName
) const
3683 SwFormat
* pRet
= nullptr;
3684 if( !m_vColl
.empty() )
3686 for(sal_uInt16 nI
= 0; nI
< m_pStyles
->GetCount(); nI
++ )
3687 if( m_vColl
[ nI
].m_bValid
3688 && (rName
.equals( m_vColl
[ nI
].GetOrgWWName())) )
3690 pRet
= m_vColl
[ nI
].m_pFormat
;
3699 const sal_uInt8
* WW8RStyle::HasParaSprm( sal_uInt16 nId
) const
3701 if( !pParaSprms
|| !nSprmsLen
)
3704 return maSprmParser
.findSprmData(nId
, pParaSprms
, nSprmsLen
);
3707 void WW8RStyle::ImportSprms(sal_uInt8
*pSprms
, short nLen
, bool bPap
)
3714 pParaSprms
= pSprms
; // for HasParaSprms()
3718 WW8SprmIter
aSprmIter(pSprms
, nLen
, maSprmParser
);
3719 while (const sal_uInt8
* pSprm
= aSprmIter
.GetSprms())
3721 #ifdef DEBUGSPRMREADER
3722 fprintf(stderr
, "id is %x\n", aIter
.GetAktId());
3724 pIo
->ImportSprm(pSprm
, aSprmIter
.GetRemLen(), aSprmIter
.GetAktId());
3725 aSprmIter
.advance();
3728 pParaSprms
= nullptr;
3732 void WW8RStyle::ImportSprms(std::size_t nPosFc
, short nLen
, bool bPap
)
3737 if (checkSeek(*pStStrm
, nPosFc
))
3739 std::unique_ptr
<sal_uInt8
[]> pSprms( new sal_uInt8
[nLen
] );
3740 nLen
= pStStrm
->ReadBytes(pSprms
.get(), nLen
);
3741 ImportSprms(pSprms
.get(), nLen
, bPap
);
3745 static inline short WW8SkipOdd(SvStream
* pSt
)
3747 if ( pSt
->Tell() & 0x1 )
3750 return pSt
->ReadBytes( &c
, 1 );
3755 static inline short WW8SkipEven(SvStream
* pSt
)
3757 if (!(pSt
->Tell() & 0x1))
3760 return pSt
->ReadBytes( &c
, 1 );
3765 short WW8RStyle::ImportUPX(short nLen
, bool bPAP
, bool bOdd
)
3767 if( 0 < nLen
) // Empty ?
3770 nLen
= nLen
- WW8SkipEven( pStStrm
);
3772 nLen
= nLen
- WW8SkipOdd( pStStrm
);
3775 pStStrm
->ReadInt16( cbUPX
);
3780 cbUPX
= nLen
; // shrink cbUPX to nLen
3782 if( (1 < cbUPX
) || ( (0 < cbUPX
) && !bPAP
) )
3787 pStStrm
->ReadUInt16( id
);
3795 sal_uInt64
const nPos
= pStStrm
->Tell(); // if something is interpreted wrong,
3796 // this should make it work again
3797 ImportSprms( nPos
, cbUPX
, bPAP
);
3799 if ( pStStrm
->Tell() != nPos
+ cbUPX
)
3800 pStStrm
->Seek( nPos
+cbUPX
);
3802 nLen
= nLen
- cbUPX
;
3809 void WW8RStyle::ImportGrupx(short nLen
, bool bPara
, bool bOdd
)
3814 nLen
= nLen
- WW8SkipEven( pStStrm
);
3816 nLen
= nLen
- WW8SkipOdd( pStStrm
);
3818 if( bPara
) // Grupx.Papx
3819 nLen
= ImportUPX(nLen
, true, bOdd
);
3820 ImportUPX(nLen
, false, bOdd
); // Grupx.Chpx
3823 WW8RStyle::WW8RStyle(WW8Fib
& _rFib
, SwWW8ImplReader
* pI
)
3824 : WW8Style(*pI
->m_pTableStream
, _rFib
)
3825 , maSprmParser(_rFib
)
3827 , pStStrm(pI
->m_pTableStream
)
3829 , pParaSprms(nullptr)
3832 , bTextColChanged(false)
3833 , bFontChanged(false)
3834 , bCJKFontChanged(false)
3835 , bCTLFontChanged(false)
3836 , bFSizeChanged(false)
3837 , bFCTLSizeChanged(false)
3838 , bWidowsChanged(false)
3840 pIo
->m_vColl
.resize(cstd
);
3843 void WW8RStyle::Set1StyleDefaults()
3845 // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3846 if (!bCJKFontChanged
) // Style no CJK Font? set the default
3847 pIo
->SetNewFontAttr(ftcFE
, true, RES_CHRATR_CJK_FONT
);
3849 if (!bCTLFontChanged
) // Style no CTL Font? set the default
3850 pIo
->SetNewFontAttr(ftcBi
, true, RES_CHRATR_CTL_FONT
);
3852 // western 2nd to make western charset conversion the default
3853 if (!bFontChanged
) // Style has no Font? set the default,
3854 pIo
->SetNewFontAttr(ftcAsci
, true, RES_CHRATR_FONT
);
3856 if( !pIo
->m_bNoAttrImport
)
3858 // Style has no text color set, winword default is auto
3859 if ( !bTextColChanged
)
3860 pIo
->m_pAktColl
->SetFormatAttr(SvxColorItem(Color(COL_AUTO
), RES_CHRATR_COLOR
));
3862 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3863 if( !bFSizeChanged
)
3865 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3866 pIo
->m_pAktColl
->SetFormatAttr(aAttr
);
3867 aAttr
.SetWhich(RES_CHRATR_CJK_FONTSIZE
);
3868 pIo
->m_pAktColl
->SetFormatAttr(aAttr
);
3871 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3872 if( !bFCTLSizeChanged
)
3874 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3875 aAttr
.SetWhich(RES_CHRATR_CTL_FONTSIZE
);
3876 pIo
->m_pAktColl
->SetFormatAttr(aAttr
);
3879 if( !bWidowsChanged
) // Widows ?
3881 pIo
->m_pAktColl
->SetFormatAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS
) );
3882 pIo
->m_pAktColl
->SetFormatAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS
) );
3887 bool WW8RStyle::PrepareStyle(SwWW8StyInf
&rSI
, ww::sti eSti
, sal_uInt16 nThisStyle
, sal_uInt16 nNextStyle
)
3895 sw::util::ParaStyleMapper::StyleResult aResult
=
3896 pIo
->m_aParaStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
);
3897 pColl
= aResult
.first
;
3898 bStyExist
= aResult
.second
;
3903 sw::util::CharStyleMapper::StyleResult aResult
=
3904 pIo
->m_aCharStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
);
3905 pColl
= aResult
.first
;
3906 bStyExist
= aResult
.second
;
3909 bool bImport
= !bStyExist
|| pIo
->m_bNewDoc
; // import content ?
3911 // Do not override character styles the list import code created earlier.
3912 if (bImport
&& bStyExist
&& rSI
.GetOrgWWName().startsWith("WW8Num"))
3915 bool bOldNoImp
= pIo
->m_bNoAttrImport
;
3916 rSI
.m_bImportSkipped
= !bImport
;
3919 pIo
->m_bNoAttrImport
= true;
3924 pColl
->ResetAllFormatAttr(); // #i73790# - method renamed
3926 pColl
->SetAuto(false); // suggested by JP
3927 } // but changes the UI
3928 pIo
->m_pAktColl
= pColl
;
3929 rSI
.m_pFormat
= pColl
; // remember translation WW->SW
3930 rSI
.m_bImportSkipped
= !bImport
;
3932 // Set Based on style
3933 sal_uInt16 j
= rSI
.m_nBase
;
3934 if (j
!= nThisStyle
&& j
< cstd
)
3936 SwWW8StyInf
* pj
= &pIo
->m_vColl
[j
];
3937 if (rSI
.m_pFormat
&& pj
->m_pFormat
&& rSI
.m_bColl
== pj
->m_bColl
)
3939 rSI
.m_pFormat
->SetDerivedFrom( pj
->m_pFormat
); // ok, set Based on
3940 rSI
.m_eLTRFontSrcCharSet
= pj
->m_eLTRFontSrcCharSet
;
3941 rSI
.m_eRTLFontSrcCharSet
= pj
->m_eRTLFontSrcCharSet
;
3942 rSI
.m_eCJKFontSrcCharSet
= pj
->m_eCJKFontSrcCharSet
;
3943 rSI
.m_n81Flags
= pj
->m_n81Flags
;
3944 rSI
.m_n81BiDiFlags
= pj
->m_n81BiDiFlags
;
3945 if (!rSI
.IsWW8BuiltInHeadingStyle())
3947 rSI
.mnWW8OutlineLevel
= pj
->mnWW8OutlineLevel
;
3949 rSI
.m_bParaAutoBefore
= pj
->m_bParaAutoBefore
;
3950 rSI
.m_bParaAutoAfter
= pj
->m_bParaAutoAfter
;
3953 rSI
.m_xWWFly
.reset(new WW8FlyPara(pIo
->m_bVer67
, pj
->m_xWWFly
.get()));
3956 else if( pIo
->m_bNewDoc
&& bStyExist
)
3957 rSI
.m_pFormat
->SetDerivedFrom();
3959 rSI
.m_nFollow
= nNextStyle
; // remember Follow
3961 pStyRule
= nullptr; // recreate if necessary
3962 bTextColChanged
= bFontChanged
= bCJKFontChanged
= bCTLFontChanged
=
3963 bFSizeChanged
= bFCTLSizeChanged
= bWidowsChanged
= false;
3964 pIo
->SetNAktColl( nThisStyle
);
3965 pIo
->m_bStyNormal
= nThisStyle
== 0;
3969 void WW8RStyle::PostStyle(SwWW8StyInf
&rSI
, bool bOldNoImp
)
3971 // Reset attribute flags, because there are no style-ends.
3973 pIo
->m_bHasBorder
= pIo
->m_bSpec
= pIo
->m_bObj
= pIo
->m_bSymbol
= false;
3974 pIo
->m_nCharFormat
= -1;
3976 // If Style basiert auf Nichts oder Basis ignoriert
3977 if ((rSI
.m_nBase
>= cstd
|| pIo
->m_vColl
[rSI
.m_nBase
].m_bImportSkipped
) && rSI
.m_bColl
)
3979 // If Char-Styles does not work
3980 // -> set hard WW-Defaults
3981 Set1StyleDefaults();
3984 pStyRule
= nullptr; // to be on the safe side
3985 pIo
->m_bStyNormal
= false;
3986 pIo
->SetNAktColl( 0 );
3987 pIo
->m_bNoAttrImport
= bOldNoImp
;
3988 // reset the list-remember-fields, if used when reading styles
3989 pIo
->m_nLFOPosition
= USHRT_MAX
;
3990 pIo
->m_nListLevel
= WW8ListManager::nMaxLevel
;
3993 void WW8RStyle::Import1Style( sal_uInt16 nNr
)
3995 if (nNr
>= pIo
->m_vColl
.size())
3998 SwWW8StyInf
&rSI
= pIo
->m_vColl
[nNr
];
4000 if( rSI
.m_bImported
|| !rSI
.m_bValid
)
4003 rSI
.m_bImported
= true; // set flag now to avoid endless loops
4005 // valid and not NUL and not yet imported
4007 if( rSI
.m_nBase
< cstd
&& !pIo
->m_vColl
[rSI
.m_nBase
].m_bImported
)
4008 Import1Style( rSI
.m_nBase
);
4010 pStStrm
->Seek( rSI
.m_nFilePos
);
4015 std::unique_ptr
<WW8_STD
> xStd(Read1Style(nSkip
, &sName
, &cbStd
));// read Style
4018 rSI
.SetOrgWWIdent( sName
, xStd
->sti
);
4020 // either no Name or unused Slot or unknown Style
4022 if ( !xStd
|| sName
.isEmpty() || ((1 != xStd
->sgc
) && (2 != xStd
->sgc
)) )
4024 pStStrm
->SeekRel( nSkip
);
4028 bool bOldNoImp
= PrepareStyle(rSI
, static_cast<ww::sti
>(xStd
->sti
), nNr
, xStd
->istdNext
);
4030 // if something is interpreted wrong, this should make it work again
4031 long nPos
= pStStrm
->Tell();
4033 //Variable parts of the STD start at even byte offsets, but "inside
4034 //the STD", which I take to meaning even in relation to the starting
4035 //position of the STD, which matches findings in #89439#, generally it
4036 //doesn't matter as the STSHI starts off nearly always on an even
4039 //Import of the Style Contents
4040 ImportGrupx(nSkip
, xStd
->sgc
== 1, rSI
.m_nFilePos
& 1);
4042 PostStyle(rSI
, bOldNoImp
);
4044 pStStrm
->Seek( nPos
+nSkip
);
4047 void WW8RStyle::RecursiveReg(sal_uInt16 nNr
)
4049 if (nNr
>= pIo
->m_vColl
.size())
4052 SwWW8StyInf
&rSI
= pIo
->m_vColl
[nNr
];
4053 if( rSI
.m_bImported
|| !rSI
.m_bValid
)
4056 rSI
.m_bImported
= true;
4058 if( rSI
.m_nBase
< cstd
&& !pIo
->m_vColl
[rSI
.m_nBase
].m_bImported
)
4059 RecursiveReg(rSI
.m_nBase
);
4061 pIo
->RegisterNumFormatOnStyle(nNr
);
4066 After all styles are imported then we can recursively apply numbering
4067 styles to them, and change their tab stop settings if they turned out
4068 to have special first line indentation.
4070 void WW8RStyle::PostProcessStyles()
4074 Clear all imported flags so that we can recursively apply numbering
4075 formats and use it to mark handled ones
4077 for (i
=0; i
< cstd
; ++i
)
4078 pIo
->m_vColl
[i
].m_bImported
= false;
4081 Register the num formats and tabstop changes on the styles recursively.
4085 In the same loop apply the tabstop changes required because we need to
4086 change their location if theres a special indentation for the first line,
4087 By avoiding making use of each styles margins during reading of their
4088 tabstops we don't get problems with doubly adjusting tabstops that
4091 for (i
=0; i
< cstd
; ++i
)
4093 if (pIo
->m_vColl
[i
].m_bValid
)
4100 void WW8RStyle::ScanStyles() // investigate style dependencies
4101 { // and detect Filepos for each Style
4102 for (sal_uInt16 i
= 0; i
< cstd
; ++i
)
4105 SwWW8StyInf
&rSI
= pIo
->m_vColl
[i
];
4107 rSI
.m_nFilePos
= pStStrm
->Tell(); // remember FilePos
4108 WW8_STD
* pStd
= Read1Style( nSkip
, nullptr, nullptr ); // read STD
4109 rSI
.m_bValid
= (nullptr != pStd
);
4112 rSI
.m_nBase
= pStd
->istdBase
; // remember Basis
4113 rSI
.m_bColl
= ( pStd
->sgc
== 1 ); // Para-Style
4116 rSI
= SwWW8StyInf();
4119 pStStrm
->SeekRel( nSkip
); // skip Names and Sprms
4123 std::vector
<sal_uInt8
> ChpxToSprms(const Word2CHPX
&rChpx
)
4125 std::vector
<sal_uInt8
> aRet
;
4128 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fBold
) );
4131 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fItalic
) );
4134 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fStrike
) );
4137 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fOutline
) );
4140 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fSmallCaps
) );
4143 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fCaps
) );
4146 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fVanish
) );
4152 ShortToSVBT16(rChpx
.ftc
, a
);
4153 aRet
.push_back(a
[1]);
4154 aRet
.push_back(a
[0]);
4160 aRet
.push_back(rChpx
.kul
);
4167 ShortToSVBT16(rChpx
.lid
, a
);
4168 aRet
.push_back(a
[1]);
4169 aRet
.push_back(a
[0]);
4175 aRet
.push_back(rChpx
.ico
);
4183 ShortToSVBT16(rChpx
.hps
, a
);
4184 aRet
.push_back(a
[0]);
4190 aRet
.push_back(rChpx
.hpsPos
);
4194 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fBoldBi
) );
4197 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fItalicBi
) );
4203 ShortToSVBT16(rChpx
.fsFtcBi
, a
);
4204 aRet
.push_back(a
[1]);
4205 aRet
.push_back(a
[0]);
4212 ShortToSVBT16(rChpx
.lidBi
, a
);
4213 aRet
.push_back(a
[1]);
4214 aRet
.push_back(a
[0]);
4220 aRet
.push_back(rChpx
.icoBi
);
4227 ShortToSVBT16(rChpx
.hpsBi
, a
);
4228 aRet
.push_back(a
[1]);
4229 aRet
.push_back(a
[0]);
4235 Word2CHPX
ReadWord2Chpx(SvStream
&rSt
, std::size_t nOffset
, sal_uInt8 nSize
)
4249 rSt
.ReadUChar( nFlags8
);
4252 aChpx
.fBold
= nFlags8
& 0x01;
4253 aChpx
.fItalic
= (nFlags8
& 0x02) >> 1;
4254 aChpx
.fRMarkDel
= (nFlags8
& 0x04) >> 2;
4255 aChpx
.fOutline
= (nFlags8
& 0x08) >> 3;
4256 aChpx
.fFieldVanish
= (nFlags8
& 0x10) >> 4;
4257 aChpx
.fSmallCaps
= (nFlags8
& 0x20) >> 5;
4258 aChpx
.fCaps
= (nFlags8
& 0x40) >> 6;
4259 aChpx
.fVanish
= (nFlags8
& 0x80) >> 7;
4261 if (nCount
>= nSize
) break;
4262 rSt
.ReadUChar( nFlags8
);
4265 aChpx
.fRMark
= nFlags8
& 0x01;
4266 aChpx
.fSpec
= (nFlags8
& 0x02) >> 1;
4267 aChpx
.fStrike
= (nFlags8
& 0x04) >> 2;
4268 aChpx
.fObj
= (nFlags8
& 0x08) >> 3;
4269 aChpx
.fBoldBi
= (nFlags8
& 0x10) >> 4;
4270 aChpx
.fItalicBi
= (nFlags8
& 0x20) >> 5;
4271 aChpx
.fBiDi
= (nFlags8
& 0x40) >> 6;
4272 aChpx
.fDiacUSico
= (nFlags8
& 0x80) >> 7;
4274 if (nCount
>= nSize
) break;
4275 rSt
.ReadUChar( nFlags8
);
4278 aChpx
.fsIco
= nFlags8
& 0x01;
4279 aChpx
.fsFtc
= (nFlags8
& 0x02) >> 1;
4280 aChpx
.fsHps
= (nFlags8
& 0x04) >> 2;
4281 aChpx
.fsKul
= (nFlags8
& 0x08) >> 3;
4282 aChpx
.fsPos
= (nFlags8
& 0x10) >> 4;
4283 aChpx
.fsSpace
= (nFlags8
& 0x20) >> 5;
4284 aChpx
.fsLid
= (nFlags8
& 0x40) >> 6;
4285 aChpx
.fsIcoBi
= (nFlags8
& 0x80) >> 7;
4287 if (nCount
>= nSize
) break;
4288 rSt
.ReadUChar( nFlags8
);
4291 aChpx
.fsFtcBi
= nFlags8
& 0x01;
4292 aChpx
.fsHpsBi
= (nFlags8
& 0x02) >> 1;
4293 aChpx
.fsLidBi
= (nFlags8
& 0x04) >> 2;
4295 if (nCount
>= nSize
) break;
4296 rSt
.ReadUInt16( aChpx
.ftc
);
4299 if (nCount
>= nSize
) break;
4300 rSt
.ReadUInt16( aChpx
.hps
);
4303 if (nCount
>= nSize
) break;
4304 rSt
.ReadUChar( nFlags8
);
4307 aChpx
.qpsSpace
= nFlags8
& 0x3F;
4308 aChpx
.fSysVanish
= (nFlags8
& 0x40) >> 6;
4309 aChpx
.fNumRun
= (nFlags8
& 0x80) >> 7;
4311 if (nCount
>= nSize
) break;
4312 rSt
.ReadUChar( nFlags8
);
4315 aChpx
.ico
= nFlags8
& 0x1F;
4316 aChpx
.kul
= (nFlags8
& 0xE0) >> 5;
4318 if (nCount
>= nSize
) break;
4319 rSt
.ReadUChar( aChpx
.hpsPos
);
4322 if (nCount
>= nSize
) break;
4323 rSt
.ReadUChar( aChpx
.icoBi
);
4326 if (nCount
>= nSize
) break;
4327 rSt
.ReadUInt16( aChpx
.lid
);
4330 if (nCount
>= nSize
) break;
4331 rSt
.ReadUInt16( aChpx
.ftcBi
);
4334 if (nCount
>= nSize
) break;
4335 rSt
.ReadUInt16( aChpx
.hpsBi
);
4338 if (nCount
>= nSize
) break;
4339 rSt
.ReadUInt16( aChpx
.lidBi
);
4342 if (nCount
>= nSize
) break;
4343 rSt
.ReadUInt32( aChpx
.fcPic
);
4349 rSt
.SeekRel(nSize
-nCount
);
4355 struct pxoffset
{ std::size_t mnOffset
; sal_uInt8 mnSize
; };
4358 void WW8RStyle::ImportOldFormatStyles()
4360 for (sal_uInt16 i
=0; i
< cstd
; ++i
)
4362 pIo
->m_vColl
[i
].m_bColl
= true;
4363 //every chain must end eventually at the null style (style code 222)
4364 pIo
->m_vColl
[i
].m_nBase
= 222;
4367 rtl_TextEncoding eStructChrSet
= WW8Fib::GetFIBCharset(
4368 pIo
->m_pWwFib
->m_chseTables
, pIo
->m_pWwFib
->m_lid
);
4370 sal_uInt16
cstcStd(0);
4371 rSt
.ReadUInt16( cstcStd
);
4373 size_t nMaxByteCount
= rSt
.remainingSize();
4374 sal_uInt16
cbName(0);
4375 rSt
.ReadUInt16(cbName
);
4376 if (cbName
> nMaxByteCount
)
4378 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4379 << cbName
<< " to " << nMaxByteCount
);
4380 cbName
= nMaxByteCount
;
4382 sal_uInt16 nByteCount
= 2;
4384 while (nByteCount
< cbName
)
4386 sal_uInt8
nCount(0);
4387 rSt
.ReadUChar( nCount
);
4390 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4391 if (stc
>=pIo
->m_vColl
.size())
4394 SwWW8StyInf
&rSI
= pIo
->m_vColl
[stc
];
4397 if (nCount
!= 0xFF) // undefined style
4399 if (nCount
!= 0) // user style
4401 OString aTmp
= read_uInt8s_ToOString(rSt
, nCount
);
4402 nByteCount
+= aTmp
.getLength();
4403 sName
= OStringToOUString(aTmp
, eStructChrSet
);
4405 rSI
.m_bImported
= true;
4408 if (sName
.isEmpty())
4410 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4411 if (const sal_Char
*pStr
= GetEnglishNameFromSti(eSti
))
4412 sName
= OUString(pStr
, strlen(pStr
), RTL_TEXTENCODING_ASCII_US
);
4415 if (sName
.isEmpty())
4416 sName
= "Unknown Style: " + OUString::number(stc
);
4418 rSI
.SetOrgWWIdent(sName
, stc
);
4422 sal_uInt16 nStyles
=stcp
;
4424 std::vector
<pxoffset
> aCHPXOffsets(stcp
);
4425 nMaxByteCount
= rSt
.remainingSize();
4426 sal_uInt16
cbChpx(0);
4427 rSt
.ReadUInt16(cbChpx
);
4428 if (cbChpx
> nMaxByteCount
)
4430 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4431 << cbChpx
<< " to " << nMaxByteCount
);
4432 cbChpx
= nMaxByteCount
;
4436 std::vector
< std::vector
<sal_uInt8
> > aConvertedChpx
;
4437 while (nByteCount
< cbChpx
)
4439 if (stcp
== aCHPXOffsets
.size())
4441 //more data than style slots, skip remainder
4442 rSt
.SeekRel(cbChpx
-nByteCount
);
4447 rSt
.ReadUChar( cb
);
4450 aCHPXOffsets
[stcp
].mnSize
= 0;
4454 sal_uInt8 nRemainder
= cb
;
4456 aCHPXOffsets
[stcp
].mnOffset
= rSt
.Tell();
4457 aCHPXOffsets
[stcp
].mnSize
= nRemainder
;
4459 Word2CHPX aChpx
= ReadWord2Chpx(rSt
, aCHPXOffsets
[stcp
].mnOffset
,
4460 aCHPXOffsets
[stcp
].mnSize
);
4461 aConvertedChpx
.push_back( ChpxToSprms(aChpx
) );
4463 nByteCount
+= nRemainder
;
4466 aConvertedChpx
.push_back( std::vector
<sal_uInt8
>() );
4471 std::vector
<pxoffset
> aPAPXOffsets(stcp
);
4472 nMaxByteCount
= rSt
.remainingSize();
4473 sal_uInt16
cbPapx(0);
4474 rSt
.ReadUInt16(cbPapx
);
4475 if (cbPapx
> nMaxByteCount
)
4477 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4478 << cbPapx
<< " to " << nMaxByteCount
);
4479 cbPapx
= nMaxByteCount
;
4483 while (nByteCount
< cbPapx
)
4485 if (stcp
== aPAPXOffsets
.size())
4487 rSt
.SeekRel(cbPapx
-nByteCount
);
4492 rSt
.ReadUChar( cb
);
4495 aPAPXOffsets
[stcp
].mnSize
= 0;
4500 rSt
.ReadUChar( stc2
);
4503 sal_uInt8 nRemainder
= cb
-7;
4505 aPAPXOffsets
[stcp
].mnOffset
= rSt
.Tell();
4506 aPAPXOffsets
[stcp
].mnSize
= nRemainder
;
4508 rSt
.SeekRel(nRemainder
);
4509 nByteCount
+= nRemainder
;
4516 rSt
.ReadUInt16( iMac
);
4518 if (iMac
> nStyles
) iMac
= nStyles
;
4520 for (stcp
= 0; stcp
< iMac
; ++stcp
)
4522 sal_uInt8
stcNext(0), stcBase(0);
4523 rSt
.ReadUChar( stcNext
);
4524 rSt
.ReadUChar( stcBase
);
4526 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4529 #i64557# style based on itself
4530 every chain must end eventually at the null style (style code 222)
4535 SwWW8StyInf
&rSI
= pIo
->m_vColl
[stc
];
4536 rSI
.m_nBase
= stcBase
;
4538 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4540 if (eSti
== ww::stiNil
)
4543 if (stcp
>= aPAPXOffsets
.size())
4546 rSI
.m_bValid
= true;
4548 if (ww::StandardStiIsCharStyle(eSti
) && !aPAPXOffsets
[stcp
].mnSize
)
4549 pIo
->m_vColl
[stc
].m_bColl
= false;
4551 bool bOldNoImp
= PrepareStyle(rSI
, eSti
, stc
, stcNext
);
4553 ImportSprms(aPAPXOffsets
[stcp
].mnOffset
, aPAPXOffsets
[stcp
].mnSize
,
4556 if (aConvertedChpx
[stcp
].size() > 0)
4557 ImportSprms(&(aConvertedChpx
[stcp
][0]),
4558 static_cast< short >(aConvertedChpx
[stcp
].size()),
4561 PostStyle(rSI
, bOldNoImp
);
4565 void WW8RStyle::ImportNewFormatStyles()
4567 ScanStyles(); // Scan Based On
4569 for (sal_uInt16 i
= 0; i
< cstd
; ++i
) // import Styles
4570 if (pIo
->m_vColl
[i
].m_bValid
)
4574 void WW8RStyle::Import()
4576 pIo
->m_pDfltTextFormatColl
= pIo
->m_rDoc
.GetDfltTextFormatColl();
4577 pIo
->m_pStandardFormatColl
=
4578 pIo
->m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
, false);
4580 if( pIo
->m_nIniFlags
& WW8FL_NO_STYLES
)
4583 if (pIo
->m_pWwFib
->GetFIBVersion() <= ww::eWW2
)
4584 ImportOldFormatStyles();
4586 ImportNewFormatStyles();
4588 for (sal_uInt16 i
= 0; i
< cstd
; ++i
)
4591 SwWW8StyInf
* pi
= &pIo
->m_vColl
[i
];
4592 sal_uInt16 j
= pi
->m_nFollow
;
4595 SwWW8StyInf
* pj
= &pIo
->m_vColl
[j
];
4596 if ( j
!= i
// rational Index ?
4597 && pi
->m_pFormat
// Format ok ?
4598 && pj
->m_pFormat
// Derived-Format ok ?
4599 && pi
->m_bColl
// only possible for paragraph templates (WW)
4600 && pj
->m_bColl
){ // identical Typ ?
4601 static_cast<SwTextFormatColl
*>(pi
->m_pFormat
)->SetNextTextFormatColl(
4602 *static_cast<SwTextFormatColl
*>(pj
->m_pFormat
) ); // ok, register
4607 // Missing special handling for default character template
4608 // "Absatz-Standardschriftart" ( Style-ID 65 ).
4609 // That is empty by default ( WW6 dt and US ) and not changeable
4610 // via WW-UI so this does not matter.
4611 // This could be done by:
4612 // if( bNew ) rDoc.SetDefault( pDefCharFormat->GetAttrSet() );
4614 // for e.g. tables an always valid Std-Style is necessary
4616 if( pIo
->StyleExists(0) && !pIo
->m_vColl
.empty() &&
4617 pIo
->m_vColl
[0].m_pFormat
&& pIo
->m_vColl
[0].m_bColl
&& pIo
->m_vColl
[0].m_bValid
)
4618 pIo
->m_pDfltTextFormatColl
= static_cast<SwTextFormatColl
*>(pIo
->m_vColl
[0].m_pFormat
);
4620 pIo
->m_pDfltTextFormatColl
= pIo
->m_rDoc
.GetDfltTextFormatColl();
4622 // set Hyphenation flag on BASIC para-style
4623 if (pIo
->m_bNewDoc
&& pIo
->m_pStandardFormatColl
)
4625 if (pIo
->m_pWDop
->fAutoHyphen
4626 && SfxItemState::SET
!= pIo
->m_pStandardFormatColl
->GetItemState(
4627 RES_PARATR_HYPHENZONE
, false) )
4629 SvxHyphenZoneItem
aAttr(true, RES_PARATR_HYPHENZONE
);
4630 aAttr
.GetMinLead() = 2;
4631 aAttr
.GetMinTrail() = 2;
4632 aAttr
.GetMaxHyphens() = 0;
4634 pIo
->m_pStandardFormatColl
->SetFormatAttr( aAttr
);
4638 Word defaults to ltr not from environment like writer. Regardless of
4639 the page/sections rtl setting the standard style lack of rtl still
4642 if (SfxItemState::SET
!= pIo
->m_pStandardFormatColl
->GetItemState(RES_FRAMEDIR
,
4645 pIo
->m_pStandardFormatColl
->SetFormatAttr(
4646 SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP
, RES_FRAMEDIR
));
4650 // we do not read styles anymore:
4651 pIo
->m_pAktColl
= nullptr;
4654 rtl_TextEncoding
SwWW8StyInf::GetCharSet() const
4656 if ((m_pFormat
) && (m_pFormat
->GetFrameDir().GetValue() == FRMDIR_HORI_RIGHT_TOP
))
4657 return m_eRTLFontSrcCharSet
;
4658 return m_eLTRFontSrcCharSet
;
4661 rtl_TextEncoding
SwWW8StyInf::GetCJKCharSet() const
4663 if ((m_pFormat
) && (m_pFormat
->GetFrameDir().GetValue() == FRMDIR_HORI_RIGHT_TOP
))
4664 return m_eRTLFontSrcCharSet
;
4665 return m_eCJKFontSrcCharSet
;
4668 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */