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>
21 #include <sal/log.hxx>
23 #include <comphelper/string.hxx>
24 #include <osl/diagnose.h>
25 #include <o3tl/safeint.hxx>
26 #include <o3tl/temporary.hxx>
27 #include <tools/solar.h>
28 #include <vcl/font.hxx>
29 #include <hintids.hxx>
30 #include <editeng/colritem.hxx>
31 #include <editeng/orphitem.hxx>
32 #include <editeng/widwitem.hxx>
33 #include <editeng/brushitem.hxx>
34 #include <editeng/boxitem.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/fhgtitem.hxx>
37 #include <editeng/hyphenzoneitem.hxx>
38 #include <editeng/frmdiritem.hxx>
39 #include <editeng/pgrditem.hxx>
40 #include <msfilter.hxx>
42 #include <deletelistener.hxx>
44 #include <IDocumentStylePoolAccess.hxx>
48 #include <poolfmt.hxx>
49 #include <swtable.hxx>
56 #include <fmtlsplt.hxx>
57 #include <charfmt.hxx>
58 #include <fmtanchr.hxx>
59 #include <fmtrowsplt.hxx>
60 #include <fmtfollowtextflow.hxx>
61 #include <numrule.hxx>
62 #include "sprmids.hxx"
63 #include <wwstyles.hxx>
64 #include "ww8struc.hxx"
66 #include "ww8par2.hxx"
69 #include <itabenum.hxx>
70 #include <unocrsr.hxx>
75 using namespace ::com::sun::star
;
77 WW8TabBandDesc::WW8TabBandDesc():
78 pNextBand(nullptr), nGapHalf(0), mnDefaultLeft(0), mnDefaultTop(0), mnDefaultRight(0),
79 mnDefaultBottom(0), mbHasSpacing(false), nLineHeight(0), nRows(0), nCenter
{}, nWidth
{},
80 nWwCols(0), nSwCols(0), bLEmptyCol(false), bREmptyCol(false), bCantSplit(false),
81 bCantSplit90(false), pTCs(nullptr), nOverrideSpacing
{}, nOverrideValues
{}, pSHDs(nullptr),
82 pNewSHDs(nullptr), bExist
{}, nTransCell
{}
84 for (sal_uInt16
& rn
: maDirections
)
88 WW8TabBandDesc::~WW8TabBandDesc()
95 void sw::util::RedlineStack::close( const SwPosition
& rPos
,
96 RedlineType eType
, WW8TabDesc
* pTabDesc
)
98 // If the redline type is not found in the redline stack, we have to check if there has been
99 // a tabledesc and to check its saved redline stack, too. (#136939, #i68139)
100 if( !close( rPos
, eType
) )
102 if( pTabDesc
&& pTabDesc
->getOldRedlineStack() )
105 pTabDesc
->getOldRedlineStack()->close(rPos
, eType
);
106 OSL_ENSURE( bResult
, "close without open!");
111 void wwSectionManager::SetCurrentSectionHasFootnote()
113 OSL_ENSURE(!maSegments
.empty(),
114 "should not be possible, must be at least one segment");
115 if (!maSegments
.empty())
116 maSegments
.back().mbHasFootnote
= true;
119 void wwSectionManager::SetCurrentSectionVerticalAdjustment(const drawing::TextVerticalAdjust nVA
)
121 OSL_ENSURE(!maSegments
.empty(),
122 "should not be possible, must be at least one segment");
123 if ( !maSegments
.empty() )
124 maSegments
.back().mnVerticalAdjustment
= nVA
;
127 bool wwSectionManager::CurrentSectionIsVertical() const
129 OSL_ENSURE(!maSegments
.empty(),
130 "should not be possible, must be at least one segment");
131 if (!maSegments
.empty())
132 return maSegments
.back().IsVertical();
136 bool wwSectionManager::CurrentSectionIsProtected() const
138 OSL_ENSURE(!maSegments
.empty(),
139 "should not be possible, must be at least one segment");
140 if (!maSegments
.empty())
141 return SectionIsProtected(maSegments
.back());
145 sal_uInt32
wwSectionManager::GetPageLeft() const
147 return !maSegments
.empty() ? maSegments
.back().m_nPgLeft
: 0;
150 sal_uInt32
wwSectionManager::GetPageRight() const
152 return !maSegments
.empty() ? maSegments
.back().m_nPgRight
: 0;
155 sal_uInt32
wwSectionManager::GetPageWidth() const
157 return !maSegments
.empty() ? maSegments
.back().GetPageWidth() : 0;
160 sal_uInt32
wwSectionManager::GetTextAreaWidth() const
162 return !maSegments
.empty() ? maSegments
.back().GetTextAreaWidth() : 0;
165 sal_uInt32
wwSectionManager::GetWWPageTopMargin() const
167 return !maSegments
.empty() ? maSegments
.back().maSep
.dyaTop
: 0;
170 sal_uInt16
SwWW8ImplReader::End_Footnote()
173 Ignoring Footnote outside of the normal Text. People will put footnotes
174 into field results and field commands.
177 m_pPaM
->GetPoint()->GetNode() < m_rDoc
.GetNodes().GetEndOfExtras())
182 OSL_ENSURE(!m_aFootnoteStack
.empty(), "footnote end without start");
183 if (m_aFootnoteStack
.empty())
186 bool bFtEdOk
= false;
187 const FootnoteDescriptor
&rDesc
= m_aFootnoteStack
.back();
189 //Get the footnote character and remove it from the txtnode. We'll
190 //replace it with the footnote
191 SwTextNode
* pText
= m_pPaM
->GetPointNode().GetTextNode();
192 sal_Int32 nPos
= m_pPaM
->GetPoint()->GetContentIndex();
195 SwTextFootnote
* pFN
= nullptr;
196 //There should have been a footnote char, we will replace this.
199 sChar
+= OUStringChar(pText
->GetText()[--nPos
]);
201 m_pPaM
->GetMark()->AdjustContent(-1);
202 std::shared_ptr
<SwUnoCursor
> xLastAnchorCursor(m_oLastAnchorPos
? m_rDoc
.CreateUnoCursor(*m_oLastAnchorPos
) : nullptr);
203 m_oLastAnchorPos
.reset();
204 m_rDoc
.getIDocumentContentOperations().DeleteRange( *m_pPaM
);
205 m_pPaM
->DeleteMark();
206 if (xLastAnchorCursor
)
207 m_oLastAnchorPos
.emplace(*xLastAnchorCursor
->GetPoint());
208 SwFormatFootnote
aFootnote(rDesc
.meType
== MAN_EDN
);
209 pFN
= static_cast<SwTextFootnote
*>(pText
->InsertItem(aFootnote
, nPos
, nPos
));
211 OSL_ENSURE(pFN
, "Problems creating the footnote text");
214 SwPosition
aTmpPos( *m_pPaM
->GetPoint() ); // remember old cursor position
215 WW8PLCFxSaveAll aSave
;
216 m_xPlcxMan
->SaveAllPLCFx( aSave
);
217 std::shared_ptr
<WW8PLCFMan
> xOldPlcxMan
= m_xPlcxMan
;
219 const SwNodeIndex
* pSttIdx
= pFN
->GetStartNode();
220 assert(pSttIdx
&& "Problems creating footnote text");
222 pFN
->SetSeqNo(m_rDoc
.GetFootnoteIdxs().size());
224 bool bOld
= m_bFootnoteEdn
;
225 m_bFootnoteEdn
= true;
227 SwFormatFootnote
& rFormatFootnote
= static_cast<SwFormatFootnote
&>(pFN
->GetAttr());
229 SvtDeleteListener
aDeleteListener(rFormatFootnote
.GetNotifier());
231 // read content of Ft-/End-Note
232 Read_HdFtFootnoteText( pSttIdx
, rDesc
.mnStartCp
, rDesc
.mnLen
, rDesc
.meType
);
234 m_bFootnoteEdn
= bOld
;
236 SAL_WARN_IF(aDeleteListener
.WasDeleted(), "sw.ww8", "Footnode deleted during its import");
237 if (!aDeleteListener
.WasDeleted())
241 OSL_ENSURE(sChar
.getLength()==1 && ((rDesc
.mbAutoNum
== (sChar
[0] == 2))),
242 "footnote autonumbering must be 0x02, and everything else must not be");
244 // If no automatic numbering use the following char from the main text
245 // as the footnote number
246 if (!rDesc
.mbAutoNum
)
247 pFN
->SetNumber(0, 0, sChar
);
250 Delete the footnote char from the footnote if it's at the beginning
251 as usual. Might not be if the user has already deleted it, e.g.
254 SwPosition
& rPaMPointPos
= *m_pPaM
->GetPoint();
255 rPaMPointPos
.Assign(pSttIdx
->GetIndex() + 1);
256 SwTextNode
* pTNd
= rPaMPointPos
.GetNode().GetTextNode();
257 if (pTNd
&& !pTNd
->GetText().isEmpty() && !sChar
.isEmpty())
259 const OUString
&rText
= pTNd
->GetText();
260 if (rText
[0] == sChar
[0])
262 // Allow MSO to emulate LO footnote text starting at left margin - only meaningful with hanging indent
263 sal_Int32 nFirstLineIndent
=0;
264 SfxItemSetFixed
<RES_MARGIN_FIRSTLINE
, RES_MARGIN_FIRSTLINE
> aSet(m_rDoc
.GetAttrPool());
265 if ( pTNd
->GetAttr(aSet
) )
267 const SvxFirstLineIndentItem
*const pFirstLine(aSet
.GetItem
<SvxFirstLineIndentItem
>(RES_MARGIN_FIRSTLINE
));
270 nFirstLineIndent
= pFirstLine
->GetTextFirstLineOffset();
274 rPaMPointPos
.SetContent(0);
276 // Strip out aesthetic tabs we may have inserted on export #i24762#
277 if (nFirstLineIndent
< 0 && rText
.getLength() > 1 && rText
[1] == 0x09)
278 m_pPaM
->GetMark()->AdjustContent(1);
279 m_pPaM
->GetMark()->AdjustContent(1);
280 m_xReffingStck
->Delete(*m_pPaM
);
281 m_rDoc
.getIDocumentContentOperations().DeleteRange( *m_pPaM
);
282 m_pPaM
->DeleteMark();
287 *m_pPaM
->GetPoint() = aTmpPos
; // restore Cursor
289 m_xPlcxMan
= xOldPlcxMan
; // Restore attributes
290 m_xPlcxMan
->RestoreAllPLCFx( aSave
);
294 m_aSectionManager
.SetCurrentSectionHasFootnote();
296 m_aFootnoteStack
.pop_back();
300 tools::Long
SwWW8ImplReader::Read_Footnote(WW8PLCFManResult
* pRes
)
303 Ignoring Footnote outside of the normal Text. People will put footnotes
304 into field results and field commands.
307 m_pPaM
->GetPoint()->GetNode() < m_rDoc
.GetNodes().GetEndOfExtras())
312 FootnoteDescriptor aDesc
;
313 aDesc
.mbAutoNum
= true;
314 if (eEDN
== pRes
->nSprmId
)
316 aDesc
.meType
= MAN_EDN
;
317 WW8PLCFx_SubDoc
* pEndNote
= m_xPlcxMan
->GetEdn();
318 if (const void* pData
= pEndNote
? pEndNote
->GetData() : nullptr)
319 aDesc
.mbAutoNum
= 0 != *static_cast<short const*>(pData
);
323 aDesc
.meType
= MAN_FTN
;
324 WW8PLCFx_SubDoc
* pFootNote
= m_xPlcxMan
->GetFootnote();
325 if (const void* pData
= pFootNote
? pFootNote
->GetData() : nullptr)
326 aDesc
.mbAutoNum
= 0 != *static_cast<short const*>(pData
);
329 aDesc
.mnStartCp
= pRes
->nCp2OrIdx
;
330 aDesc
.mnLen
= pRes
->nMemLen
;
332 m_aFootnoteStack
.push_back(aDesc
);
337 bool SwWW8ImplReader::SearchRowEnd(WW8PLCFx_Cp_FKP
* pPap
, WW8_CP
&rStartCp
,
341 aRes
.pMemPos
= nullptr;
342 aRes
.nEndPos
= rStartCp
;
343 std::set
<std::pair
<WW8_CP
, WW8_CP
>> aPrevRes
;
345 while (pPap
->HasFkp() && rStartCp
!= WW8_CP_MAX
)
347 if (pPap
->Where() != WW8_CP_MAX
)
349 SprmResult aSprmRes
= pPap
->HasSprm(TabRowSprm(nLevel
));
350 const sal_uInt8
* pB
= aSprmRes
.pSprm
;
351 if (pB
&& aSprmRes
.nRemainingData
>= 1 && *pB
== 1)
353 aSprmRes
= pPap
->HasSprm(0x6649);
354 const sal_uInt8
*pLevel
= aSprmRes
.pSprm
;
355 if (pLevel
&& aSprmRes
.nRemainingData
>= 1)
357 if (nLevel
+ 1 == *pLevel
)
362 OSL_ENSURE(!nLevel
|| pLevel
, "sublevel without level sprm");
363 return true; // RowEnd found
368 aRes
.nStartPos
= aRes
.nEndPos
;
369 aRes
.pMemPos
= nullptr;
370 //Seek to our next block of properties
371 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
373 aRes
.nEndPos
= WW8_CP_MAX
;
374 pPap
->SetDirty(true);
376 pPap
->GetSprms(&aRes
);
377 pPap
->SetDirty(false);
378 auto aBounds(std::make_pair(aRes
.nStartPos
, aRes
.nEndPos
));
379 if (!aPrevRes
.insert(aBounds
).second
) //already seen these bounds, infinite loop
381 SAL_WARN("sw.ww8", "SearchRowEnd, loop in paragraph property chain");
384 //Update our aRes to get the new starting point of the next properties
385 rStartCp
= aRes
.nEndPos
;
391 bool SwWW8ImplReader::SearchTableEnd(WW8PLCFx_Cp_FKP
* pPap
) const
394 // The below SPRM is for WW8 only.
398 aRes
.pMemPos
= nullptr;
399 aRes
.nEndPos
= pPap
->Where();
400 std::set
<std::pair
<WW8_CP
, WW8_CP
>> aPrevRes
;
402 while (pPap
->HasFkp() && pPap
->Where() != WW8_CP_MAX
)
404 // See if the current pap is outside the table.
405 SprmResult aSprmRes
= pPap
->HasSprm(NS_sprm::PFInTable::val
);
406 const sal_uInt8
* pB
= aSprmRes
.pSprm
;
407 if (!pB
|| aSprmRes
.nRemainingData
< 1 || *pB
!= 1)
408 // Yes, this is the position after the end of the table.
411 // It is, so seek to the next pap.
412 aRes
.nStartPos
= aRes
.nEndPos
;
413 aRes
.pMemPos
= nullptr;
414 if (!pPap
->SeekPos(aRes
.nStartPos
))
417 // Read the sprms and make sure we moved forward to avoid infinite loops.
418 pPap
->GetSprms(&aRes
);
419 auto aBounds(std::make_pair(aRes
.nStartPos
, aRes
.nEndPos
));
420 if (!aPrevRes
.insert(aBounds
).second
) //already seen these bounds, infinite loop
422 SAL_WARN("sw.ww8", "SearchTableEnd, loop in paragraph property chain");
430 ApoTestResults
SwWW8ImplReader::TestApo(int nCellLevel
, bool bTableRowEnd
,
431 const WW8_TablePos
*pTabPos
)
433 const WW8_TablePos
*pTopLevelTable
= nCellLevel
<= 1 ? pTabPos
: nullptr;
435 // Frame in Style Definition (word appears to ignore them if inside an
437 sal_uInt16
const nStyle(m_xPlcxMan
->GetColl());
438 if (!m_bTxbxFlySection
&& nStyle
< m_vColl
.size())
439 aRet
.mpStyleApo
= StyleExists(nStyle
) ? m_vColl
[nStyle
].m_xWWFly
.get() : nullptr;
443 If I have a table and apply a style to one of its frames that should cause
444 a paragraph that it is applied to it to only exist as a separate floating
445 frame, then the behaviour depends on which cell that it has been applied
446 to. If it is the first cell of a row then the whole table row jumps into the
447 new frame, if it isn't then the paragraph attributes are applied
448 "except" for the floating frame stuff. i.e. it's ignored. So if there's a
449 table, and we're not in the first cell then we ignore the fact that the
450 paragraph style wants to be in a different frame.
452 This sort of mindbending inconsistency is surely why frames are deprecated
453 in word 97 onwards and hidden away from the user
456 If we are already a table in a frame then we must grab the para properties
457 to see if we are still in that frame.
460 aRet
.m_bHasSprm37
= m_xPlcxMan
->HasParaSprm(m_bVer67
? 37 : 0x2423).pSprm
!= nullptr; // sprmPWr
461 SprmResult aSrpm29
= m_xPlcxMan
->HasParaSprm(m_bVer67
? 29 : 0x261B); // sprmPPc
462 const sal_uInt8
*pSrpm29
= aSrpm29
.pSprm
;
463 aRet
.m_bHasSprm29
= pSrpm29
!= nullptr;
464 const sal_Int16 nTPc
= aRet
.mpStyleApo
? aRet
.mpStyleApo
->nTPc
: 0;
465 aRet
.m_nSprm29
= (pSrpm29
&& aSrpm29
.nRemainingData
>= 1) ? *pSrpm29
: nTPc
;
467 // Is there some frame data here
468 bool bNowApo
= aRet
.HasFrame() || pTopLevelTable
;
471 if (!ConstructApo(aRet
, pTabPos
))
475 bool bTestAllowed
= !m_bTxbxFlySection
&& !bTableRowEnd
;
478 //Test is allowed if there is no table.
479 //Otherwise only allowed if we are in the
480 //first paragraph of the first cell of a row.
481 //(And only if the row we are inside is at the
482 //same level as the previous row, think tables
484 if (nCellLevel
== m_nInTable
)
493 OSL_ENSURE(m_xTableDesc
, "What!");
494 bTestAllowed
= false;
499 // If current cell isn't valid, the test is allowed.
500 // The cell isn't valid, if e.g. there is a new row
501 // <pTableDesc->nCurrentRow> >= <pTableDesc->pTabLines->Count()>
503 m_xTableDesc
->GetCurrentCol() == 0 &&
504 ( !m_xTableDesc
->IsValidCell( m_xTableDesc
->GetCurrentCol() ) ||
505 m_xTableDesc
->InFirstParaInCell() );
514 aRet
.mbStartApo
= bNowApo
&& !InEqualOrHigherApo(1); // APO-start
515 aRet
.mbStopApo
= InEqualOrHigherApo(nCellLevel
) && !bNowApo
; // APO-end
517 //If it happens that we are in a table, then if it's not the first cell
518 //then any attributes that might otherwise cause the contents to jump
519 //into another frame don't matter, a table row sticks together as one
520 //unit no matter what else happens. So if we are not in a table at
521 //all, or if we are in the first cell then test that the last frame
522 //data is the same as the current one
523 if (bNowApo
&& InEqualApo(nCellLevel
))
525 // two bordering each other
526 if (!TestSameApo(aRet
, pTabPos
))
527 aRet
.mbStopApo
= aRet
.mbStartApo
= true;
533 // helper methods for outline, numbering and bullets
535 static void SetBaseAnlv(SwNumFormat
&rNum
, WW8_ANLV
const &rAV
, sal_uInt8 nSwLevel
)
537 static const SvxNumType eNumA
[8] = { SVX_NUM_ARABIC
, SVX_NUM_ROMAN_UPPER
, SVX_NUM_ROMAN_LOWER
,
538 SVX_NUM_CHARS_UPPER_LETTER_N
, SVX_NUM_CHARS_LOWER_LETTER_N
, SVX_NUM_ARABIC
,
539 SVX_NUM_ARABIC
, SVX_NUM_ARABIC
};
541 static const SvxAdjust eAdjA
[4] = { SvxAdjust::Left
,
542 SvxAdjust::Right
, SvxAdjust::Left
, SvxAdjust::Left
};
544 rNum
.SetNumberingType( eNumA
[ rAV
.nfc
] );
546 SvxNumType nType
= SVX_NUM_ARABIC
;
549 case 19:nType
= SVX_NUM_FULL_WIDTH_ARABIC
; break;
550 case 30:nType
= SVX_NUM_TIAN_GAN_ZH
; break;
551 case 31:nType
= SVX_NUM_DI_ZI_ZH
; break;
555 case 39:nType
= SVX_NUM_NUMBER_LOWER_ZH
; break;
556 case 34:nType
= SVX_NUM_NUMBER_UPPER_ZH_TW
; break;
557 case 38:nType
= SVX_NUM_NUMBER_UPPER_ZH
; break;
559 case 11:nType
= SVX_NUM_NUMBER_TRADITIONAL_JA
; break;
560 case 20:nType
= SVX_NUM_AIU_FULLWIDTH_JA
; break;
561 case 12:nType
= SVX_NUM_AIU_HALFWIDTH_JA
; break;
562 case 21:nType
= SVX_NUM_IROHA_FULLWIDTH_JA
; break;
563 case 13:nType
= SVX_NUM_IROHA_HALFWIDTH_JA
; break;
564 case 24:nType
= SVX_NUM_HANGUL_SYLLABLE_KO
; break;
565 case 25:nType
= SVX_NUM_HANGUL_JAMO_KO
; break;
566 case 41:nType
= SVX_NUM_NUMBER_HANGUL_KO
; break;
569 case 44:nType
= SVX_NUM_NUMBER_UPPER_KO
; break;
571 nType
= SVX_NUM_ARABIC
;break;
573 rNum
.SetNumberingType( nType
);
576 if ((rAV
.aBits1
& 0x4) >> 2)
578 rNum
.SetIncludeUpperLevels(nSwLevel
+ 1);
580 rNum
.SetStart( SVBT16ToUInt16( rAV
.iStartAt
) );
581 rNum
.SetNumAdjust( eAdjA
[ rAV
.aBits1
& 0x3] );
583 rNum
.SetCharTextDistance( SVBT16ToUInt16( rAV
.dxaSpace
) );
584 sal_Int16 nIndent
= std::abs(static_cast<sal_Int16
>(SVBT16ToUInt16( rAV
.dxaIndent
)));
585 if( rAV
.aBits1
& 0x08 ) //fHang
587 rNum
.SetFirstLineOffset( -nIndent
);
588 rNum
.SetAbsLSpace( nIndent
);
591 rNum
.SetCharTextDistance( nIndent
); // width of number is missing
593 if( rAV
.nfc
== 5 || rAV
.nfc
== 7 )
595 OUString sP
= "." + rNum
.GetSuffix();
596 rNum
.SetListFormat("", sP
, nSwLevel
); // ordinal number
599 rNum
.SetListFormat("", "", nSwLevel
);
602 void SwWW8ImplReader::SetAnlvStrings(SwNumFormat
&rNum
, int nLevel
, WW8_ANLV
const &rAV
,
603 const sal_uInt8
* pText
, size_t nStart
, size_t nElements
, bool bOutline
)
605 if (nStart
> nElements
)
611 bool bInsert
= false; // Default
612 rtl_TextEncoding eCharSet
= m_eStructCharSet
;
614 const WW8_FFN
* pF
= m_xFonts
->GetFont(SVBT16ToUInt16(rAV
.ftc
)); // FontInfo
615 bool bListSymbol
= pF
&& ( pF
->aFFNBase
.chs
== 2 ); // Symbol/WingDings/...
617 sal_uInt32 nLen
= rAV
.cbTextBefore
+ rAV
.cbTextAfter
;
618 OUStringBuffer
sText(static_cast<sal_Int32
>(nLen
));
621 if (nLen
> nElements
)
623 SAL_WARN("sw.ww8", "SetAnlvStrings: ignoring out of range "
624 << nLen
<< " vs " << nElements
<< " max");
627 sText
= OUString(reinterpret_cast<char const *>(pText
), nLen
, eCharSet
);
628 // ofz#23961 in case of multi-byte input encoding resulting in shorter
629 // output pad to full length with something semi-arbitrary
630 comphelper::string::padToLength(sText
, nLen
, cBulletChar
);
634 if (nLen
> nElements
/ 2)
636 SAL_WARN("sw.ww8", "SetAnlvStrings: ignoring out of range "
637 << nLen
<< " vs " << nElements
/ 2 << " max");
640 for(sal_uInt32 i
= 0; i
< nLen
; ++i
, pText
+= 2)
642 sText
.append(static_cast<sal_Unicode
>(SVBT16ToUInt16(*reinterpret_cast<SVBT16
const *>(pText
))));
648 if( !rNum
.GetIncludeUpperLevels() // there are <= 1 number to show
649 || rNum
.GetNumberingType() == SVX_NUM_NUMBER_NONE
) // or this level has none
651 // if self defined digits
652 bInsert
= true; // then apply character
654 // replace by simple Bullet ?
657 // use cBulletChar for correct mapping on MAC
659 comphelper::string::padToLength(sText
, rAV
.cbTextBefore
660 + rAV
.cbTextAfter
, cBulletChar
);
665 { // numbering / bullets
673 if( GetFontParams( SVBT16ToUInt16( rAV
.ftc
), eFamily
, aName
,
674 ePitch
, eCharSet
) ){
677 aFont
.SetFamilyName( aName
);
678 aFont
.SetFamily( eFamily
);
680 aFont
.SetCharSet( eCharSet
);
681 rNum
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
683 rNum
.SetBulletFont( &aFont
);
685 // take only the very first character
686 if (rAV
.cbTextBefore
|| rAV
.cbTextAfter
)
689 OUString::unacquired(sText
).iterateCodePoints(&o3tl::temporary(sal_Int32(0))));
692 rNum
.SetBulletChar( 0x2190 );
701 if (rAV
.cbTextBefore
)
703 sPrefix
= sText
.copy( 0, rAV
.cbTextBefore
).makeStringAndClear();
705 if( rAV
.cbTextAfter
)
707 sSuffix
= rNum
.GetSuffix() + sText
.subView( rAV
.cbTextBefore
, rAV
.cbTextAfter
);
710 rNum
.SetListFormat(sPrefix
, sSuffix
, nLevel
);
712 // The characters before and after multiple digits do not apply because
713 // those are handled differently by the writer and the result is in most
714 // cases worse than without.
717 // SetAnld gets a WW-ANLD-Descriptor and a Level and modifies the NumRules
718 // which are provided by pNumR. This is used for everything beside
719 // outline inside the text.
720 void SwWW8ImplReader::SetAnld(SwNumRule
* pNumR
, WW8_ANLD
const * pAD
, sal_uInt8 nSwLevel
,
724 aNF
.SetListFormat("", "", nSwLevel
);
726 { // there is an Anld-Sprm
727 m_bCurrentAND_fNumberAcross
= 0 != pAD
->fNumberAcross
;
728 WW8_ANLV
const &rAV
= pAD
->eAnlv
;
729 SetBaseAnlv(aNF
, rAV
, nSwLevel
); // set the base format
730 SetAnlvStrings(aNF
, nSwLevel
, rAV
, pAD
->rgchAnld
, 0, SAL_N_ELEMENTS(pAD
->rgchAnld
), bOutLine
); // set the rest
732 pNumR
->Set(nSwLevel
, aNF
);
735 // chapter numbering and bullets
737 // Chapter numbering happens in the style definition.
738 // Sprm 13 provides the level, Sprm 12 the content.
740 SwNumRule
* SwWW8ImplReader::GetStyRule()
742 if( m_xStyles
->mpStyRule
) // Bullet-Style already present
743 return m_xStyles
->mpStyRule
;
745 const OUString
aBaseName("WW8StyleNum");
746 const OUString
aName( m_rDoc
.GetUniqueNumRuleName( &aBaseName
, false) );
749 sal_uInt16 nRul
= m_rDoc
.MakeNumRule( aName
, nullptr, false,
750 SvxNumberFormat::LABEL_ALIGNMENT
);
751 m_xStyles
->mpStyRule
= m_rDoc
.GetNumRuleTable()[nRul
];
752 // Auto == false-> numbering style
753 m_xStyles
->mpStyRule
->SetAutoRule(false);
755 return m_xStyles
->mpStyRule
;
759 void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
761 m_nSwNumLevel
= 0xff; // Default: invalid
769 // only for SwTextFormatColl, not CharFormat
770 // WW: 0 = no Numbering
771 SwWW8StyInf
* pColl
= GetStyle(m_nCurrentColl
);
772 if (pColl
!= nullptr && pColl
->m_bColl
&& *pData
)
774 // Range WW:1..9 -> SW:0..8 no bullets / numbering
778 m_nSwNumLevel
= *pData
- 1;
779 if (!m_bNoAttrImport
)
780 static_cast<SwTextFormatColl
*>(m_pCurrentColl
)->AssignToListLevelOfOutlineStyle( m_nSwNumLevel
);
781 // For WW-NoNumbering also NO_NUMBERING could be used.
782 // ( For normal numberierung NO_NUM has to be used:
783 // NO_NUM : pauses numbering,
784 // NO_NUMBERING : no numbering at all )
787 else if( *pData
== 10 || *pData
== 11 )
789 // remember type, the rest happens at Sprm 12
790 m_xStyles
->mnWwNumLevel
= *pData
;
798 StartAnl(pData
); // begin of outline / bullets
803 void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16
, const sal_uInt8
* pData
, short nLen
) // Sprm 12
805 SwWW8StyInf
* pStyInf
= GetStyle(m_nCurrentColl
);
806 if( !m_pCurrentColl
|| nLen
<= 0 // only for Styledef
807 || (pStyInf
&& !pStyInf
->m_bColl
) // ignore CharFormat ->
808 || ( m_nIniFlags
& WW8FL_NO_OUTLINE
) )
810 m_nSwNumLevel
= 0xff;
814 if (o3tl::make_unsigned(nLen
) < sizeof(WW8_ANLD
))
816 SAL_WARN("sw.ww8", "ANLevelDesc property is " << nLen
<< " long, needs to be at least " << sizeof(WW8_ANLD
));
817 m_nSwNumLevel
= 0xff;
821 if (m_nSwNumLevel
<= 9) // Value range mapping WW:1..9 -> SW:0..8
824 // If NumRuleItems were set, either directly or through inheritance, disable them now
825 m_pCurrentColl
->SetFormatAttr( SwNumRuleItem() );
827 const OUString
aName("Outline");
828 SwNumRule
aNR( m_rDoc
.GetUniqueNumRuleName( &aName
),
829 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
831 aNR
= *m_rDoc
.GetOutlineNumRule();
833 SetAnld(&aNR
, reinterpret_cast<WW8_ANLD
const *>(pData
), m_nSwNumLevel
, true);
835 // Missing Levels need not be replenished
836 m_rDoc
.SetOutlineNumRule( aNR
);
838 else if( m_xStyles
->mnWwNumLevel
== 10 || m_xStyles
->mnWwNumLevel
== 11 ){
839 SwNumRule
* pNR
= GetStyRule();
840 SetAnld(pNR
, reinterpret_cast<WW8_ANLD
const *>(pData
), 0, false);
841 m_pCurrentColl
->SetFormatAttr( SwNumRuleItem( pNR
->GetName() ) );
843 pStyInf
= GetStyle(m_nCurrentColl
);
844 if (pStyInf
!= nullptr)
845 pStyInf
->m_bHasStyNumRule
= true;
849 // Numbering / Bullets
851 // SetNumOlst() carries the Numrules for this cell to SwNumFormat.
852 // For this the info is fetched from OLST and not from ANLD ( see later )
853 // ( only for outline inside text; Bullets / numbering use ANLDs )
854 void SwWW8ImplReader::SetNumOlst(SwNumRule
* pNumR
, WW8_OLST
* pO
, sal_uInt8 nSwLevel
)
857 WW8_ANLV
&rAV
= pO
->rganlv
[nSwLevel
];
858 SetBaseAnlv(aNF
, rAV
, nSwLevel
);
859 // ... and then the Strings
862 WW8_ANLV
* pAV1
; // search String-Positions
863 for (i
= 0, pAV1
= pO
->rganlv
; i
< nSwLevel
; ++i
, ++pAV1
)
864 nTextOfs
+= pAV1
->cbTextBefore
+ pAV1
->cbTextAfter
;
868 SetAnlvStrings(aNF
, nSwLevel
, rAV
, pO
->rgch
, nTextOfs
, SAL_N_ELEMENTS(pO
->rgch
), true); // and apply
869 pNumR
->Set(nSwLevel
, aNF
);
872 // The OLST is at the beginning of each section that contains outlines.
873 // The ANLDs that are connected to each outline-line contain only nonsense,
874 // so the OLSTs are remembered for the section to have usable information
875 // when outline-paragraphs occur.
876 void SwWW8ImplReader::Read_OLST( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
882 if (o3tl::make_unsigned(nLen
) < sizeof(WW8_OLST
))
884 SAL_WARN("sw.ww8", "WW8_OLST property is " << nLen
<< " long, needs to be at least " << sizeof(WW8_OLST
));
888 m_xNumOlst
.reset(new WW8_OLST
);
889 *m_xNumOlst
= *reinterpret_cast<WW8_OLST
const *>(pData
);
892 WW8LvlType
GetNumType(sal_uInt8 nWwLevelNo
)
894 WW8LvlType nRet
= WW8_None
;
895 if( nWwLevelNo
== 12 )
897 else if( nWwLevelNo
== 10 )
898 nRet
= WW8_Numbering
;
899 else if( nWwLevelNo
== 11 )
901 else if( nWwLevelNo
> 0 && nWwLevelNo
<= 9 )
906 SwNumRule
*ANLDRuleMap::GetNumRule(const SwDoc
& rDoc
, sal_uInt8 nNumType
)
908 const OUString
& rNumRule
= WW8_Numbering
== nNumType
? msNumberingNumRule
: msOutlineNumRule
;
909 if (rNumRule
.isEmpty())
911 return rDoc
.FindNumRulePtr(rNumRule
);
914 void ANLDRuleMap::SetNumRule(const OUString
& rNumRule
, sal_uInt8 nNumType
)
916 if (WW8_Numbering
== nNumType
)
917 msNumberingNumRule
= rNumRule
;
919 msOutlineNumRule
= rNumRule
;
922 // StartAnl is called at the beginning of a row area that contains
923 // outline / numbering / bullets
924 void SwWW8ImplReader::StartAnl(const sal_uInt8
* pSprm13
)
926 m_bCurrentAND_fNumberAcross
= false;
928 sal_uInt8 nT
= static_cast< sal_uInt8
>(GetNumType(*pSprm13
));
929 if (nT
== WW8_Pause
|| nT
== WW8_None
)
933 SwNumRule
*pNumRule
= m_aANLDRules
.GetNumRule(m_rDoc
, m_nWwNumType
);
935 // check for COL numbering:
936 SprmResult aS12
; // sprmAnld
941 sNumRule
= m_xTableDesc
->GetNumRuleName();
942 if (!sNumRule
.isEmpty())
944 pNumRule
= m_rDoc
.FindNumRulePtr(sNumRule
);
949 // this is ROW numbering ?
950 aS12
= m_xPlcxMan
->HasParaSprm(m_bVer67
? 12 : NS_sprm::LN_PAnld
); // sprmAnld
951 if (aS12
.pSprm
&& aS12
.nRemainingData
>= sal_Int32(sizeof(WW8_ANLD
)) && 0 != reinterpret_cast<WW8_ANLD
const *>(aS12
.pSprm
)->fNumberAcross
)
957 SwWW8StyInf
* pStyInf
= GetStyle(m_nCurrentColl
);
958 if (sNumRule
.isEmpty() && pStyInf
!= nullptr && pStyInf
->m_bHasStyNumRule
)
960 sNumRule
= pStyInf
->m_pFormat
->GetNumRule().GetValue();
961 pNumRule
= m_rDoc
.FindNumRulePtr(sNumRule
);
966 if (sNumRule
.isEmpty())
971 pNumRule
= m_rDoc
.GetNumRuleTable()[
972 m_rDoc
.MakeNumRule( sNumRule
, nullptr, false,
973 SvxNumberFormat::LABEL_ALIGNMENT
) ];
978 aS12
= m_xPlcxMan
->HasParaSprm(m_bVer67
? 12 : NS_sprm::LN_PAnld
); // sprmAnld
979 if (!aS12
.pSprm
|| aS12
.nRemainingData
< sal_Int32(sizeof(WW8_ANLD
)) || !reinterpret_cast<WW8_ANLD
const *>(aS12
.pSprm
)->fNumberAcross
)
980 m_xTableDesc
->SetNumRuleName(pNumRule
->GetName());
986 sNumRule
= pNumRule
? pNumRule
->GetName() : OUString();
987 // set NumRules via stack
988 m_xCtrlStck
->NewAttr(*m_pPaM
->GetPoint(),
989 SfxStringItem(RES_FLTR_NUMRULE
, sNumRule
));
991 m_aANLDRules
.SetNumRule(sNumRule
, m_nWwNumType
);
994 // NextAnlLine() is called once for every row of a
995 // outline / numbering / bullet
996 void SwWW8ImplReader::NextAnlLine(const sal_uInt8
* pSprm13
)
1001 SwNumRule
*pNumRule
= m_aANLDRules
.GetNumRule(m_rDoc
, m_nWwNumType
);
1003 // pNd->UpdateNum without a set of rules crashes at the latest whilst storing as sdw3
1005 // WW:10 = numbering -> SW:0 & WW:11 = bullets -> SW:0
1006 if (*pSprm13
== 10 || *pSprm13
== 11)
1009 if (pNumRule
&& !pNumRule
->GetNumFormat(m_nSwNumLevel
))
1013 SprmResult aS12
= m_xPlcxMan
->HasParaSprm(m_bVer67
? 12 : NS_sprm::LN_PAnld
);
1014 if (aS12
.nRemainingData
>= sal_Int32(sizeof(WW8_ANLD
)))
1015 SetAnld(pNumRule
, reinterpret_cast<WW8_ANLD
const *>(aS12
.pSprm
), m_nSwNumLevel
, false);
1018 else if( *pSprm13
> 0 && *pSprm13
<= MAXLEVEL
) // range WW:1..9 -> SW:0..8
1020 m_nSwNumLevel
= *pSprm13
- 1; // outline
1022 if (pNumRule
&& !pNumRule
->GetNumFormat(m_nSwNumLevel
))
1024 if (m_xNumOlst
) // there was a OLST
1026 //Assure upper levels are set, #i9556#
1027 for (sal_uInt8 nI
= 0; nI
< m_nSwNumLevel
; ++nI
)
1029 if (!pNumRule
->GetNumFormat(nI
))
1030 SetNumOlst(pNumRule
, m_xNumOlst
.get(), nI
);
1033 SetNumOlst(pNumRule
, m_xNumOlst
.get(), m_nSwNumLevel
);
1035 else // no Olst -> use Anld
1038 SprmResult aS12
= m_xPlcxMan
->HasParaSprm(m_bVer67
? 12 : NS_sprm::LN_PAnld
);
1039 if (aS12
.nRemainingData
>= sal_Int32(sizeof(WW8_ANLD
)))
1040 SetAnld(pNumRule
, reinterpret_cast<WW8_ANLD
const *>(aS12
.pSprm
), m_nSwNumLevel
, false);
1045 m_nSwNumLevel
= 0xff; // no number
1047 SwTextNode
* pNd
= m_pPaM
->GetPointNode().GetTextNode();
1051 if (m_nSwNumLevel
< MAXLEVEL
)
1052 pNd
->SetAttrListLevel( m_nSwNumLevel
);
1055 pNd
->SetAttrListLevel(0);
1056 pNd
->SetCountedInList( false );
1060 void SwWW8ImplReader::StopAllAnl(bool bGoBack
)
1062 //Of course we're not restarting, but we'll make use of our knowledge
1063 //of the implementation to do it.
1064 StopAnlToRestart(WW8_None
, bGoBack
);
1067 void SwWW8ImplReader::StopAnlToRestart(sal_uInt8 nNewType
, bool bGoBack
)
1071 SwPosition
aTmpPos(*m_pPaM
->GetPoint());
1072 m_pPaM
->Move(fnMoveBackward
, GoInContent
);
1073 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1074 *m_pPaM
->GetPoint() = aTmpPos
;
1077 m_xCtrlStck
->SetAttr(*m_pPaM
->GetPoint(), RES_FLTR_NUMRULE
);
1079 m_aANLDRules
.msNumberingNumRule
.clear();
1082 my take on this problem is that moving either way from an outline to a
1083 numbering doesn't halt the outline, while the numbering is always halted
1085 bool bNumberingNotStopOutline
=
1086 (((m_nWwNumType
== WW8_Outline
) && (nNewType
== WW8_Numbering
)) ||
1087 ((m_nWwNumType
== WW8_Numbering
) && (nNewType
== WW8_Outline
)));
1088 if (!bNumberingNotStopOutline
)
1089 m_aANLDRules
.msOutlineNumRule
.clear();
1091 m_nSwNumLevel
= 0xff;
1092 m_nWwNumType
= WW8_None
;
1096 WW8TabBandDesc::WW8TabBandDesc( WW8TabBandDesc
const & rBand
)
1101 pTCs
= reinterpret_cast<WW8_TCell
*>(new char[nWwCols
* sizeof (WW8_TCell
)]);
1102 // create uninitialized
1103 memcpy( pTCs
, rBand
.pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1107 pSHDs
= new WW8_SHD
[nWwCols
];
1108 memcpy( pSHDs
, rBand
.pSHDs
, nWwCols
* sizeof( WW8_SHD
) );
1110 if( rBand
.pNewSHDs
)
1112 pNewSHDs
= new Color
[nWwCols
];
1113 memcpy(pNewSHDs
, rBand
.pNewSHDs
, nWwCols
* sizeof(Color
));
1115 memcpy(aDefBrcs
, rBand
.aDefBrcs
, sizeof(aDefBrcs
));
1118 // ReadDef reads the cell position and the borders of a band
1119 void WW8TabBandDesc::ReadDef(bool bVer67
, const sal_uInt8
* pS
, short nLen
)
1121 --nLen
; //reduce len by expected nCols arg
1124 sal_uInt8 nCols
= *pS
; // number of cells
1126 if (nCols
> MAX_COL
)
1129 nLen
-= 2 * (nCols
+ 1); //reduce len by claimed amount of next x-borders arguments
1133 short nOldCols
= nWwCols
;
1136 const sal_uInt8
* pT
= &pS
[1];
1137 for (int i
= 0; i
<= nCols
; i
++, pT
+=2)
1138 nCenter
[i
] = static_cast<sal_Int16
>(SVBT16ToUInt16( pT
)); // X-borders
1140 if( nCols
!= nOldCols
) // different column count
1150 short nFileCols
= nLen
/ ( bVer67
? 10 : 20 ); // really saved
1155 pTCs
= new WW8_TCell
[nCols
];
1158 short nColsToRead
= std::min
<short>(nFileCols
, nCols
);
1160 if (nColsToRead
<= 0)
1166 Attention: Beginning with Ver8 there is an extra ushort per TC
1167 added and the size of the border code is doubled.
1168 Because of this a simple copy (pTCs[i] = *pTc;)
1171 Advantage: The work structure suits better.
1173 WW8_TCell
* pCurrentTC
= pTCs
;
1176 WW8_TCellVer6
const * pTc
= reinterpret_cast<WW8_TCellVer6
const *>(pT
);
1177 for (int i
= 0; i
< nColsToRead
; i
++, ++pCurrentTC
,++pTc
)
1180 sal_uInt8 aBits1
= pTc
->aBits1Ver6
;
1181 pCurrentTC
->bFirstMerged
= sal_uInt8( ( aBits1
& 0x01 ) != 0 );
1182 pCurrentTC
->bMerged
= sal_uInt8( ( aBits1
& 0x02 ) != 0 );
1183 pCurrentTC
->rgbrc
[ WW8_TOP
]
1184 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_TOP
] ));
1185 pCurrentTC
->rgbrc
[ WW8_LEFT
]
1186 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_LEFT
] ));
1187 pCurrentTC
->rgbrc
[ WW8_BOT
]
1188 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_BOT
] ));
1189 pCurrentTC
->rgbrc
[ WW8_RIGHT
]
1190 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_RIGHT
] ));
1191 if( ( pCurrentTC
->bMerged
)
1194 // Cell merged -> remember
1195 //bWWMergedVer6[i] = true;
1196 pTCs
[i
-1].rgbrc
[ WW8_RIGHT
]
1197 = WW8_BRCVer9(WW8_BRC( pTc
->rgbrcVer6
[ WW8_RIGHT
] ));
1198 // apply right border to previous cell
1199 // bExist must not be set to false, because WW
1200 // does not count this cells in text boxes...
1206 WW8_TCellVer8
const * pTc
= reinterpret_cast<WW8_TCellVer8
const *>(pT
);
1207 for (int k
= 0; k
< nColsToRead
; ++k
, ++pCurrentTC
, ++pTc
)
1209 sal_uInt16 aBits1
= SVBT16ToUInt16( pTc
->aBits1Ver8
);
1210 pCurrentTC
->bFirstMerged
= sal_uInt8( ( aBits1
& 0x0001 ) != 0 );
1211 pCurrentTC
->bMerged
= sal_uInt8( ( aBits1
& 0x0002 ) != 0 );
1212 pCurrentTC
->bVertical
= sal_uInt8( ( aBits1
& 0x0004 ) != 0 );
1213 pCurrentTC
->bBackward
= sal_uInt8( ( aBits1
& 0x0008 ) != 0 );
1214 pCurrentTC
->bRotateFont
= sal_uInt8( ( aBits1
& 0x0010 ) != 0 );
1215 pCurrentTC
->bVertMerge
= sal_uInt8( ( aBits1
& 0x0020 ) != 0 );
1216 pCurrentTC
->bVertRestart
= sal_uInt8( ( aBits1
& 0x0040 ) != 0 );
1217 pCurrentTC
->nVertAlign
= ( ( aBits1
& 0x0180 ) >> 7 );
1218 // note: in aBits1 there are 7 bits unused,
1219 // followed by another 16 unused bits
1221 pCurrentTC
->rgbrc
[ WW8_TOP
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_TOP
]);
1222 pCurrentTC
->rgbrc
[ WW8_LEFT
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_LEFT
]);
1223 pCurrentTC
->rgbrc
[ WW8_BOT
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_BOT
]);
1224 pCurrentTC
->rgbrc
[ WW8_RIGHT
] = WW8_BRCVer9(pTc
->rgbrcVer8
[ WW8_RIGHT
]);
1228 // #i25071 In '97 text direction appears to be only set using TC properties
1229 // not with sprmTTextFlow so we need to cycle through the maDirections and
1230 // double check any non-default directions
1231 for (int k
= 0; k
< nCols
; ++k
)
1233 if(maDirections
[k
] == 4)
1235 if(pTCs
[k
].bVertical
)
1237 if(pTCs
[k
].bBackward
)
1238 maDirections
[k
] = 3;
1240 maDirections
[k
] = 1;
1246 void WW8TabBandDesc::ProcessSprmTSetBRC(int nBrcVer
, const sal_uInt8
* pParamsTSetBRC
, sal_uInt16 nParamsLen
)
1248 if( !pParamsTSetBRC
|| !pTCs
) // set one or more cell border(s)
1253 SAL_WARN("sw.ww8", "table border property is too short");
1257 sal_uInt8 nitcFirst
= pParamsTSetBRC
[0];// first col to be changed
1258 sal_uInt8 nitcLim
= pParamsTSetBRC
[1];// (last col to be changed)+1
1259 sal_uInt8 nFlag
= *(pParamsTSetBRC
+2);
1261 if (nitcFirst
>= nWwCols
)
1264 if (nitcLim
> nWwCols
)
1267 bool bChangeRight
= (nFlag
& 0x08) != 0;
1268 bool bChangeBottom
= (nFlag
& 0x04) != 0;
1269 bool bChangeLeft
= (nFlag
& 0x02) != 0;
1270 bool bChangeTop
= (nFlag
& 0x01) != 0;
1272 WW8_TCell
* pCurrentTC
= pTCs
+ nitcFirst
;
1273 WW8_BRCVer9 brcVer9
;
1276 if (nParamsLen
< sizeof(WW8_BRCVer6
) + 3)
1278 SAL_WARN("sw.ww8", "table border property is too short");
1281 brcVer9
= WW8_BRCVer9(WW8_BRC(*reinterpret_cast<WW8_BRCVer6
const *>(pParamsTSetBRC
+3)));
1283 else if( nBrcVer
== 8 )
1285 static_assert(sizeof (WW8_BRC
) == 4, "this has to match the msword size");
1286 if (nParamsLen
< sizeof(WW8_BRC
) + 3)
1288 SAL_WARN("sw.ww8", "table border property is too short");
1291 brcVer9
= WW8_BRCVer9(*reinterpret_cast<WW8_BRC
const *>(pParamsTSetBRC
+3));
1295 if (nParamsLen
< sizeof(WW8_BRCVer9
) + 3)
1297 SAL_WARN("sw.ww8", "table border property is too short");
1300 brcVer9
= *reinterpret_cast<WW8_BRCVer9
const *>(pParamsTSetBRC
+3);
1303 for( int i
= nitcFirst
; i
< nitcLim
; ++i
, ++pCurrentTC
)
1306 pCurrentTC
->rgbrc
[ WW8_TOP
] = brcVer9
;
1308 pCurrentTC
->rgbrc
[ WW8_LEFT
] = brcVer9
;
1310 pCurrentTC
->rgbrc
[ WW8_BOT
] = brcVer9
;
1312 pCurrentTC
->rgbrc
[ WW8_RIGHT
] = brcVer9
;
1316 void WW8TabBandDesc::ProcessSprmTTableBorders(int nBrcVer
, const sal_uInt8
* pParams
, sal_uInt16 nParamsLen
)
1318 // sprmTTableBorders
1321 if (nParamsLen
< sizeof(WW8_BRCVer6
) * 6)
1323 SAL_WARN("sw.ww8", "table border property is too short");
1326 WW8_BRCVer6
const *pVer6
= reinterpret_cast<WW8_BRCVer6
const *>(pParams
);
1327 for (int i
= 0; i
< 6; ++i
)
1328 aDefBrcs
[i
] = WW8_BRCVer9(WW8_BRC(pVer6
[i
]));
1330 else if ( nBrcVer
== 8 )
1332 static_assert(sizeof (WW8_BRC
) == 4, "this has to match the msword size");
1333 if (nParamsLen
< sizeof(WW8_BRC
) * 6)
1335 SAL_WARN("sw.ww8", "table border property is too short");
1338 for( int i
= 0; i
< 6; ++i
)
1339 aDefBrcs
[i
] = WW8_BRCVer9(reinterpret_cast<WW8_BRC
const *>(pParams
)[i
]);
1343 if (nParamsLen
< sizeof( aDefBrcs
))
1345 SAL_WARN("sw.ww8", "table border property is too short");
1348 memcpy( aDefBrcs
, pParams
, sizeof( aDefBrcs
) );
1352 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8
* pParamsTDxaCol
)
1354 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1355 // whose index is within a certain range to be a certain value.
1357 if( !(nWwCols
&& pParamsTDxaCol
) ) // set one or more cell length(s)
1360 sal_uInt8 nitcFirst
= pParamsTDxaCol
[0]; // first col to be changed
1361 sal_uInt8 nitcLim
= pParamsTDxaCol
[1]; // (last col to be changed)+1
1362 short nDxaCol
= static_cast<sal_Int16
>(SVBT16ToUInt16( pParamsTDxaCol
+ 2 ));
1364 for( int i
= nitcFirst
; (i
< nitcLim
) && (i
< nWwCols
); i
++ )
1366 const short nOrgWidth
= nCenter
[i
+1] - nCenter
[i
];
1367 const short nDelta
= nDxaCol
- nOrgWidth
;
1368 for( int j
= i
+1; j
<= nWwCols
; j
++ )
1370 nCenter
[j
] = nCenter
[j
] + nDelta
;
1375 void WW8TabBandDesc::ProcessSprmTInsert(const sal_uInt8
* pParamsTInsert
)
1377 if( !nWwCols
|| !pParamsTInsert
) // set one or more cell length(s)
1380 sal_uInt8 nitcInsert
= pParamsTInsert
[0]; // position at which to insert
1381 if (nitcInsert
>= MAX_COL
) // cannot insert into cell outside max possible index
1383 sal_uInt8 nctc
= pParamsTInsert
[1]; // number of cells
1384 sal_uInt16 ndxaCol
= SVBT16ToUInt16( pParamsTInsert
+2 );
1387 if (nitcInsert
> nWwCols
)
1389 nNewWwCols
= nitcInsert
+nctc
;
1390 //if new count would be outside max possible count, clip it, and calc a new replacement
1392 if (nNewWwCols
> MAX_COL
)
1394 nNewWwCols
= MAX_COL
;
1395 nctc
= ::sal::static_int_cast
<sal_uInt8
>(nNewWwCols
-nitcInsert
);
1400 nNewWwCols
= nWwCols
+nctc
;
1401 //if new count would be outside max possible count, clip it, and calc a new replacement
1403 if (nNewWwCols
> MAX_COL
)
1405 nNewWwCols
= MAX_COL
;
1406 nctc
= ::sal::static_int_cast
<sal_uInt8
>(nNewWwCols
-nWwCols
);
1410 WW8_TCell
*pTC2s
= new WW8_TCell
[nNewWwCols
];
1414 memcpy( pTC2s
, pTCs
, nWwCols
* sizeof( WW8_TCell
) );
1419 //If we have to move some cells
1420 if (nitcInsert
<= nWwCols
)
1422 // adjust the left x-position of the dummy at the very end
1423 nCenter
[nWwCols
+ nctc
] = nCenter
[nWwCols
]+nctc
*ndxaCol
;
1424 for( int i
= nWwCols
-1; i
>= nitcInsert
; i
--)
1426 // adjust the left x-position
1427 nCenter
[i
+ nctc
] = nCenter
[i
]+nctc
*ndxaCol
;
1429 // adjust the cell's borders
1430 pTCs
[i
+ nctc
] = pTCs
[i
];
1434 //if itcMac is larger than full size, fill in missing ones first
1435 for( int i
= nWwCols
; i
> nitcInsert
+nWwCols
; i
--)
1436 nCenter
[i
] = i
? (nCenter
[i
- 1]+ndxaCol
) : 0;
1438 //now add in our new cells
1439 for( int j
= 0;j
< nctc
; j
++)
1440 nCenter
[j
+ nitcInsert
] = (j
+ nitcInsert
) ? (nCenter
[j
+ nitcInsert
-1]+ndxaCol
) : 0;
1442 nWwCols
= nNewWwCols
;
1446 void WW8TabBandDesc::ProcessDirection(const sal_uInt8
* pParams
)
1448 sal_uInt8 nStartCell
= *pParams
++;
1449 sal_uInt8 nEndCell
= *pParams
++;
1450 sal_uInt16 nCode
= SVBT16ToUInt16(pParams
);
1452 OSL_ENSURE(nStartCell
< nEndCell
, "not as I thought");
1453 OSL_ENSURE(nEndCell
< MAX_COL
+ 1, "not as I thought");
1454 if (nStartCell
> MAX_COL
)
1456 if (nEndCell
> MAX_COL
+ 1)
1457 nEndCell
= MAX_COL
+ 1;
1459 for (;nStartCell
< nEndCell
; ++nStartCell
)
1460 maDirections
[nStartCell
] = nCode
;
1463 void WW8TabBandDesc::ProcessSpacing(const sal_uInt8
* pParams
)
1465 sal_uInt8 nLen
= pParams
? *(pParams
- 1) : 0;
1466 OSL_ENSURE(nLen
== 6, "Unexpected spacing len");
1470 #if OSL_DEBUG_LEVEL > 0
1471 sal_uInt8 nWhichCell
= *pParams
;
1472 OSL_ENSURE(nWhichCell
== 0, "Expected cell to be 0!");
1474 ++pParams
; //Skip which cell
1475 ++pParams
; //unknown byte
1477 sal_uInt8 nSideBits
= *pParams
++;
1478 OSL_ENSURE(nSideBits
< 0x10, "Unexpected value for nSideBits");
1479 ++pParams
; //unknown byte
1480 sal_uInt16 nValue
= SVBT16ToUInt16( pParams
);
1481 for (int i
= wwTOP
; i
<= wwRIGHT
; i
++)
1483 switch (nSideBits
& (1 << i
))
1486 mnDefaultTop
= nValue
;
1489 mnDefaultLeft
= nValue
;
1492 mnDefaultBottom
= nValue
;
1495 mnDefaultRight
= nValue
;
1500 OSL_ENSURE(false, "Impossible");
1506 void WW8TabBandDesc::ProcessSpecificSpacing(const sal_uInt8
* pParams
)
1508 sal_uInt8 nLen
= pParams
? *(pParams
- 1) : 0;
1509 OSL_ENSURE(nLen
== 6, "Unexpected spacing len");
1513 const sal_uInt8 nStartCell
= *pParams
++; // The first cell these margins could apply to.
1514 const sal_uInt8 nEndCell
= *pParams
++; // The cell that does NOT apply these margins.
1515 OSL_ENSURE(nStartCell
< MAX_COL
+ 1, "Cell out of range in spacings");
1516 if ( nStartCell
>= nEndCell
|| nEndCell
> MAX_COL
+1 )
1519 sal_uInt8 nSideBits
= *pParams
++;
1520 OSL_ENSURE(nSideBits
< 0x10, "Unexpected value for nSideBits");
1522 const sal_uInt8 nSizeType
= *pParams
++; // Fts: FtsDxa(0x3) is the only type that mentions cellMargin
1523 OSL_ENSURE(nSizeType
== 0x3, "Unexpected non-twip value for margin width");
1524 if ( nSizeType
!= 0x3 ) // i.e FtsNil: The size is wrong (or unconverted) and MUST be ignored
1527 sal_uInt16 nValue
= SVBT16ToUInt16( pParams
);
1529 for (int nCell
= nStartCell
; nCell
< nEndCell
; ++nCell
)
1531 nOverrideSpacing
[ nCell
] |= nSideBits
;
1532 OSL_ENSURE(nOverrideSpacing
[ nCell
] < 0x10, "Unexpected value for nSideBits");
1534 for (int i
=0; i
< 4; i
++)
1536 if (nSideBits
& (1 << i
))
1537 nOverrideValues
[ nCell
][ i
] = nValue
;
1542 void WW8TabBandDesc::ProcessSprmTDelete(const sal_uInt8
* pParamsTDelete
)
1544 if( !(nWwCols
&& pParamsTDelete
) ) // set one or more cell length(s)
1547 sal_uInt8 nitcFirst
= pParamsTDelete
[0]; // first col to be deleted
1548 if (nitcFirst
>= nWwCols
) // first index to delete from doesn't exist
1550 sal_uInt8 nitcLim
= pParamsTDelete
[1]; // (last col to be deleted)+1
1551 if (nitcLim
<= nitcFirst
) // second index to delete to is not greater than first index
1555 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1556 * greater than or equal to itcLim to be moved
1558 int nShlCnt
= nWwCols
- nitcLim
; // count of cells to be shifted
1560 if (nShlCnt
>= 0) //There exist entries whose index is greater than or equal to itcLim
1562 WW8_TCell
* pCurrentTC
= pTCs
+ nitcFirst
;
1564 while( i
< nShlCnt
)
1566 // adjust the left x-position
1567 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1569 // adjust the cell's borders
1570 *pCurrentTC
= pTCs
[ nitcLim
+ i
];
1575 // adjust the left x-position of the dummy at the very end
1576 nCenter
[nitcFirst
+ i
] = nCenter
[nitcLim
+ i
];
1579 short nCellsDeleted
= nitcLim
- nitcFirst
;
1580 //clip delete request to available number of cells
1581 if (nCellsDeleted
> nWwCols
)
1582 nCellsDeleted
= nWwCols
;
1583 nWwCols
-= nCellsDeleted
;
1586 // ReadShd reads the background color of a cell
1587 // ReadDef must be called before
1588 void WW8TabBandDesc::ReadShd(const sal_uInt8
* pS
)
1590 sal_uInt8 nLen
= pS
? *(pS
- 1) : 0;
1596 pSHDs
= new WW8_SHD
[nWwCols
];
1599 short nCount
= nLen
>> 1;
1600 if (nCount
> nWwCols
)
1603 SVBT16
const * pShd
;
1605 for(i
=0, pShd
= reinterpret_cast<SVBT16
const *>(pS
); i
<nCount
; i
++, pShd
++ )
1606 pSHDs
[i
].SetWWValue( *pShd
);
1609 void WW8TabBandDesc::ReadNewShd(const sal_uInt8
* pS
, bool bVer67
, sal_uInt8 nStart
)
1611 sal_uInt8 nLen
= pS
? *(pS
- 1) : 0;
1612 if (!nLen
|| nStart
>= nWwCols
)
1616 pNewSHDs
= new Color
[nWwCols
];
1618 short nCount
= nLen
/ 10 + nStart
; //10 bytes each
1619 if (nCount
> nWwCols
)
1624 pNewSHDs
[i
++] = SwWW8ImplReader::ExtractColour(pS
, bVer67
);
1627 pNewSHDs
[i
++] = COL_AUTO
;
1632 SprmResult
HasTabCellSprm(WW8PLCFx_Cp_FKP
* pPap
, bool bVer67
)
1635 return pPap
->HasSprm(24);
1636 SprmResult aRes
= pPap
->HasSprm(0x244B);
1637 if (aRes
.pSprm
== nullptr)
1638 aRes
= pPap
->HasSprm(0x2416);
1649 sprmTTableWidth
, sprmTTextFlow
, sprmTFCantSplit
, sprmTJc
, sprmTFBiDi
,
1650 sprmTDefTable
, sprmTDyaRowHeight
, sprmTDefTableShd
, sprmTDxaLeft
,
1651 sprmTSetBrc
, sprmTSetBrc90
, sprmTDxaCol
, sprmTInsert
, sprmTDelete
,
1652 sprmTTableHeader
, sprmTDxaGapHalf
, sprmTTableBorders
, sprmTTableBorders90
,
1653 sprmTDefTableNewShd
, sprmTDefTableNewShd2nd
, sprmTDefTableNewShd3rd
,
1654 sprmTCellPadding
, sprmTCellPaddingDefault
1659 static wwTableSprm
GetTableSprm(sal_uInt16 nId
, ww::WordVersion eVer
)
1666 case NS_sprm::TTableWidth::val
:
1667 return sprmTTableWidth
;
1668 case NS_sprm::TTextFlow::val
:
1669 return sprmTTextFlow
;
1670 case NS_sprm::TTableHeader::val
:
1671 return sprmTTableHeader
;
1672 case NS_sprm::TFCantSplit::val
:
1673 return sprmTFCantSplit
;
1674 case NS_sprm::TJc90::val
:
1676 case NS_sprm::TFBiDi::val
:
1678 case NS_sprm::TDelete::val
:
1680 case NS_sprm::TInsert::val
:
1682 case NS_sprm::TDxaCol::val
:
1684 case NS_sprm::TDyaRowHeight::val
:
1685 return sprmTDyaRowHeight
;
1686 case NS_sprm::TDxaLeft::val
:
1687 return sprmTDxaLeft
;
1688 case NS_sprm::TDxaGapHalf::val
:
1689 return sprmTDxaGapHalf
;
1690 case NS_sprm::TTableBorders80::val
:
1691 return sprmTTableBorders
;
1692 case NS_sprm::TDefTable::val
:
1693 return sprmTDefTable
;
1694 case NS_sprm::TDefTableShd80::val
:
1695 return sprmTDefTableShd
;
1696 case NS_sprm::TDefTableShd::val
:
1697 return sprmTDefTableNewShd
;
1698 case NS_sprm::TDefTableShd2nd::val
:
1699 return sprmTDefTableNewShd2nd
;
1700 case NS_sprm::TDefTableShd3rd::val
:
1701 return sprmTDefTableNewShd3rd
;
1702 case NS_sprm::TTableBorders::val
:
1703 return sprmTTableBorders90
;
1704 case NS_sprm::TSetBrc80::val
:
1706 case NS_sprm::TSetBrc::val
:
1707 return sprmTSetBrc90
;
1708 case NS_sprm::TCellPadding::val
:
1709 return sprmTCellPadding
;
1710 case NS_sprm::TCellPaddingDefault::val
:
1711 return sprmTCellPaddingDefault
;
1721 return sprmTDxaLeft
;
1723 return sprmTDxaGapHalf
;
1725 return sprmTTableHeader
;
1727 return sprmTTableBorders
;
1729 return sprmTDyaRowHeight
;
1731 return sprmTDefTable
;
1733 return sprmTDefTableShd
;
1751 return sprmTDxaLeft
;
1753 return sprmTDxaGapHalf
;
1755 return sprmTDyaRowHeight
;
1757 return sprmTDefTable
;
1759 return sprmTDefTableShd
;
1774 WW8TabDesc::WW8TabDesc(SwWW8ImplReader
* pIoClass
, WW8_CP nStartCp
) :
1776 m_pFirstBand(nullptr),
1777 m_pActBand(nullptr),
1778 m_pTableNd(nullptr),
1779 m_pTabLines(nullptr),
1780 m_pTabLine(nullptr),
1781 m_pTabBoxes(nullptr),
1783 m_pCurrentWWCell(nullptr),
1785 m_nDefaultSwCols(0),
1790 m_nPreferredWidth(0),
1793 m_bClaimLineFormat(false),
1794 m_eOri(text::HoriOrientation::LEFT
),
1797 m_nCurrentBandRow(0),
1801 m_pParentPos(nullptr),
1802 m_pFlyFormat(nullptr),
1803 m_aItemSet(m_pIo
->m_rDoc
.GetAttrPool(),svl::Items
<RES_FRMATR_BEGIN
,RES_FRMATR_END
-1>)
1805 m_pIo
->m_bCurrentAND_fNumberAcross
= false;
1807 static const sal_Int16 aOriArr
[] =
1809 text::HoriOrientation::LEFT
, text::HoriOrientation::CENTER
, text::HoriOrientation::RIGHT
, text::HoriOrientation::CENTER
1812 bool bOldVer
= ww::IsSevenMinus(m_pIo
->GetFib().GetFIBVersion());
1813 WW8_TablePos aTabPos
;
1815 WW8PLCFxSave1 aSave
;
1816 m_pIo
->m_xPlcxMan
->GetPap()->Save( aSave
);
1818 WW8PLCFx_Cp_FKP
* pPap
= m_pIo
->m_xPlcxMan
->GetPapPLCF();
1820 WW8TabBandDesc
* pNewBand
= new WW8TabBandDesc
;
1822 wwSprmParser
aSprmParser(m_pIo
->GetFib());
1824 std::set
<std::pair
<WW8_CP
, WW8_CP
>> aPrevRes
;
1826 // process pPap until end of table found
1829 short nTabeDxaNew
= SHRT_MAX
;
1830 bool bTabRowJustRead
= false;
1831 const sal_uInt8
* pShadeSprm
= nullptr;
1832 const sal_uInt8
* pNewShadeSprm
[3] = {nullptr, nullptr, nullptr};
1833 const sal_uInt8
* pTableBorders
= nullptr;
1834 sal_uInt16 nTableBordersLen
= 0;
1835 const sal_uInt8
* pTableBorders90
= nullptr;
1836 sal_uInt16 nTableBorders90Len
= 0;
1838 std::vector
<std::pair
<const sal_uInt8
*, sal_uInt16
>> aTSetBrcs
, aTSetBrc90s
;
1839 WW8_TablePos
*pTabPos
= nullptr;
1841 // search end of a tab row
1842 if(!(m_pIo
->SearchRowEnd(pPap
, nStartCp
, m_pIo
->m_nInTable
)))
1848 // Get the SPRM chains:
1849 // first from PAP and then from PCD (of the Piece Table)
1851 pPap
->GetSprms( &aDesc
);
1852 WW8SprmIter
aSprmIter(aDesc
.pMemPos
, aDesc
.nSprmsLen
, aSprmParser
);
1854 for (int nLoop
= 0; nLoop
< 2; ++nLoop
)
1856 const sal_uInt8
* pParams
;
1857 while (aSprmIter
.GetSprms() && nullptr != (pParams
= aSprmIter
.GetCurrentParams()))
1859 sal_uInt16 nId
= aSprmIter
.GetCurrentId();
1860 sal_Int32 nFixedLen
= aSprmParser
.DistanceToData(nId
);
1861 sal_Int32 nL
= aSprmParser
.GetSprmSize(nId
, aSprmIter
.GetSprms(), aSprmIter
.GetRemLen());
1862 sal_Int32 nLen
= nL
- nFixedLen
;
1863 wwTableSprm eSprm
= GetTableSprm(nId
, m_pIo
->GetFib().GetFIBVersion());
1866 case sprmTTableWidth
:
1868 const sal_uInt8 b0
= pParams
[0];
1869 const sal_uInt8 b1
= pParams
[1];
1870 const sal_uInt8 b2
= pParams
[2];
1871 if (b0
== 3) // Twips
1872 m_nPreferredWidth
= b2
* 0x100 + b1
;
1873 else if (b0
== 2) // percent in fiftieths of a percent
1875 m_nPercentWidth
= (b2
* 0x100 + b1
);
1876 // MS documentation: non-negative, and 600% max
1877 if ( m_nPercentWidth
>= 0 && m_nPercentWidth
<= 30000 )
1878 m_nPercentWidth
*= .02;
1880 m_nPercentWidth
= 100;
1885 pNewBand
->ProcessDirection(pParams
);
1887 case sprmTFCantSplit
:
1888 pNewBand
->bCantSplit
= *pParams
;
1889 m_bClaimLineFormat
= true;
1891 case sprmTTableBorders
:
1892 pTableBorders
= pParams
; // process at end
1893 nTableBordersLen
= nLen
;
1895 case sprmTTableBorders90
:
1896 pTableBorders90
= pParams
; // process at end
1897 nTableBorders90Len
= nLen
;
1899 case sprmTTableHeader
:
1901 if ( m_nRowsToRepeat
== m_nRows
)
1902 m_nRowsToRepeat
= (m_nRows
+ 1);
1905 // sprmTJc - Justification Code
1907 m_eOri
= aOriArr
[*pParams
& 0x3];
1910 m_bIsBiDi
= SVBT16ToUInt16(pParams
) != 0;
1912 case sprmTDxaGapHalf
:
1913 pNewBand
->nGapHalf
= static_cast<sal_Int16
>(SVBT16ToUInt16( pParams
));
1915 case sprmTDyaRowHeight
:
1916 pNewBand
->nLineHeight
= static_cast<sal_Int16
>(SVBT16ToUInt16( pParams
));
1917 m_bClaimLineFormat
= true;
1920 pNewBand
->ReadDef(bOldVer
, pParams
, nLen
);
1921 bTabRowJustRead
= true;
1923 case sprmTDefTableShd
:
1924 pShadeSprm
= pParams
;
1926 case sprmTDefTableNewShd
:
1927 pNewShadeSprm
[0] = pParams
;
1929 case sprmTDefTableNewShd2nd
:
1930 pNewShadeSprm
[1] = pParams
;
1932 case sprmTDefTableNewShd3rd
:
1933 pNewShadeSprm
[2] = pParams
;
1936 // our Writer cannot shift single table lines
1937 // horizontally so we have to find the smallest
1938 // parameter (meaning the left-most position) and then
1939 // shift the whole table to that margin (see below)
1941 short nDxaNew
= static_cast<sal_Int16
>(SVBT16ToUInt16( pParams
));
1942 if( nDxaNew
< nTabeDxaNew
)
1943 nTabeDxaNew
= nDxaNew
;
1947 aTSetBrcs
.emplace_back(pParams
, nLen
); // process at end
1950 aTSetBrc90s
.emplace_back(pParams
, nLen
); // process at end
1953 pNewBand
->ProcessSprmTDxaCol(pParams
);
1956 pNewBand
->ProcessSprmTInsert(pParams
);
1959 pNewBand
->ProcessSprmTDelete(pParams
);
1961 case sprmTCellPaddingDefault
:
1962 pNewBand
->ProcessSpacing(pParams
);
1964 case sprmTCellPadding
:
1965 pNewBand
->ProcessSpecificSpacing(pParams
);
1970 aSprmIter
.advance();
1975 pPap
->GetPCDSprms( aDesc
);
1976 aSprmIter
.SetSprms( aDesc
.pMemPos
, aDesc
.nSprmsLen
);
1980 // WW-Tables can contain Fly-changes. For this abort tables here
1981 // and start again. *pPap is still before TabRowEnd, so TestApo()
1982 // can be called with the last parameter set to false and therefore
1985 if (bTabRowJustRead
)
1987 // Some SPRMs need to be processed *after* ReadDef is called
1988 // so they were saved up until here
1990 pNewBand
->ReadShd(pShadeSprm
);
1991 if (pNewShadeSprm
[0])
1992 pNewBand
->ReadNewShd(pNewShadeSprm
[0], bOldVer
, /*nStart=*/0);
1993 if (pNewShadeSprm
[1])
1994 pNewBand
->ReadNewShd(pNewShadeSprm
[1], bOldVer
, /*nStart=*/22);
1995 if (pNewShadeSprm
[2])
1996 pNewBand
->ReadNewShd(pNewShadeSprm
[2], bOldVer
, /*nStart=*/44);
1997 if (pTableBorders90
)
1998 pNewBand
->ProcessSprmTTableBorders(9, pTableBorders90
, nTableBorders90Len
);
1999 else if (pTableBorders
)
2000 pNewBand
->ProcessSprmTTableBorders(bOldVer
? 6 : 8,
2001 pTableBorders
, nTableBordersLen
);
2002 for (const auto& a
: aTSetBrcs
)
2003 pNewBand
->ProcessSprmTSetBRC(bOldVer
? 6 : 8, a
.first
, a
.second
);
2004 for (const auto& a
: aTSetBrc90s
)
2005 pNewBand
->ProcessSprmTSetBRC(9, a
.first
, a
.second
);
2008 if( nTabeDxaNew
< SHRT_MAX
)
2010 short* pCenter
= pNewBand
->nCenter
;
2011 short firstDxaCenter
= *pCenter
;
2012 for( int i
= 0; i
< pNewBand
->nWwCols
; i
++, ++pCenter
)
2014 // #i30298# Use sprmTDxaLeft to adjust the left indent
2015 // #i40461# Use dxaGapHalf during calculation
2017 (nTabeDxaNew
- (firstDxaCenter
+ pNewBand
->nGapHalf
));
2022 m_pActBand
= m_pFirstBand
= pNewBand
;
2025 m_pActBand
->pNextBand
= pNewBand
;
2026 m_pActBand
= pNewBand
;
2030 pNewBand
= new WW8TabBandDesc
;
2033 m_pActBand
->nRows
++;
2035 //Seek our pap to its next block of properties
2037 aRes
.pMemPos
= nullptr;
2038 aRes
.nStartPos
= nStartCp
;
2040 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2042 aRes
.nEndPos
= WW8_CP_MAX
;
2043 pPap
->SetDirty(true);
2045 pPap
->GetSprms(&aRes
);
2046 pPap
->SetDirty(false);
2048 //Are we at the end of available properties
2050 !pPap
->HasFkp() || pPap
->Where() == WW8_CP_MAX
||
2051 aRes
.nStartPos
== WW8_CP_MAX
2058 //Are we still in a table cell
2059 SprmResult aParamsRes
= HasTabCellSprm(pPap
, bOldVer
);
2060 const sal_uInt8
* pParams
= aParamsRes
.pSprm
;
2061 SprmResult aLevelRes
= pPap
->HasSprm(0x6649);
2062 const sal_uInt8
*pLevel
= aLevelRes
.pSprm
;
2064 if (!pParams
|| aParamsRes
.nRemainingData
< 1 || (1 != *pParams
) ||
2065 (pLevel
&& aLevelRes
.nRemainingData
>= 1 && (*pLevel
<= m_pIo
->m_nInTable
)))
2070 //Get the end of row new table positioning data
2071 WW8_CP nMyStartCp
=nStartCp
;
2072 if (m_pIo
->SearchRowEnd(pPap
, nMyStartCp
, m_pIo
->m_nInTable
))
2073 if (SwWW8ImplReader::ParseTabPos(&aTabPos
, pPap
))
2076 //Move back to this cell
2077 aRes
.pMemPos
= nullptr;
2078 aRes
.nStartPos
= nStartCp
;
2080 // PlcxMan currently points too far ahead so we need to bring
2081 // it back to where we are trying to make a table
2082 m_pIo
->m_xPlcxMan
->GetPap()->nOrigStartPos
= aRes
.nStartPos
;
2083 m_pIo
->m_xPlcxMan
->GetPap()->nCpOfs
= aRes
.nCpOfs
;
2084 if (!(pPap
->SeekPos(aRes
.nStartPos
)))
2086 aRes
.nEndPos
= WW8_CP_MAX
;
2087 pPap
->SetDirty(true);
2089 pPap
->GetSprms(&aRes
);
2090 pPap
->SetDirty(false);
2092 //Does this row match up with the last row closely enough to be
2093 //considered part of the same table
2094 ApoTestResults aApo
= m_pIo
->TestApo(m_pIo
->m_nInTable
+ 1, false, pTabPos
);
2097 ##513##, #79474# If this is not sufficient, then we should look at
2098 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2099 part of this table, but instead is an absolutely positioned table
2104 if (aApo
.mbStartApo
)
2106 //if there really is a fly here, and not a "null" fly then break.
2107 if (m_pIo
->ConstructApo(aApo
, pTabPos
))
2111 auto aBounds(std::make_pair(aRes
.nStartPos
, aRes
.nEndPos
));
2112 if (!aPrevRes
.insert(aBounds
).second
) //already seen these bounds, infinite loop
2114 SAL_WARN("sw.ww8", "WW8TabDesc, loop in paragraph property chain");
2117 nStartCp
= aRes
.nEndPos
;
2123 if( m_pActBand
->nRows
> 1 )
2125 // last band has more than 1 cell
2127 pNewBand
= new WW8TabBandDesc( *m_pActBand
); // create new
2128 m_pActBand
->nRows
--; // because of special treatment of border defaults
2129 pNewBand
->nRows
= 1;
2130 m_pActBand
->pNextBand
= pNewBand
; // append at the end
2132 pNewBand
= nullptr; // do not delete
2138 m_pIo
->m_xPlcxMan
->GetPap()->Restore( aSave
);
2141 WW8TabDesc::~WW8TabDesc()
2143 WW8TabBandDesc
* pR
= m_pFirstBand
;
2146 WW8TabBandDesc
* pR2
= pR
->pNextBand
;
2151 delete m_pParentPos
;
2154 void WW8TabDesc::CalcDefaults()
2156 short nMinCols
= SHRT_MAX
;
2159 m_nMinLeft
= SHRT_MAX
;
2160 m_nMaxRight
= SHRT_MIN
;
2163 If we are an honestly inline centered table, then the normal rules of
2164 engagement for left and right margins do not apply. The multiple rows are
2165 centered regardless of the actual placement of rows, so we cannot have
2166 mismatched rows as is possible in other configurations.
2168 e.g. change the example bugdoc in word from text wrapping of none (inline)
2169 to around (in frame (bApo)) and the table splits into two very disjoint
2170 rows as the beginning point of each row are very different
2172 if ((!m_pIo
->InLocalApo()) && (m_eOri
== text::HoriOrientation::CENTER
))
2174 for (pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2175 for( short i
= pR
->nWwCols
; i
>= 0; --i
)
2176 pR
->nCenter
[i
] = pR
->nCenter
[i
] - pR
->nCenter
[0];
2179 // First loop: find outermost L and R borders
2180 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2182 if( pR
->nCenter
[0] < m_nMinLeft
)
2183 m_nMinLeft
= pR
->nCenter
[0];
2185 // Following adjustment moves a border and then uses it to find width
2186 // of next cell, so collect current widths, to avoid situation when width
2187 // adjustment to too narrow cell makes next cell have negative width
2188 short nOrigWidth
[MAX_COL
+ 1];
2189 for( short i
= 0; i
< pR
->nWwCols
; i
++ )
2191 nOrigWidth
[i
] = pR
->nCenter
[i
+1] - pR
->nCenter
[i
];
2194 for( short i
= 0; i
< pR
->nWwCols
; i
++ )
2197 If the margins are so large as to make the displayable
2198 area inside them smaller than the minimum allowed then adjust the
2199 width to fit. But only do it if the two cells are not the exact
2200 same value, if they are then the cell does not really exist and will
2201 be blended together into the same cell through the use of the
2203 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2205 int nCellWidth
= pR
->nCenter
[i
+1] - pR
->nCenter
[i
];
2206 if (nCellWidth
!= nOrigWidth
[i
])
2208 if (nOrigWidth
[i
] == 0)
2209 nCellWidth
= 0; // restore zero-width "cell"
2210 else if ((pR
->nGapHalf
>= nCellWidth
) && (pR
->nGapHalf
< nOrigWidth
[i
]))
2211 nCellWidth
= pR
->nGapHalf
+ 1; // avoid false ignore
2212 else if ((nCellWidth
<= 0) && (nOrigWidth
[i
] > 0))
2213 nCellWidth
= 1; // minimal non-zero width to minimize distortion
2215 if (nCellWidth
&& ((nCellWidth
- pR
->nGapHalf
*2) < MINLAY
) && pR
->nGapHalf
< nCellWidth
)
2217 nCellWidth
= MINLAY
+ pR
->nGapHalf
* 2;
2219 pR
->nCenter
[i
+ 1] = pR
->nCenter
[i
] + nCellWidth
;
2222 if( pR
->nCenter
[pR
->nWwCols
] > m_nMaxRight
)
2223 m_nMaxRight
= pR
->nCenter
[pR
->nWwCols
];
2225 m_nSwWidth
= m_nMaxRight
- m_nMinLeft
;
2227 // If the table is right aligned we need to align all rows to the
2228 // row that has the furthest right point
2230 if(m_eOri
== text::HoriOrientation::RIGHT
)
2232 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2234 int adjust
= m_nMaxRight
- pR
->nCenter
[pR
->nWwCols
];
2235 for( short i
= 0; i
< pR
->nWwCols
+ 1; i
++ )
2237 pR
->nCenter
[i
] = static_cast< short >(pR
->nCenter
[i
] + adjust
);
2243 // 2. pass: Detect number of writer columns. This can exceed the count
2244 // of columns in WW by 2, because SW in contrast to WW does not provide
2245 // fringed left and right borders and has to fill with empty boxes.
2246 // Non existent cells can reduce the number of columns.
2248 // 3. pass: Replace border with defaults if needed
2249 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2253 pR
->pTCs
= new WW8_TCell
[ pR
->nWwCols
];
2255 for (int k
= 0; k
< pR
->nWwCols
; ++k
)
2257 WW8_TCell
& rT
= pR
->pTCs
[k
];
2258 for (int i
= 0; i
< 4; ++i
)
2260 if (rT
.rgbrc
[i
].brcType()==0)
2262 // if shadow is set, its invalid
2267 // outer top / horizontally inside
2268 j
= (pR
== m_pFirstBand
) ? 0 : 4;
2271 // outer left / vertically inside
2275 // outer bottom / horizontally inside
2276 j
= pR
->pNextBand
? 4 : 2;
2279 // outer right / vertically inside
2280 j
= (k
== pR
->nWwCols
- 1) ? 3 : 5;
2283 // merge with above defaults
2284 rT
.rgbrc
[i
] = pR
->aDefBrcs
[j
];
2290 for( pR
= m_pFirstBand
; pR
; pR
= pR
->pNextBand
)
2292 pR
->nSwCols
= pR
->nWwCols
;
2293 pR
->bLEmptyCol
= pR
->nCenter
[0] - m_nMinLeft
>= MINLAY
;
2294 pR
->bREmptyCol
= (m_nMaxRight
- pR
->nCenter
[pR
->nWwCols
]) >= MINLAY
;
2296 short nAddCols
= short(pR
->bLEmptyCol
) + short(pR
->bREmptyCol
);
2298 sal_uInt16 j
= ( pR
->bLEmptyCol
) ? 1 : 0;
2299 for (i
= 0; i
< pR
->nWwCols
; ++i
)
2301 pR
->nTransCell
[i
] = static_cast<sal_Int8
>(j
);
2302 if ( pR
->nCenter
[i
] < pR
->nCenter
[i
+1] )
2304 pR
->bExist
[i
] = true;
2309 pR
->bExist
[i
] = false;
2314 OSL_ENSURE(i
,"no columns in row ?");
2317 If the last cell was "false" then there is no valid cell following it,
2318 so the default mapping forward won't work. So map it (and
2319 contiguous invalid cells backwards to the last valid cell instead.)
2321 if (i
&& !pR
->bExist
[i
-1])
2324 while (k
&& !pR
->bExist
[k
])
2326 for (sal_uInt16 n
=k
+1;n
<i
;n
++)
2327 pR
->nTransCell
[n
] = pR
->nTransCell
[k
];
2330 pR
->nTransCell
[i
++] = static_cast<sal_Int8
>(j
++); // Can exceed by 2 among other
2331 pR
->nTransCell
[i
] = static_cast<sal_Int8
>(j
); // things because of bREmptyCol
2333 pR
->nSwCols
= pR
->nSwCols
+ nAddCols
;
2334 if( pR
->nSwCols
< nMinCols
)
2335 nMinCols
= pR
->nSwCols
;
2338 if ((m_nMinLeft
&& !m_bIsBiDi
&& text::HoriOrientation::LEFT
== m_eOri
) ||
2339 (m_nMinLeft
!= -108 && m_bIsBiDi
&& text::HoriOrientation::RIGHT
== m_eOri
)) // Word sets the first nCenter value to -108 when no indent is used
2340 m_eOri
= text::HoriOrientation::LEFT_AND_WIDTH
; // absolutely positioned
2342 m_nDefaultSwCols
= nMinCols
; // because inserting cells is cheaper than merging
2343 if( m_nDefaultSwCols
== 0 )
2345 m_pActBand
= m_pFirstBand
;
2346 m_nCurrentBandRow
= 0;
2347 OSL_ENSURE( m_pActBand
, "pActBand is 0" );
2350 void WW8TabDesc::SetSizePosition(SwFrameFormat
* pFrameFormat
)
2352 SwFrameFormat
* pApply
= pFrameFormat
;
2354 pApply
= m_pTable
->GetFrameFormat();
2355 OSL_ENSURE(pApply
,"No frame");
2356 pApply
->SetFormatAttr(m_aItemSet
);
2359 SwFormatFrameSize aSize
= pFrameFormat
->GetFrameSize();
2360 aSize
.SetHeightSizeType(SwFrameSize::Minimum
);
2361 aSize
.SetHeight(MINLAY
);
2362 pFrameFormat
->SetFormatAttr(aSize
);
2363 m_pTable
->GetFrameFormat()->SetFormatAttr(SwFormatHoriOrient(0,text::HoriOrientation::FULL
));
2367 void wwSectionManager::PrependedInlineNode(const SwPosition
&rPos
,
2368 const SwNode
&rNode
)
2370 OSL_ENSURE(!maSegments
.empty(),
2371 "should not be possible, must be at least one segment");
2372 if ((!maSegments
.empty()) && (maSegments
.back().maStart
== rPos
.GetNode()))
2373 maSegments
.back().maStart
.Assign(rNode
);
2376 void WW8TabDesc::CreateSwTable()
2378 ::SetProgressState(m_pIo
->m_nProgress
, m_pIo
->m_pDocShell
); // Update
2380 // if there is already some content on the Node append new node to ensure
2381 // that this content remains ABOVE the table
2382 SwPosition
* pPoint
= m_pIo
->m_pPaM
->GetPoint();
2383 bool bInsNode
= pPoint
->GetContentIndex() != 0;
2384 bool bSetMinHeight
= false;
2388 Set fly anchor to its anchor pos, so that if a table starts immediately
2389 at this position a new node will be inserted before inserting the table.
2391 SwFrameFormat
* pFormat
= (!bInsNode
&& m_pIo
->m_xFormatOfJustInsertedApo
)
2392 ? m_pIo
->m_xFormatOfJustInsertedApo
->GetFormat() : nullptr;
2395 const SwNode
* pAnchorNode
=
2396 pFormat
->GetAnchor().GetAnchorNode();
2397 if (pAnchorNode
&& *pAnchorNode
== pPoint
->GetNode())
2400 bSetMinHeight
= true;
2402 SwFormatSurround
aSur(pFormat
->GetSurround());
2403 aSur
.SetAnchorOnly(true);
2404 pFormat
->SetFormatAttr(aSur
);
2410 // minimize Fontsize to minimize height growth of the header/footer
2411 // set font size to 1 point to minimize y-growth of Hd/Ft
2412 SvxFontHeightItem
aSz(20, 100, RES_CHRATR_FONTSIZE
);
2413 m_pIo
->NewAttr( aSz
);
2414 m_pIo
->m_xCtrlStck
->SetAttr(*pPoint
, RES_CHRATR_FONTSIZE
);
2418 m_pIo
->AppendTextNode(*pPoint
);
2420 m_xTmpPos
= m_pIo
->m_rDoc
.CreateUnoCursor(*m_pIo
->m_pPaM
->GetPoint());
2422 // Because SW cannot handle multi-page floating frames,
2423 // _any unnecessary_ floating tables have been converted to inline.
2424 tools::Long nLeft
= 0;
2425 if (m_pIo
->m_xSFlyPara
&& !m_pIo
->m_xSFlyPara
->GetFlyFormat())
2427 // Get the table orientation from the fly
2428 // Do we also need to check m_pIo->m_xSFlyPara->bTogglePos/IsPosToggle()? [Probably not - layout-only concern]
2429 const bool bAdjustMargin
= m_pIo
->m_xSFlyPara
->eHRel
== text::RelOrientation::PAGE_FRAME
|| m_pIo
->m_xSFlyPara
->nXPos
;
2430 const bool bIsInsideMargin
= m_bIsBiDi
? m_pIo
->m_xSFlyPara
->eHAlign
== text::HoriOrientation::RIGHT
2431 : m_pIo
->m_xSFlyPara
->eHAlign
== text::HoriOrientation::LEFT
;
2432 if ( bIsInsideMargin
&& bAdjustMargin
)
2433 m_eOri
= text::HoriOrientation::LEFT_AND_WIDTH
;
2434 else if ( m_pIo
->m_xSFlyPara
->eHAlign
!= text::HoriOrientation::NONE
)
2435 m_eOri
= m_pIo
->m_xSFlyPara
->eHAlign
;
2436 if ( m_eOri
== text::HoriOrientation::LEFT_AND_WIDTH
)
2438 nLeft
= m_pIo
->m_xSFlyPara
->nXPos
;
2439 if ( m_pIo
->m_xSFlyPara
->eHRel
== text::RelOrientation::PAGE_FRAME
)
2442 nLeft
-= m_pIo
->m_aSectionManager
.GetPageLeft();
2444 nLeft
+= m_pIo
->m_aSectionManager
.GetPageRight();
2449 // The table is small: The number of columns is the lowest count of
2450 // columns of the origin, because inserting is faster than deleting.
2451 // The number of rows is the count of bands because (identically)
2452 // rows of a band can be duplicated easy.
2453 m_pTable
= m_pIo
->m_rDoc
.InsertTable(
2454 SwInsertTableOptions( SwInsertTableFlags::HeadlineNoBorder
, 0 ),
2455 *m_xTmpPos
->GetPoint(), m_nBands
, m_nDefaultSwCols
, m_eOri
);
2457 OSL_ENSURE(m_pTable
&& m_pTable
->GetFrameFormat(), "insert table failed");
2458 if (!m_pTable
|| !m_pTable
->GetFrameFormat())
2461 SwTableNode
* pTableNode
= m_pTable
->GetTableNode();
2462 OSL_ENSURE(pTableNode
, "no table node!");
2465 m_pIo
->m_aSectionManager
.PrependedInlineNode(*m_pIo
->m_pPaM
->GetPoint(),
2469 // Check if the node into which the table should be inserted already
2470 // contains a Pagedesc. If so that Pagedesc would be moved to the
2471 // row after the table, that would be wrong. So delete and
2472 // set later to the table format.
2473 if (SwTextNode
*const pNd
= m_xTmpPos
->GetPoint()->GetNode().GetTextNode())
2475 if (const SfxItemSet
* pSet
= pNd
->GetpSwAttrSet())
2477 std::unique_ptr
<SfxPoolItem
> pSetAttr
;
2479 if (const SvxFormatBreakItem
* pBreakItem
= pSet
->GetItemIfSet(RES_BREAK
, false))
2481 pSetAttr
.reset(new SvxFormatBreakItem( *pBreakItem
));
2482 pNd
->ResetAttr( RES_BREAK
);
2485 // eventually set the PageDesc/Break now to the table
2488 m_aItemSet
.Put(std::move(pSetAttr
));
2493 // total width of table
2494 if( m_nMaxRight
- m_nMinLeft
> MINLAY
* m_nDefaultSwCols
)
2496 SwFormatFrameSize
aFrameSize(SwFrameSize::Fixed
, m_nSwWidth
);
2497 // Don't set relative width if the table is in a floating frame
2498 if ( m_nPercentWidth
&& (!m_pIo
->m_xSFlyPara
|| !m_pIo
->m_xSFlyPara
->GetFlyFormat()) )
2499 aFrameSize
.SetWidthPercent(m_nPercentWidth
);
2500 m_pTable
->GetFrameFormat()->SetFormatAttr(aFrameSize
);
2501 m_aItemSet
.Put(aFrameSize
);
2504 SvxFrameDirectionItem
aDirection(
2505 m_bIsBiDi
? SvxFrameDirection::Horizontal_RL_TB
: SvxFrameDirection::Horizontal_LR_TB
, RES_FRAMEDIR
);
2506 m_pTable
->GetFrameFormat()->SetFormatAttr(aDirection
);
2508 if (text::HoriOrientation::LEFT_AND_WIDTH
== m_eOri
)
2510 if (!m_pIo
->m_nInTable
&& m_pIo
->InLocalApo() && m_pIo
->m_xSFlyPara
&&
2511 m_pIo
->m_xSFlyPara
->GetFlyFormat() && GetMinLeft())
2513 //If we are inside a frame and we have a border, the frames
2514 //placement does not consider the tables border, which word
2515 //displays outside the frame, so adjust here.
2516 SwFormatHoriOrient
aHori(m_pIo
->m_xSFlyPara
->GetFlyFormat()->GetHoriOrient());
2517 sal_Int16 eHori
= aHori
.GetHoriOrient();
2518 if ((eHori
== text::HoriOrientation::NONE
) || (eHori
== text::HoriOrientation::LEFT
) ||
2519 (eHori
== text::HoriOrientation::LEFT_AND_WIDTH
))
2521 //With multiple table, use last table settings. Perhaps
2522 //the maximum is what word does ?
2523 aHori
.SetPos(m_pIo
->m_xSFlyPara
->nXPos
+ GetMinLeft());
2524 aHori
.SetHoriOrient(text::HoriOrientation::NONE
);
2525 m_pIo
->m_xSFlyPara
->GetFlyFormat()->SetFormatAttr(aHori
);
2528 else // Not directly in a floating frame.
2530 //Historical note: If InLocalApo(), then this table is being placed in a floating
2531 //frame, and the frame matches the left and right *lines* of the
2532 //table, so the space to the left of the table isn't to be used
2533 //inside the frame, in word the dialog involved greys out the
2534 //ability to set the margin.
2535 SvxLRSpaceItem
aL( RES_LR_SPACE
);
2538 nLeft
+= GetMinLeft();
2541 const short nTableWidth
= m_nPreferredWidth
? m_nPreferredWidth
: m_nSwWidth
;
2542 nLeft
+= m_pIo
->m_aSectionManager
.GetTextAreaWidth();
2543 nLeft
= nLeft
- nTableWidth
- GetMinLeft();
2551 mxOldRedlineStack
= std::move(m_pIo
->m_xRedlineStack
);
2552 m_pIo
->m_xRedlineStack
.reset(new sw::util::RedlineStack(m_pIo
->m_rDoc
));
2555 void WW8TabDesc::UseSwTable()
2558 m_pTabLines
= &m_pTable
->GetTabLines();
2559 m_nCurrentRow
= m_nCurrentCol
= m_nCurrentBandRow
= 0;
2561 m_pTableNd
= const_cast<SwTableNode
*>((*m_pTabLines
)[0]->GetTabBoxes()[0]->
2562 GetSttNd()->FindTableNode());
2563 OSL_ENSURE( m_pTableNd
, "Where is my table node" );
2565 // #i69519# - Restrict rows to repeat to a decent value
2566 if ( m_nRowsToRepeat
== o3tl::narrowing
<sal_uInt16
>(m_nRows
) )
2567 m_nRowsToRepeat
= 1;
2569 m_pTableNd
->GetTable().SetRowsToRepeat( m_nRowsToRepeat
);
2570 // insert extra cells if needed and something like this
2573 WW8DupProperties
aDup(m_pIo
->m_rDoc
, m_pIo
->m_xCtrlStck
.get());
2574 m_pIo
->m_xCtrlStck
->SetAttr(*m_pIo
->m_pPaM
->GetPoint(), 0, false);
2576 // now set the correct PaM and prepare first merger group if any
2577 SetPamInCell(m_nCurrentCol
, true);
2578 aDup
.Insert(*m_pIo
->m_pPaM
->GetPoint());
2580 m_pIo
->m_bWasTabRowEnd
= false;
2581 m_pIo
->m_bWasTabCellEnd
= false;
2584 void WW8TabDesc::MergeCells()
2588 for (m_pActBand
=m_pFirstBand
, nRow
=0; m_pActBand
; m_pActBand
=m_pActBand
->pNextBand
)
2590 // insert current box into merge group if appropriate.
2591 // The algorithm must ensure proper row and column order in WW8SelBoxInfo!
2592 if( m_pActBand
->pTCs
)
2594 for( short j
= 0; j
< m_pActBand
->nRows
; j
++, nRow
++ )
2595 for( short i
= 0; i
< m_pActBand
->nWwCols
; i
++ )
2597 WW8SelBoxInfo
* pActMGroup
= nullptr;
2599 // start a new merge group if appropriate
2601 OSL_ENSURE(nRow
< o3tl::narrowing
<sal_uInt16
>(m_pTabLines
->size()),
2602 "Too few lines, table ended early");
2603 if (nRow
>= o3tl::narrowing
<sal_uInt16
>(m_pTabLines
->size()))
2605 m_pTabLine
= (*m_pTabLines
)[ nRow
];
2606 m_pTabBoxes
= &m_pTabLine
->GetTabBoxes();
2608 sal_uInt16 nCol
= m_pActBand
->nTransCell
[ i
];
2609 if (!m_pActBand
->bExist
[i
])
2611 OSL_ENSURE(nCol
< m_pTabBoxes
->size(),
2612 "Too few columns, table ended early");
2613 if (nCol
>= m_pTabBoxes
->size())
2615 m_pTabBox
= (*m_pTabBoxes
)[nCol
];
2616 WW8_TCell
& rCell
= m_pActBand
->pTCs
[ i
];
2617 // is this the left upper cell of a merge group ?
2619 bool bMerge
= false;
2620 if ( rCell
.bVertRestart
&& !rCell
.bMerged
)
2622 else if (rCell
.bFirstMerged
&& m_pActBand
->bExist
[i
])
2624 // Some tests to avoid merging cells which previously were
2625 // declared invalid because of sharing the exact same dimensions
2626 // as their previous cell
2628 //If there's anything underneath/above we're ok.
2629 if (rCell
.bVertMerge
|| rCell
.bVertRestart
)
2633 //If it's a hori merge only, and the only things in
2634 //it are invalid cells then it's already taken care
2635 //of, so don't merge.
2636 for (sal_uInt16 i2
= i
+1; i2
< m_pActBand
->nWwCols
; i2
++ )
2637 if (m_pActBand
->pTCs
[ i2
].bMerged
&&
2638 !m_pActBand
->pTCs
[ i2
].bFirstMerged
)
2640 if (m_pActBand
->bExist
[i2
])
2651 // remove numbering from cells that will be disabled in the merge
2652 if( rCell
.bVertMerge
&& !rCell
.bVertRestart
)
2654 SwPaM
aPam( *m_pTabBox
->GetSttNd(), 0 );
2655 aPam
.GetPoint()->Adjust(SwNodeOffset(1));
2656 SwTextNode
* pNd
= aPam
.GetPointNode().GetTextNode();
2659 pNd
->SetCountedInList( false );
2661 aPam
.GetPoint()->Adjust(SwNodeOffset(1));
2662 pNd
= aPam
.GetPointNode().GetTextNode();
2668 short nX1
= m_pActBand
->nCenter
[ i
];
2669 short nWidth
= m_pActBand
->nWidth
[ i
];
2671 // 2. create current merge group
2672 pActMGroup
= new WW8SelBoxInfo( nX1
, nWidth
);
2674 // determine size of new merge group
2675 // before inserted the new merge group.
2676 // Needed to correctly locked previously created merge groups.
2677 // Calculate total width and set
2678 short nSizCell
= m_pActBand
->nWidth
[ i
];
2679 for (sal_uInt16 i2
= i
+1; i2
< m_pActBand
->nWwCols
; i2
++ )
2680 if (m_pActBand
->pTCs
[ i2
].bMerged
&&
2681 !m_pActBand
->pTCs
[ i2
].bFirstMerged
)
2683 nSizCell
= nSizCell
+ m_pActBand
->nWidth
[ i2
];
2687 pActMGroup
->m_nGroupWidth
= nSizCell
;
2689 // locked previously created merge groups,
2690 // after determining the size for the new merge group.
2691 // 1. If necessary close old merge group(s) that overlap
2692 // the X-area of the new group
2695 WW8SelBoxInfo
* p
= FindMergeGroup(
2696 nX1
, pActMGroup
->m_nGroupWidth
, false );
2701 p
->m_bGroupLocked
= true;
2704 // 3. push to group array
2705 m_MergeGroups
.push_back(std::unique_ptr
<WW8SelBoxInfo
>(pActMGroup
));
2708 // if necessary add the current box to a merge group
2709 // (that can be a newly created or another group)
2710 UpdateTableMergeGroup( rCell
, pActMGroup
, m_pTabBox
, i
);
2716 //There is a limbo area in word at the end of the row marker
2717 //where properties can live in word, there is no location in
2718 //writer equivalent, so try and park the cursor in the best
2719 //match, see #i23022#/#i18644#
2720 void WW8TabDesc::ParkPaM()
2722 SwTableBox
*pTabBox2
= nullptr;
2723 short nRow
= m_nCurrentRow
+ 1;
2724 if (nRow
< o3tl::narrowing
<sal_uInt16
>(m_pTabLines
->size()))
2726 if (SwTableLine
*pLine
= (*m_pTabLines
)[nRow
])
2728 SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
2729 pTabBox2
= rBoxes
.empty() ? nullptr : rBoxes
.front();
2733 if (!pTabBox2
|| !pTabBox2
->GetSttNd())
2739 SwNodeOffset nSttNd
= pTabBox2
->GetSttIdx() + 1,
2740 nEndNd
= pTabBox2
->GetSttNd()->EndOfSectionIndex();
2742 if (m_pIo
->m_pPaM
->GetPoint()->GetNodeIndex() != nSttNd
)
2746 m_pIo
->m_pPaM
->GetPoint()->Assign(nSttNd
);
2748 while (m_pIo
->m_pPaM
->GetPointNode().GetNodeType() != SwNodeType::Text
&& ++nSttNd
< nEndNd
);
2750 m_pIo
->m_pPaM
->GetPoint()->SetContent(0);
2751 m_pIo
->m_rDoc
.SetTextFormatColl(*m_pIo
->m_pPaM
, const_cast<SwTextFormatColl
*>(m_pIo
->m_pDfltTextFormatColl
));
2755 void WW8TabDesc::MoveOutsideTable()
2757 OSL_ENSURE(m_xTmpPos
&& m_pIo
, "I've forgotten where the table is anchored");
2758 if (m_xTmpPos
&& m_pIo
)
2759 *m_pIo
->m_pPaM
->GetPoint() = *m_xTmpPos
->GetPoint();
2762 void WW8TabDesc::FinishSwTable()
2764 m_pIo
->m_xRedlineStack
->closeall(*m_pIo
->m_pPaM
->GetPoint());
2766 // ofz#38011 drop m_pLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
2767 // place, or somewhere close if that place got destroyed
2768 std::shared_ptr
<SwUnoCursor
> xLastAnchorCursor(m_pIo
->m_oLastAnchorPos
? m_pIo
->m_rDoc
.CreateUnoCursor(*m_pIo
->m_oLastAnchorPos
) : nullptr);
2769 m_pIo
->m_oLastAnchorPos
.reset();
2771 SwTableNode
* pTableNode
= m_pTable
->GetTableNode();
2772 SwDeleteListener
aListener(*pTableNode
);
2773 m_pIo
->m_xRedlineStack
= std::move(mxOldRedlineStack
);
2775 if (xLastAnchorCursor
)
2776 m_pIo
->m_oLastAnchorPos
.emplace(*xLastAnchorCursor
->GetPoint());
2778 WW8DupProperties
aDup(m_pIo
->m_rDoc
,m_pIo
->m_xCtrlStck
.get());
2779 m_pIo
->m_xCtrlStck
->SetAttr( *m_pIo
->m_pPaM
->GetPoint(), 0, false);
2784 aDup
.Insert(*m_pIo
->m_pPaM
->GetPoint());
2786 m_pIo
->m_bWasTabRowEnd
= false;
2787 m_pIo
->m_bWasTabCellEnd
= false;
2789 m_pIo
->m_aInsertedTables
.InsertTable(*m_pTableNd
, *m_pIo
->m_pPaM
);
2791 if (aListener
.WasDeleted())
2792 throw std::runtime_error("table unexpectedly destroyed by applying redlines");
2796 // if needed group cells together that should be merged
2797 if (m_MergeGroups
.empty())
2800 // process all merge groups one by one
2801 for (auto const& groupIt
: m_MergeGroups
)
2803 if((1 < groupIt
->size()) && groupIt
->row(0)[0])
2805 SwFrameFormat
* pNewFormat
= groupIt
->row(0)[0]->ClaimFrameFormat();
2806 pNewFormat
->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Variable
, groupIt
->m_nGroupWidth
, 0));
2807 const sal_uInt16 nRowSpan
= groupIt
->rowsCount();
2808 for (sal_uInt16 n
= 0; n
< nRowSpan
; ++n
)
2810 auto& rRow
= groupIt
->row(n
);
2811 for (size_t i
= 0; i
<rRow
.size(); ++i
)
2813 const sal_Int32 nRowSpanSet
= (n
== 0) && (i
== 0) ?
2815 (-1 * (nRowSpan
- n
));
2816 SwTableBox
* pCurrentBox
= rRow
[i
];
2817 pCurrentBox
->setRowSpan(nRowSpanSet
);
2820 pCurrentBox
->ChgFrameFormat(static_cast<SwTableBoxFormat
*>(pNewFormat
));
2823 SwFrameFormat
* pFormat
= pCurrentBox
->ClaimFrameFormat();
2824 pFormat
->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Variable
, 0, 0));
2830 m_pIo
->m_xFormatOfJustInsertedApo
.reset();
2831 m_MergeGroups
.clear();
2834 // browse m_MergeGroups, detect the index of the first fitting group or -1 otherwise
2836 // Parameter: nXcenter = center position of asking box
2837 // nWidth = width of asking box
2838 // bExact = flag, if box has to fit into group
2839 // or only has to touch
2841 WW8SelBoxInfo
* WW8TabDesc::FindMergeGroup(short nX1
, short nWidth
, bool bExact
)
2843 if (!m_MergeGroups
.empty())
2845 // still valid area near the boundary
2846 const short nTolerance
= 4;
2848 short nX2
= nX1
+ nWidth
;
2849 // approximate group boundary
2853 // improvement: search backwards
2854 for (short iGr
= m_MergeGroups
.size() - 1; iGr
>= 0; --iGr
)
2856 // the currently inspected group
2857 WW8SelBoxInfo
& rActGroup
= *m_MergeGroups
[ iGr
];
2858 if (!rActGroup
.m_bGroupLocked
)
2860 // approximate group boundary with room (tolerance) to the *outside*
2861 nGrX1
= rActGroup
.m_nGroupXStart
- nTolerance
;
2862 nGrX2
= rActGroup
.m_nGroupXStart
2863 + rActGroup
.m_nGroupWidth
+ nTolerance
;
2865 // If box fits report success
2867 if( ( nX1
> nGrX1
) && ( nX2
< nGrX2
) )
2872 // does the box share areas with the group?
2876 // successful if nX1 *or* nX2 are inside the group
2877 if( ( ( nX1
> nGrX1
)
2878 && ( nX1
< nGrX2
- 2*nTolerance
) )
2879 || ( ( nX2
> nGrX1
+ 2*nTolerance
)
2880 && ( nX2
< nGrX2
) )
2881 // or nX1 and nX2 surround the group
2882 || ( ( nX1
<=nGrX1
)
2883 && ( nX2
>=nGrX2
) ) )
2894 bool WW8TabDesc::IsValidCell(short nCol
) const
2896 return (o3tl::make_unsigned(nCol
) < SAL_N_ELEMENTS(m_pActBand
->bExist
)) &&
2897 m_pActBand
->bExist
[nCol
] &&
2898 o3tl::make_unsigned(m_nCurrentRow
) < m_pTabLines
->size();
2901 bool WW8TabDesc::InFirstParaInCell() const
2904 if (!m_pTabBox
|| !m_pTabBox
->GetSttNd())
2906 OSL_FAIL("Problem with table");
2910 if (!IsValidCell(GetCurrentCol()))
2913 return m_pIo
->m_pPaM
->GetPoint()->GetNodeIndex() == m_pTabBox
->GetSttIdx() + 1;
2916 void WW8TabDesc::SetPamInCell(short nWwCol
, bool bPam
)
2918 OSL_ENSURE( m_pActBand
, "pActBand is 0" );
2922 sal_uInt16 nCol
= m_pActBand
->transCell(nWwCol
);
2924 if (o3tl::make_unsigned(m_nCurrentRow
) >= m_pTabLines
->size())
2926 OSL_ENSURE(false, "Actual row bigger than expected." );
2932 m_pTabLine
= (*m_pTabLines
)[m_nCurrentRow
];
2933 m_pTabBoxes
= &m_pTabLine
->GetTabBoxes();
2935 if (nCol
>= m_pTabBoxes
->size())
2939 // The first paragraph in a cell with upper autospacing has upper
2942 m_pIo
->m_bParaAutoBefore
&& m_pIo
->m_bFirstPara
&&
2943 !m_pIo
->m_xWDop
->fDontUseHTMLAutoSpacing
2946 m_pIo
->SetUpperSpacing(*m_pIo
->m_pPaM
, 0);
2949 // The last paragraph in a cell with lower autospacing has lower
2951 if (m_pIo
->m_bParaAutoAfter
&& !m_pIo
->m_xWDop
->fDontUseHTMLAutoSpacing
)
2952 m_pIo
->SetLowerSpacing(*m_pIo
->m_pPaM
, 0);
2958 m_pTabBox
= (*m_pTabBoxes
)[nCol
];
2959 if( !m_pTabBox
->GetSttNd() )
2961 OSL_ENSURE(m_pTabBox
->GetSttNd(), "Problems building the table");
2969 m_pCurrentWWCell
= &m_pActBand
->pTCs
[ nWwCol
];
2971 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2972 if(m_pIo
->m_bParaAutoBefore
&& m_pIo
->m_bFirstPara
&& !m_pIo
->m_xWDop
->fDontUseHTMLAutoSpacing
)
2973 m_pIo
->SetUpperSpacing(*m_pIo
->m_pPaM
, 0);
2975 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2976 if(m_pIo
->m_bParaAutoAfter
&& !m_pIo
->m_xWDop
->fDontUseHTMLAutoSpacing
)
2977 m_pIo
->SetLowerSpacing(*m_pIo
->m_pPaM
, 0);
2979 //We need to set the pPaM on the first cell, invalid
2980 //or not so that we can collect paragraph properties over
2981 //all the cells, but in that case on the valid cell we do not
2982 //want to reset the fmt properties
2983 SwNodeOffset nSttNd
= m_pTabBox
->GetSttIdx() + 1,
2984 nEndNd
= m_pTabBox
->GetSttNd()->EndOfSectionIndex();
2985 if (m_pIo
->m_pPaM
->GetPoint()->GetNodeIndex() != nSttNd
)
2989 m_pIo
->m_pPaM
->GetPoint()->Assign(nSttNd
);
2991 while (m_pIo
->m_pPaM
->GetPointNode().GetNodeType() != SwNodeType::Text
&& ++nSttNd
< nEndNd
);
2992 m_pIo
->m_pPaM
->GetPoint()->SetContent(0);
2993 // Precautionally set now, otherwise the style is not set for cells
2994 // that are inserted for margin balancing.
2995 m_pIo
->m_rDoc
.SetTextFormatColl(*m_pIo
->m_pPaM
, const_cast<SwTextFormatColl
*>(m_pIo
->m_pDfltTextFormatColl
));
2996 // because this cells are invisible helper constructions only to simulate
2997 // the frayed view of WW-tables we do NOT need SetTextFormatCollAndListLevel()
3000 // Better to turn Snap to Grid off for all paragraphs in tables
3001 SwPosition
* pGridPos
= m_pIo
->m_pPaM
->GetPoint();
3002 SwTextNode
*pNd
= pGridPos
->GetNode().GetTextNode();
3006 const SfxPoolItem
&rItm
= pNd
->SwContentNode::GetAttr(RES_PARATR_SNAPTOGRID
);
3007 const SvxParaGridItem
&rSnapToGrid
= static_cast<const SvxParaGridItem
&>(rItm
);
3009 if(!rSnapToGrid
.GetValue())
3012 SvxParaGridItem
aGridItem( rSnapToGrid
);
3013 aGridItem
.SetValue(false);
3015 const sal_Int32 nEnd
= pGridPos
->GetContentIndex();
3016 pGridPos
->SetContent(0);
3017 m_pIo
->m_xCtrlStck
->NewAttr(*pGridPos
, aGridItem
);
3018 pGridPos
->SetContent(nEnd
);
3019 m_pIo
->m_xCtrlStck
->SetAttr(*pGridPos
, RES_PARATR_SNAPTOGRID
);
3022 void WW8TabDesc::InsertCells( short nIns
)
3024 m_pTabLine
= (*m_pTabLines
)[m_nCurrentRow
];
3025 m_pTabBoxes
= &m_pTabLine
->GetTabBoxes();
3026 m_pTabBox
= (*m_pTabBoxes
)[0];
3028 m_pIo
->m_rDoc
.GetNodes().InsBoxen( m_pTableNd
, m_pTabLine
, static_cast<SwTableBoxFormat
*>(m_pTabBox
->GetFrameFormat()),
3029 const_cast<SwTextFormatColl
*>(m_pIo
->m_pDfltTextFormatColl
), nullptr, m_pTabBoxes
->size(), nIns
);
3030 // The third parameter contains the FrameFormat of the boxes.
3031 // Here it is possible to optimize to save (reduce) FrameFormats.
3034 void WW8TabDesc::SetTabBorders(SwTableBox
* pBox
, short nWwIdx
)
3036 if( nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3037 return; // faked cells -> no border
3039 SvxBoxItem
aFormatBox( RES_BOX
);
3040 if (m_pActBand
->pTCs
) // neither Cell Border nor Default Border defined ?
3042 WW8_TCell
* pT
= &m_pActBand
->pTCs
[nWwIdx
];
3043 if (SwWW8ImplReader::IsBorder(pT
->rgbrc
))
3044 SwWW8ImplReader::SetBorder(aFormatBox
, pT
->rgbrc
);
3047 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwTOP
))
3049 aFormatBox
.SetDistance(
3050 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwTOP
],
3051 SvxBoxItemLine::TOP
);
3054 aFormatBox
.SetDistance(m_pActBand
->mnDefaultTop
, SvxBoxItemLine::TOP
);
3055 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwBOTTOM
))
3057 aFormatBox
.SetDistance(
3058 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwBOTTOM
],
3059 SvxBoxItemLine::BOTTOM
);
3062 aFormatBox
.SetDistance(m_pActBand
->mnDefaultBottom
,SvxBoxItemLine::BOTTOM
);
3064 // nGapHalf for WW is a *horizontal* gap between table cell and content.
3066 m_pActBand
->mbHasSpacing
? m_pActBand
->mnDefaultLeft
: m_pActBand
->nGapHalf
;
3068 m_pActBand
->mbHasSpacing
? m_pActBand
->mnDefaultRight
: m_pActBand
->nGapHalf
;
3069 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwLEFT
))
3071 aFormatBox
.SetDistance(
3072 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwLEFT
],
3073 SvxBoxItemLine::LEFT
);
3076 aFormatBox
.SetDistance(nLeftDist
, SvxBoxItemLine::LEFT
);
3077 if (m_pActBand
->nOverrideSpacing
[nWwIdx
] & (1 << WW8TabBandDesc::wwRIGHT
))
3079 aFormatBox
.SetDistance(
3080 m_pActBand
->nOverrideValues
[nWwIdx
][WW8TabBandDesc::wwRIGHT
],
3081 SvxBoxItemLine::RIGHT
);
3084 aFormatBox
.SetDistance(nRightDist
,SvxBoxItemLine::RIGHT
);
3086 pBox
->GetFrameFormat()->SetFormatAttr(aFormatBox
);
3089 void WW8TabDesc::SetTabShades( SwTableBox
* pBox
, short nWwIdx
)
3091 if( nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3092 return; // faked cells -> no color
3095 if (m_pActBand
->pNewSHDs
&& m_pActBand
->pNewSHDs
[nWwIdx
] != COL_AUTO
)
3097 Color
aColor(m_pActBand
->pNewSHDs
[nWwIdx
]);
3098 pBox
->GetFrameFormat()->SetFormatAttr(SvxBrushItem(aColor
, RES_BACKGROUND
));
3102 //If there was no new shades, or no new shade setting
3103 if (m_pActBand
->pSHDs
&& !bFound
)
3105 WW8_SHD
& rSHD
= m_pActBand
->pSHDs
[nWwIdx
];
3106 if (!rSHD
.GetValue()) // auto
3109 SwWW8Shade
aSh( m_pIo
->m_bVer67
, rSHD
);
3110 pBox
->GetFrameFormat()->SetFormatAttr(SvxBrushItem(aSh
.m_aColor
, RES_BACKGROUND
));
3114 static SvxFrameDirection
MakeDirection(sal_uInt16 nCode
, bool bIsBiDi
)
3116 SvxFrameDirection eDir
= SvxFrameDirection::Environment
;
3117 // 1: Asian layout with rotated CJK characters
3119 // 3: Western layout rotated by 90 degrees
3120 // 4: Western layout
3124 OSL_ENSURE(eDir
== SvxFrameDirection::Environment
, "unknown direction code, maybe it's a bitfield");
3127 eDir
= SvxFrameDirection::Vertical_LR_BT
;
3130 eDir
= SvxFrameDirection::Vertical_RL_TB
;
3133 eDir
= SvxFrameDirection::Vertical_RL_TB
;
3136 eDir
= bIsBiDi
? SvxFrameDirection::Horizontal_RL_TB
: SvxFrameDirection::Horizontal_LR_TB
; // #i38158# - Consider RTL tables
3142 void WW8TabDesc::SetTabDirection(SwTableBox
* pBox
, short nWwIdx
)
3144 if (nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3146 SvxFrameDirectionItem
aItem(MakeDirection(m_pActBand
->maDirections
[nWwIdx
], m_bIsBiDi
), RES_FRAMEDIR
);
3147 pBox
->GetFrameFormat()->SetFormatAttr(aItem
);
3150 void WW8TabDesc::SetTabVertAlign( SwTableBox
* pBox
, short nWwIdx
)
3152 if( nWwIdx
< 0 || nWwIdx
>= m_pActBand
->nWwCols
)
3155 sal_Int16 eVertOri
=text::VertOrientation::TOP
;
3157 if( m_pActBand
->pTCs
)
3159 WW8_TCell
* pT
= &m_pActBand
->pTCs
[nWwIdx
];
3160 switch (pT
->nVertAlign
)
3164 eVertOri
= text::VertOrientation::TOP
;
3167 eVertOri
= text::VertOrientation::CENTER
;
3170 eVertOri
= text::VertOrientation::BOTTOM
;
3175 pBox
->GetFrameFormat()->SetFormatAttr( SwFormatVertOrient(0,eVertOri
) );
3178 void WW8TabDesc::AdjustNewBand()
3180 if( m_pActBand
->nSwCols
> m_nDefaultSwCols
) // split cells
3181 InsertCells( m_pActBand
->nSwCols
- m_nDefaultSwCols
);
3183 SetPamInCell( 0, false);
3184 OSL_ENSURE( m_pTabBoxes
&& m_pTabBoxes
->size() == o3tl::narrowing
<sal_uInt16
>(m_pActBand
->nSwCols
),
3185 "Wrong column count in table" );
3187 if( m_bClaimLineFormat
)
3189 m_pTabLine
->ClaimFrameFormat(); // necessary because of cell height
3190 SwFormatFrameSize
aF( SwFrameSize::Minimum
, 0, 0 ); // default
3192 if (m_pActBand
->nLineHeight
== 0) // 0 = Auto
3193 aF
.SetHeightSizeType( SwFrameSize::Variable
);
3196 if (m_pActBand
->nLineHeight
< 0) // positive = min, negative = exact
3198 aF
.SetHeightSizeType(SwFrameSize::Fixed
);
3199 m_pActBand
->nLineHeight
= -m_pActBand
->nLineHeight
;
3201 if (m_pActBand
->nLineHeight
< MINLAY
) // invalid cell height
3202 m_pActBand
->nLineHeight
= MINLAY
;
3204 aF
.SetHeight(m_pActBand
->nLineHeight
);// set min/exact height
3206 m_pTabLine
->GetFrameFormat()->SetFormatAttr(aF
);
3209 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3210 //we can split the row
3211 bool bSetCantSplit
= m_pActBand
->bCantSplit
;
3212 m_pTabLine
->GetFrameFormat()->SetFormatAttr(SwFormatRowSplit(!bSetCantSplit
));
3214 // if table is only a single row, and row is set as don't split, set the same value for the whole table.
3215 if (bSetCantSplit
&& m_pTabLines
->size() == 1)
3216 m_pTable
->GetFrameFormat()->SetFormatAttr(SwFormatLayoutSplit(false));
3218 short i
; // SW-Index
3219 short j
; // WW-Index
3221 SwFormatFrameSize
aFS( SwFrameSize::Fixed
);
3222 j
= m_pActBand
->bLEmptyCol
? -1 : 0;
3224 for( i
= 0; i
< m_pActBand
->nSwCols
; i
++ )
3228 nW
= m_pActBand
->nCenter
[0] - m_nMinLeft
;
3231 //Set j to first non invalid cell
3232 while ((j
< m_pActBand
->nWwCols
) && (!m_pActBand
->bExist
[j
]))
3235 if( j
< m_pActBand
->nWwCols
)
3236 nW
= m_pActBand
->nCenter
[j
+1] - m_pActBand
->nCenter
[j
];
3238 nW
= m_nMaxRight
- m_pActBand
->nCenter
[j
];
3239 m_pActBand
->nWidth
[ j
] = nW
;
3242 SwTableBox
* pBox
= (*m_pTabBoxes
)[i
];
3243 // could be reduced further by intelligent moving of FrameFormats
3244 pBox
->ClaimFrameFormat();
3246 SetTabBorders(pBox
, j
);
3248 SvxBoxItem
aCurrentBox(pBox
->GetFrameFormat()->GetFormatAttr(RES_BOX
));
3249 pBox
->GetFrameFormat()->SetFormatAttr(aCurrentBox
);
3251 SetTabVertAlign(pBox
, j
);
3252 SetTabDirection(pBox
, j
);
3253 if( m_pActBand
->pSHDs
|| m_pActBand
->pNewSHDs
)
3254 SetTabShades(pBox
, j
);
3258 pBox
->GetFrameFormat()->SetFormatAttr( aFS
);
3260 // skip non existing cells
3261 while( ( j
< m_pActBand
->nWwCols
) && !m_pActBand
->bExist
[j
] )
3263 m_pActBand
->nWidth
[j
] = m_pActBand
->nCenter
[j
+1] - m_pActBand
->nCenter
[j
];
3269 void WW8TabDesc::TableCellEnd()
3271 ::SetProgressState(m_pIo
->m_nProgress
, m_pIo
->m_pDocShell
); // Update
3274 if( m_pIo
->m_bWasTabRowEnd
)
3276 // bWasTabRowEnd will be deactivated in
3277 // SwWW8ImplReader::ProcessSpecial()
3279 sal_uInt16 iCol
= GetLogicalWWCol();
3280 if (iCol
< m_aNumRuleNames
.size())
3282 m_aNumRuleNames
.erase(m_aNumRuleNames
.begin() + iCol
,
3283 m_aNumRuleNames
.end());
3288 m_nCurrentBandRow
++;
3289 OSL_ENSURE( m_pActBand
, "pActBand is 0" );
3292 if( m_nCurrentRow
>= m_nRows
) // nothing to at end of table
3295 bool bNewBand
= m_nCurrentBandRow
>= m_pActBand
->nRows
;
3297 { // new band needed ?
3298 m_pActBand
= m_pActBand
->pNextBand
;
3299 m_nCurrentBandRow
= 0;
3300 OSL_ENSURE( m_pActBand
, "pActBand is 0" );
3305 SwTableBox
* pBox
= (*m_pTabBoxes
)[0];
3307 m_pIo
->m_rDoc
.InsertRow( SwTable::SelLineFromBox( pBox
, aBoxes
) );
3312 { // new column ( cell )
3315 SetPamInCell(m_nCurrentCol
, true);
3317 // finish Annotated Level Numbering ?
3318 if (m_pIo
->m_bAnl
&& !m_pIo
->m_bCurrentAND_fNumberAcross
&& m_pActBand
)
3319 m_pIo
->StopAllAnl(IsValidCell(m_nCurrentCol
));
3322 // if necessary register the box for the merge group for this column
3323 void WW8TabDesc::UpdateTableMergeGroup( WW8_TCell
const & rCell
,
3324 WW8SelBoxInfo
* pActGroup
,
3325 SwTableBox
* pActBox
,
3328 // check if the box has to be merged
3329 // If cell is the first one to be merged, a new merge group has to be provided.
3330 // E.g., it could be that a cell is the first one to be merged, but no
3331 // new merge group is provided, because the potential other cell to be merged
3332 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3333 if ( !(m_pActBand
->bExist
[ nCol
] &&
3334 ( ( rCell
.bFirstMerged
&& pActGroup
) ||
3337 rCell
.bVertRestart
)) )
3340 // detect appropriate merge group
3341 WW8SelBoxInfo
* pTheMergeGroup
= nullptr;
3344 pTheMergeGroup
= pActGroup
;
3348 pTheMergeGroup
= FindMergeGroup(
3349 m_pActBand
->nCenter
[ nCol
], m_pActBand
->nWidth
[ nCol
], true );
3351 if( pTheMergeGroup
)
3353 // add current box to merge group
3354 pTheMergeGroup
->push_back(pActBox
);
3358 sal_uInt16
WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3360 sal_uInt16 nCol
= 0;
3361 if( m_pActBand
&& m_pActBand
->pTCs
)
3363 for( sal_uInt16 iCol
= 1; iCol
<= m_nCurrentCol
&& iCol
<= m_pActBand
->nWwCols
; ++iCol
)
3365 if( !m_pActBand
->pTCs
[ iCol
-1 ].bMerged
)
3372 // find name of numrule valid for current WW-COL
3373 OUString
WW8TabDesc::GetNumRuleName() const
3375 sal_uInt16 nCol
= GetLogicalWWCol();
3376 if (nCol
< m_aNumRuleNames
.size())
3377 return m_aNumRuleNames
[nCol
];
3381 void WW8TabDesc::SetNumRuleName( const OUString
& rName
)
3383 sal_uInt16 nCol
= GetLogicalWWCol();
3384 for (sal_uInt16 nSize
= static_cast< sal_uInt16
>(m_aNumRuleNames
.size()); nSize
<= nCol
; ++nSize
)
3385 m_aNumRuleNames
.emplace_back();
3386 m_aNumRuleNames
[nCol
] = rName
;
3389 bool SwWW8ImplReader::StartTable(WW8_CP nStartCp
)
3391 // Entering a table so make sure the FirstPara flag gets set
3392 m_bFirstPara
= true;
3393 // no recursive table, not with InsertFile in table or foot note
3398 m_aTableStack
.push(std::move(m_xTableDesc
));
3400 // #i33818# - determine absolute position object attributes,
3401 // if possible. It's needed for nested tables.
3402 std::unique_ptr
<WW8FlyPara
> pTableWFlyPara
;
3403 WW8SwFlyPara
* pTableSFlyPara( nullptr );
3404 // #i45301# - anchor nested table inside Writer fly frame
3405 // only at-character, if absolute position object attributes are available.
3406 // Thus, default anchor type is as-character anchored.
3407 RndStdIds
eAnchor( RndStdIds::FLY_AS_CHAR
);
3410 WW8_TablePos
* pNestedTabPos( nullptr );
3411 WW8_TablePos aNestedTabPos
;
3412 WW8PLCFxSave1 aSave
;
3413 m_xPlcxMan
->GetPap()->Save( aSave
);
3414 WW8PLCFx_Cp_FKP
* pPap
= m_xPlcxMan
->GetPapPLCF();
3415 WW8_CP nMyStartCp
= nStartCp
;
3416 if ( SearchRowEnd( pPap
, nMyStartCp
, m_nInTable
) &&
3417 ParseTabPos( &aNestedTabPos
, pPap
) )
3419 pNestedTabPos
= &aNestedTabPos
;
3421 m_xPlcxMan
->GetPap()->Restore( aSave
);
3422 if ( pNestedTabPos
)
3424 ApoTestResults aApo
= TestApo( m_nInTable
+ 1, false, pNestedTabPos
);
3425 pTableWFlyPara
= ConstructApo( aApo
, pNestedTabPos
);
3426 if ( pTableWFlyPara
)
3428 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3429 // containing WW8 page top margin.
3430 pTableSFlyPara
= new WW8SwFlyPara(*m_pPaM
, *this, *pTableWFlyPara
,
3431 m_aSectionManager
.GetWWPageTopMargin(),
3432 m_aSectionManager
.GetTextAreaWidth(),
3433 m_nIniFlyDx
, m_nIniFlyDy
);
3435 // #i45301# - anchor nested table Writer fly frame at-character
3436 eAnchor
= RndStdIds::FLY_AT_CHAR
;
3440 // if first paragraph in table has break-before-page, transfer that setting to the table itself.
3441 else if( StyleExists(m_nCurrentColl
) )
3443 const SwFormat
* pStyleFormat
= m_vColl
[m_nCurrentColl
].m_pFormat
;
3444 if( pStyleFormat
&& pStyleFormat
->GetBreak().GetBreak() == SvxBreak::PageBefore
)
3445 NewAttr( pStyleFormat
->GetBreak() );
3448 m_xTableDesc
.reset(new WW8TabDesc(this, nStartCp
));
3450 if( m_xTableDesc
->Ok() )
3452 int nNewInTable
= m_nInTable
+ 1;
3454 if ((eAnchor
== RndStdIds::FLY_AT_CHAR
)
3455 && !m_aTableStack
.empty() && !InEqualApo(nNewInTable
) )
3457 m_xTableDesc
->m_pParentPos
= new SwPosition(*m_pPaM
->GetPoint());
3458 SfxItemSetFixed
<RES_FRMATR_BEGIN
, RES_FRMATR_END
-1> aItemSet(m_rDoc
.GetAttrPool());
3459 // #i33818# - anchor the Writer fly frame for the nested table at-character.
3461 SwFormatAnchor
aAnchor( eAnchor
);
3462 aAnchor
.SetAnchor( m_xTableDesc
->m_pParentPos
);
3463 aItemSet
.Put( aAnchor
);
3464 m_xTableDesc
->m_pFlyFormat
= m_rDoc
.MakeFlySection( eAnchor
,
3465 m_xTableDesc
->m_pParentPos
, &aItemSet
);
3466 OSL_ENSURE( m_xTableDesc
->m_pFlyFormat
->GetAnchor().GetAnchorId() == eAnchor
,
3467 "Not the anchor type requested!" );
3468 MoveInsideFly(m_xTableDesc
->m_pFlyFormat
);
3470 m_xTableDesc
->CreateSwTable();
3471 if (m_xTableDesc
->m_pFlyFormat
)
3473 m_xTableDesc
->SetSizePosition(m_xTableDesc
->m_pFlyFormat
);
3474 // #i33818# - Use absolute position object attributes,
3475 // if existing, and apply them to the created Writer fly frame.
3476 if ( pTableWFlyPara
&& pTableSFlyPara
)
3478 WW8FlySet
aFlySet( *this, pTableWFlyPara
.get(), pTableSFlyPara
, false );
3479 SwFormatAnchor
aAnchor( RndStdIds::FLY_AT_CHAR
);
3480 aAnchor
.SetAnchor( m_xTableDesc
->m_pParentPos
);
3481 aFlySet
.Put( aAnchor
);
3482 m_xTableDesc
->m_pFlyFormat
->SetFormatAttr( aFlySet
);
3486 SwFormatHoriOrient aHori
=
3487 m_xTableDesc
->m_pTable
->GetFrameFormat()->GetHoriOrient();
3488 m_xTableDesc
->m_pFlyFormat
->SetFormatAttr(aHori
);
3489 m_xTableDesc
->m_pFlyFormat
->SetFormatAttr( SwFormatSurround( css::text::WrapTextMode_NONE
) );
3491 // #i33818# - The nested table doesn't have to leave
3492 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3493 m_xTableDesc
->m_pFlyFormat
->SetFormatAttr( SwFormatFollowTextFlow( true ) );
3496 m_xTableDesc
->SetSizePosition(nullptr);
3497 m_xTableDesc
->UseSwTable();
3503 delete pTableSFlyPara
;
3505 return m_xTableDesc
!= nullptr;
3508 void SwWW8ImplReader::TabCellEnd()
3510 if (m_nInTable
&& m_xTableDesc
)
3511 m_xTableDesc
->TableCellEnd();
3513 m_bFirstPara
= true; // We have come to the end of a cell so FirstPara flag
3514 m_bReadTable
= false;
3517 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
3519 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3520 m_bWasTabCellEnd
= true;
3523 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16
, const sal_uInt8
* pData
, short nLen
) // Sprm25
3525 if( ( nLen
> 0 ) && ( *pData
== 1 ) )
3526 m_bWasTabRowEnd
= true;
3529 void SwWW8ImplReader::PopTableDesc()
3531 if (m_xTableDesc
&& m_xTableDesc
->m_pFlyFormat
)
3533 MoveOutsideFly(m_xTableDesc
->m_pFlyFormat
, *m_xTableDesc
->m_pParentPos
);
3536 m_xTableDesc
.reset();
3537 if (!m_aTableStack
.empty())
3539 m_xTableDesc
= std::move(m_aTableStack
.top());
3540 m_aTableStack
.pop();
3544 void SwWW8ImplReader::StopTable()
3546 OSL_ENSURE(m_xTableDesc
, "Panic, stop table with no table!");
3550 // We are leaving a table so make sure the next paragraph doesn't think
3551 // it's the first paragraph
3552 m_bFirstPara
= false;
3554 m_xTableDesc
->FinishSwTable();
3557 m_bReadTable
= true;
3560 bool SwWW8ImplReader::IsInvalidOrToBeMergedTabCell() const
3565 const WW8_TCell
* pCell
= m_xTableDesc
->GetCurrentWWCell();
3567 return !m_xTableDesc
->IsValidCell( m_xTableDesc
->GetCurrentCol() )
3569 && ( !pCell
->bFirstMerged
3571 || ( pCell
->bVertMerge
3572 && !pCell
->bVertRestart
3579 sal_uInt16
SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex
) const
3581 sal_uInt16 nRes
= USHRT_MAX
;
3582 if( !m_vColl
.empty() )
3584 for(sal_uInt16 nI
= 0; nI
< m_xStyles
->GetCount(); nI
++ )
3585 if( m_vColl
[ nI
].m_bValid
3586 && (nLFOIndex
== m_vColl
[ nI
].m_nLFOIndex
) )
3592 const SwFormat
* SwWW8ImplReader::GetStyleWithOrgWWName( std::u16string_view rName
) const
3594 SwFormat
* pRet
= nullptr;
3595 if( !m_vColl
.empty() )
3597 for(sal_uInt16 nI
= 0; nI
< m_xStyles
->GetCount(); nI
++ )
3598 if( m_vColl
[ nI
].m_bValid
3599 && (rName
== m_vColl
[ nI
].GetOrgWWName()) )
3601 pRet
= m_vColl
[ nI
].m_pFormat
;
3609 SprmResult
WW8RStyle::HasParaSprm(sal_uInt16 nId
) const
3611 if( !mpParaSprms
|| !mnSprmsLen
)
3612 return SprmResult();
3614 return maSprmParser
.findSprmData(nId
, mpParaSprms
, mnSprmsLen
);
3617 void WW8RStyle::ImportSprms(sal_uInt8
*pSprms
, short nLen
, bool bPap
)
3624 mpParaSprms
= pSprms
; // for HasParaSprms()
3628 WW8SprmIter
aSprmIter(pSprms
, nLen
, maSprmParser
);
3629 while (const sal_uInt8
* pSprm
= aSprmIter
.GetSprms())
3631 #ifdef DEBUGSPRMREADER
3632 fprintf(stderr
, "id is %x\n", aIter
.GetCurrentId());
3634 mpIo
->ImportSprm(pSprm
, aSprmIter
.GetRemLen(), aSprmIter
.GetCurrentId());
3635 aSprmIter
.advance();
3638 mpParaSprms
= nullptr;
3642 void WW8RStyle::ImportSprms(std::size_t nPosFc
, short nLen
, bool bPap
)
3647 if (checkSeek(*mpStStrm
, nPosFc
))
3649 std::unique_ptr
<sal_uInt8
[]> pSprms( new sal_uInt8
[nLen
] );
3650 nLen
= mpStStrm
->ReadBytes(pSprms
.get(), nLen
);
3651 ImportSprms(pSprms
.get(), nLen
, bPap
);
3655 static short WW8SkipOdd(SvStream
* pSt
)
3657 if ( pSt
->Tell() & 0x1 )
3660 return pSt
->ReadBytes( &c
, 1 );
3665 static short WW8SkipEven(SvStream
* pSt
)
3667 if (!(pSt
->Tell() & 0x1))
3670 return pSt
->ReadBytes( &c
, 1 );
3675 short WW8RStyle::ImportUPX(short nLen
, bool bPAP
, bool bOdd
)
3677 if( 0 < nLen
) // Empty ?
3680 nLen
= nLen
- WW8SkipEven( mpStStrm
);
3682 nLen
= nLen
- WW8SkipOdd( mpStStrm
);
3685 mpStStrm
->ReadInt16( cbUPX
);
3690 cbUPX
= nLen
; // shrink cbUPX to nLen
3692 if( (1 < cbUPX
) || ( (0 < cbUPX
) && !bPAP
) )
3697 mpStStrm
->ReadUInt16( id
);
3705 sal_uInt64
const nPos
= mpStStrm
->Tell(); // if something is interpreted wrong,
3706 // this should make it work again
3707 ImportSprms( nPos
, cbUPX
, bPAP
);
3709 if ( mpStStrm
->Tell() != nPos
+ cbUPX
)
3710 mpStStrm
->Seek( nPos
+cbUPX
);
3712 nLen
= nLen
- cbUPX
;
3719 void WW8RStyle::ImportGrupx(short nLen
, bool bPara
, bool bOdd
)
3724 nLen
= nLen
- WW8SkipEven( mpStStrm
);
3726 nLen
= nLen
- WW8SkipOdd( mpStStrm
);
3728 if( bPara
) // Grupx.Papx
3729 nLen
= ImportUPX(nLen
, true, bOdd
);
3730 ImportUPX(nLen
, false, bOdd
); // Grupx.Chpx
3733 WW8RStyle::WW8RStyle(WW8Fib
& _rFib
, SwWW8ImplReader
* pI
)
3734 : WW8Style(*pI
->m_pTableStream
, _rFib
)
3735 , maSprmParser(_rFib
)
3737 , mpStStrm(pI
->m_pTableStream
)
3738 , mpStyRule(nullptr)
3739 , mpParaSprms(nullptr)
3742 , mbTextColChanged(false)
3743 , mbFontChanged(false)
3744 , mbCJKFontChanged(false)
3745 , mbCTLFontChanged(false)
3746 , mbFSizeChanged(false)
3747 , mbFCTLSizeChanged(false)
3748 , mbWidowsChanged(false)
3749 , mbBidiChanged(false)
3751 mpIo
->m_vColl
.resize(m_cstd
);
3754 void WW8RStyle::Set1StyleDefaults()
3756 // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3757 if (!mbCJKFontChanged
) // Style no CJK Font? set the default
3758 mpIo
->SetNewFontAttr(m_ftcFE
, true, RES_CHRATR_CJK_FONT
);
3760 if (!mbCTLFontChanged
) // Style no CTL Font? set the default
3761 mpIo
->SetNewFontAttr(m_ftcBi
, true, RES_CHRATR_CTL_FONT
);
3763 // western 2nd to make western charset conversion the default
3764 if (!mbFontChanged
) // Style has no Font? set the default,
3765 mpIo
->SetNewFontAttr(m_ftcAsci
, true, RES_CHRATR_FONT
);
3767 if( mpIo
->m_bNoAttrImport
)
3770 // Style has no text color set, winword default is auto
3771 if ( !mbTextColChanged
)
3772 mpIo
->m_pCurrentColl
->SetFormatAttr(SvxColorItem(COL_AUTO
, RES_CHRATR_COLOR
));
3774 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3775 if( !mbFSizeChanged
)
3777 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3778 mpIo
->m_pCurrentColl
->SetFormatAttr(aAttr
);
3779 aAttr
.SetWhich(RES_CHRATR_CJK_FONTSIZE
);
3780 mpIo
->m_pCurrentColl
->SetFormatAttr(aAttr
);
3783 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3784 if( !mbFCTLSizeChanged
)
3786 SvxFontHeightItem
aAttr(200, 100, RES_CHRATR_FONTSIZE
);
3787 aAttr
.SetWhich(RES_CHRATR_CTL_FONTSIZE
);
3788 mpIo
->m_pCurrentColl
->SetFormatAttr(aAttr
);
3791 if( !mbWidowsChanged
) // Widows ?
3793 mpIo
->m_pCurrentColl
->SetFormatAttr( SvxWidowsItem( 2, RES_PARATR_WIDOWS
) );
3794 mpIo
->m_pCurrentColl
->SetFormatAttr( SvxOrphansItem( 2, RES_PARATR_ORPHANS
) );
3797 // Word defaults to ltr, not inheriting from the environment like Writer. Regardless of
3798 // the page/sections rtl setting, the standard/no-inherit styles lack of rtl still means ltr
3799 if( !mbBidiChanged
) // likely, since no UI to change LTR except in default style
3801 mpIo
->m_pCurrentColl
->SetFormatAttr(
3802 SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB
, RES_FRAMEDIR
));
3806 bool WW8RStyle::PrepareStyle(SwWW8StyInf
&rSI
, ww::sti eSti
, sal_uInt16 nThisStyle
,
3807 sal_uInt16 nNextStyle
,
3808 std::map
<OUString
, sal_Int32
>& rParaCollisions
,
3809 std::map
<OUString
, sal_Int32
>& rCharCollisions
)
3817 sw::util::ParaStyleMapper::StyleResult aResult
=
3818 mpIo
->m_aParaStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
, rParaCollisions
);
3819 pColl
= aResult
.first
;
3820 bStyExist
= aResult
.second
;
3825 sw::util::CharStyleMapper::StyleResult aResult
=
3826 mpIo
->m_aCharStyleMapper
.GetStyle(rSI
.GetOrgWWName(), eSti
, rCharCollisions
);
3827 pColl
= aResult
.first
;
3828 bStyExist
= aResult
.second
;
3831 bool bImport
= !bStyExist
|| mpIo
->m_bNewDoc
; // import content ?
3833 // Do not override character styles the list import code created earlier.
3834 if (bImport
&& bStyExist
&& rSI
.GetOrgWWName().startsWith("WW8Num"))
3837 bool bOldNoImp
= mpIo
->m_bNoAttrImport
;
3838 rSI
.m_bImportSkipped
= !bImport
;
3841 mpIo
->m_bNoAttrImport
= true;
3846 pColl
->ResetAllFormatAttr(); // #i73790# - method renamed
3848 pColl
->SetAuto(false); // suggested by JP
3849 } // but changes the UI
3850 mpIo
->m_pCurrentColl
= pColl
;
3851 rSI
.m_pFormat
= pColl
; // remember translation WW->SW
3852 rSI
.m_bImportSkipped
= !bImport
;
3854 // Set Based on style
3855 sal_uInt16 j
= rSI
.m_nBase
;
3856 if (j
!= nThisStyle
&& j
< m_cstd
)
3858 SwWW8StyInf
* pj
= &mpIo
->m_vColl
[j
];
3859 if (rSI
.m_pFormat
&& pj
->m_pFormat
&& rSI
.m_bColl
== pj
->m_bColl
)
3861 rSI
.m_pFormat
->SetDerivedFrom( pj
->m_pFormat
); // ok, set Based on
3862 rSI
.m_eLTRFontSrcCharSet
= pj
->m_eLTRFontSrcCharSet
;
3863 rSI
.m_eRTLFontSrcCharSet
= pj
->m_eRTLFontSrcCharSet
;
3864 rSI
.m_eCJKFontSrcCharSet
= pj
->m_eCJKFontSrcCharSet
;
3865 rSI
.m_n81Flags
= pj
->m_n81Flags
;
3866 rSI
.m_n81BiDiFlags
= pj
->m_n81BiDiFlags
;
3867 if (!rSI
.IsWW8BuiltInHeadingStyle())
3869 rSI
.mnWW8OutlineLevel
= pj
->mnWW8OutlineLevel
;
3871 rSI
.m_bParaAutoBefore
= pj
->m_bParaAutoBefore
;
3872 rSI
.m_bParaAutoAfter
= pj
->m_bParaAutoAfter
;
3875 rSI
.m_xWWFly
= std::make_shared
<WW8FlyPara
>(mpIo
->m_bVer67
, pj
->m_xWWFly
.get());
3878 else if( mpIo
->m_bNewDoc
&& bStyExist
)
3879 rSI
.m_pFormat
->SetDerivedFrom();
3881 rSI
.m_nFollow
= nNextStyle
; // remember Follow
3883 mpStyRule
= nullptr; // recreate if necessary
3884 mbTextColChanged
= mbFontChanged
= mbCJKFontChanged
= mbCTLFontChanged
=
3885 mbFSizeChanged
= mbFCTLSizeChanged
= mbWidowsChanged
= false;
3886 mpIo
->SetNCurrentColl( nThisStyle
);
3887 mpIo
->m_bStyNormal
= nThisStyle
== 0;
3891 void WW8RStyle::PostStyle(SwWW8StyInf
const &rSI
, bool bOldNoImp
)
3893 // Reset attribute flags, because there are no style-ends.
3895 mpIo
->m_bHasBorder
= mpIo
->m_bSpec
= mpIo
->m_bObj
= mpIo
->m_bSymbol
= false;
3896 mpIo
->m_nCharFormat
= -1;
3898 // if style is based on nothing or base ignored
3899 if ((rSI
.m_nBase
>= m_cstd
|| mpIo
->m_vColl
[rSI
.m_nBase
].m_bImportSkipped
) && rSI
.m_bColl
)
3901 // If Char-Styles does not work
3902 // -> set hard WW-Defaults
3903 Set1StyleDefaults();
3906 mpStyRule
= nullptr; // to be on the safe side
3907 mpIo
->m_bStyNormal
= false;
3908 mpIo
->SetNCurrentColl( 0 );
3909 mpIo
->m_bNoAttrImport
= bOldNoImp
;
3910 // reset the list-remember-fields, if used when reading styles
3911 mpIo
->m_nLFOPosition
= USHRT_MAX
;
3912 mpIo
->m_nListLevel
= MAXLEVEL
;
3915 void WW8RStyle::Import1Style(sal_uInt16 nNr
,
3916 std::map
<OUString
, sal_Int32
>& rParaCollisions
,
3917 std::map
<OUString
, sal_Int32
>& rCharCollisions
)
3919 if (nNr
>= mpIo
->m_vColl
.size())
3922 SwWW8StyInf
&rSI
= mpIo
->m_vColl
[nNr
];
3924 if( rSI
.m_bImported
|| !rSI
.m_bValid
)
3927 rSI
.m_bImported
= true; // set flag now to avoid endless loops
3929 // valid and not NUL and not yet imported
3931 if( rSI
.m_nBase
< m_cstd
&& !mpIo
->m_vColl
[rSI
.m_nBase
].m_bImported
)
3932 Import1Style(rSI
.m_nBase
, rParaCollisions
, rCharCollisions
);
3934 mpStStrm
->Seek( rSI
.m_nFilePos
);
3939 std::unique_ptr
<WW8_STD
> xStd(Read1Style(nSkip
, &sName
)); // read Style
3942 rSI
.SetOrgWWIdent( sName
, xStd
->sti
);
3944 // either no Name or unused Slot or unknown Style
3946 if ( !xStd
|| sName
.isEmpty() || ((1 != xStd
->sgc
) && (2 != xStd
->sgc
)) )
3948 nSkip
= std::min
<sal_uInt64
>(nSkip
, mpStStrm
->remainingSize());
3949 mpStStrm
->Seek(mpStStrm
->Tell() + nSkip
);
3953 bool bOldNoImp
= PrepareStyle(rSI
, static_cast<ww::sti
>(xStd
->sti
),
3954 nNr
, xStd
->istdNext
,
3955 rParaCollisions
, rCharCollisions
);
3957 // if something is interpreted wrong, this should make it work again
3958 sal_uInt64 nPos
= mpStStrm
->Tell();
3960 //Variable parts of the STD start at even byte offsets, but "inside
3961 //the STD", which I take to meaning even in relation to the starting
3962 //position of the STD, which matches findings in #89439#, generally it
3963 //doesn't matter as the STSHI starts off nearly always on an even
3966 //Import of the Style Contents
3967 ImportGrupx(nSkip
, xStd
->sgc
== 1, rSI
.m_nFilePos
& 1);
3969 PostStyle(rSI
, bOldNoImp
);
3971 mpStStrm
->Seek( nPos
+nSkip
);
3974 void WW8RStyle::RecursiveReg(sal_uInt16 nNr
)
3976 if (nNr
>= mpIo
->m_vColl
.size())
3979 SwWW8StyInf
&rSI
= mpIo
->m_vColl
[nNr
];
3980 if( rSI
.m_bImported
|| !rSI
.m_bValid
)
3983 rSI
.m_bImported
= true;
3985 if( rSI
.m_nBase
< m_cstd
&& !mpIo
->m_vColl
[rSI
.m_nBase
].m_bImported
)
3986 RecursiveReg(rSI
.m_nBase
);
3988 mpIo
->RegisterNumFormatOnStyle(nNr
);
3993 After all styles are imported then we can recursively apply numbering
3994 styles to them, and change their tab stop settings if they turned out
3995 to have special first line indentation.
3997 void WW8RStyle::PostProcessStyles()
4001 Clear all imported flags so that we can recursively apply numbering
4002 formats and use it to mark handled ones
4004 for (i
=0; i
< m_cstd
; ++i
)
4005 mpIo
->m_vColl
[i
].m_bImported
= false;
4008 Register the num formats and tabstop changes on the styles recursively.
4012 In the same loop apply the tabstop changes required because we need to
4013 change their location if there's a special indentation for the first line,
4014 By avoiding making use of each styles margins during reading of their
4015 tabstops we don't get problems with doubly adjusting tabstops that
4018 for (i
=0; i
< m_cstd
; ++i
)
4020 if (mpIo
->m_vColl
[i
].m_bValid
)
4027 void WW8RStyle::ScanStyles() // investigate style dependencies
4028 { // and detect Filepos for each Style
4029 for (sal_uInt16 i
= 0; i
< m_cstd
; ++i
)
4031 SwWW8StyInf
&rSI
= mpIo
->m_vColl
[i
];
4033 rSI
.m_nFilePos
= mpStStrm
->Tell(); // remember FilePos
4035 std::unique_ptr
<WW8_STD
> xStd(Read1Style(nSkip
, nullptr)); // read STD
4036 rSI
.m_bValid
= xStd
!= nullptr;
4039 rSI
.m_nBase
= xStd
->istdBase
; // remember Basis
4040 rSI
.m_bColl
= xStd
->sgc
== 1; // Para-Style
4043 rSI
= SwWW8StyInf();
4046 nSkip
= std::min
<sal_uInt64
>(nSkip
, mpStStrm
->remainingSize());
4047 mpStStrm
->Seek(mpStStrm
->Tell() + nSkip
); // skip Names and Sprms
4051 std::vector
<sal_uInt8
> ChpxToSprms(const Word2CHPX
&rChpx
)
4053 std::vector
<sal_uInt8
> aRet
4056 static_cast< sal_uInt8
>(128 + rChpx
.fBold
),
4059 static_cast< sal_uInt8
>(128 + rChpx
.fItalic
),
4062 static_cast< sal_uInt8
>(128 + rChpx
.fStrike
),
4065 static_cast< sal_uInt8
>(128 + rChpx
.fOutline
),
4068 static_cast< sal_uInt8
>(128 + rChpx
.fSmallCaps
),
4071 static_cast< sal_uInt8
>(128 + rChpx
.fCaps
),
4074 static_cast< sal_uInt8
>(128 + rChpx
.fVanish
)
4080 ShortToSVBT16(rChpx
.ftc
, a
);
4081 aRet
.push_back(a
[1]);
4082 aRet
.push_back(a
[0]);
4088 aRet
.push_back(rChpx
.kul
);
4095 ShortToSVBT16(rChpx
.lid
, a
);
4096 aRet
.push_back(a
[1]);
4097 aRet
.push_back(a
[0]);
4103 aRet
.push_back(rChpx
.ico
);
4111 ShortToSVBT16(rChpx
.hps
, a
);
4112 aRet
.push_back(a
[0]);
4118 aRet
.push_back(rChpx
.hpsPos
);
4122 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fBoldBi
) );
4125 aRet
.push_back( static_cast< sal_uInt8
>(128 + rChpx
.fItalicBi
) );
4131 ShortToSVBT16(rChpx
.fsFtcBi
, a
);
4132 aRet
.push_back(a
[1]);
4133 aRet
.push_back(a
[0]);
4140 ShortToSVBT16(rChpx
.lidBi
, a
);
4141 aRet
.push_back(a
[1]);
4142 aRet
.push_back(a
[0]);
4148 aRet
.push_back(rChpx
.icoBi
);
4155 ShortToSVBT16(rChpx
.hpsBi
, a
);
4156 aRet
.push_back(a
[1]);
4157 aRet
.push_back(a
[0]);
4163 Word2CHPX
ReadWord2Chpx(SvStream
&rSt
, std::size_t nOffset
, sal_uInt8 nSize
)
4167 if (!nSize
|| !checkSeek(rSt
, nOffset
))
4170 const size_t nMaxByteCount
= rSt
.remainingSize();
4174 if (nSize
> nMaxByteCount
)
4176 SAL_WARN("sw.ww8", "ReadWord2Chpx: truncating out of range "
4177 << nSize
<< " to " << nMaxByteCount
);
4178 nSize
= nMaxByteCount
;
4186 rSt
.ReadUChar( nFlags8
);
4192 aChpx
.fBold
= nFlags8
& 0x01;
4193 aChpx
.fItalic
= (nFlags8
& 0x02) >> 1;
4194 aChpx
.fRMarkDel
= (nFlags8
& 0x04) >> 2;
4195 aChpx
.fOutline
= (nFlags8
& 0x08) >> 3;
4196 aChpx
.fFieldVanish
= (nFlags8
& 0x10) >> 4;
4197 aChpx
.fSmallCaps
= (nFlags8
& 0x20) >> 5;
4198 aChpx
.fCaps
= (nFlags8
& 0x40) >> 6;
4199 aChpx
.fVanish
= (nFlags8
& 0x80) >> 7;
4201 if (nCount
>= nSize
) break;
4202 rSt
.ReadUChar( nFlags8
);
4208 aChpx
.fRMark
= nFlags8
& 0x01;
4209 aChpx
.fSpec
= (nFlags8
& 0x02) >> 1;
4210 aChpx
.fStrike
= (nFlags8
& 0x04) >> 2;
4211 aChpx
.fObj
= (nFlags8
& 0x08) >> 3;
4212 aChpx
.fBoldBi
= (nFlags8
& 0x10) >> 4;
4213 aChpx
.fItalicBi
= (nFlags8
& 0x20) >> 5;
4214 aChpx
.fBiDi
= (nFlags8
& 0x40) >> 6;
4215 aChpx
.fDiacUSico
= (nFlags8
& 0x80) >> 7;
4217 if (nCount
>= nSize
) break;
4218 rSt
.ReadUChar( nFlags8
);
4224 aChpx
.fsIco
= nFlags8
& 0x01;
4225 aChpx
.fsFtc
= (nFlags8
& 0x02) >> 1;
4226 aChpx
.fsHps
= (nFlags8
& 0x04) >> 2;
4227 aChpx
.fsKul
= (nFlags8
& 0x08) >> 3;
4228 aChpx
.fsPos
= (nFlags8
& 0x10) >> 4;
4229 aChpx
.fsSpace
= (nFlags8
& 0x20) >> 5;
4230 aChpx
.fsLid
= (nFlags8
& 0x40) >> 6;
4231 aChpx
.fsIcoBi
= (nFlags8
& 0x80) >> 7;
4233 if (nCount
>= nSize
) break;
4234 rSt
.ReadUChar( nFlags8
);
4240 aChpx
.fsFtcBi
= nFlags8
& 0x01;
4241 aChpx
.fsHpsBi
= (nFlags8
& 0x02) >> 1;
4242 aChpx
.fsLidBi
= (nFlags8
& 0x04) >> 2;
4244 if (nCount
>= nSize
) break;
4245 rSt
.ReadUInt16( aChpx
.ftc
);
4248 if (nCount
>= nSize
) break;
4249 rSt
.ReadUInt16( aChpx
.hps
);
4252 if (nCount
>= nSize
) break;
4253 rSt
.ReadUChar( nFlags8
);
4259 aChpx
.qpsSpace
= nFlags8
& 0x3F;
4260 aChpx
.fSysVanish
= (nFlags8
& 0x40) >> 6;
4261 aChpx
.fNumRun
= (nFlags8
& 0x80) >> 7;
4263 if (nCount
>= nSize
) break;
4264 rSt
.ReadUChar( nFlags8
);
4270 aChpx
.ico
= nFlags8
& 0x1F;
4271 aChpx
.kul
= (nFlags8
& 0xE0) >> 5;
4273 if (nCount
>= nSize
) break;
4274 rSt
.ReadUChar( aChpx
.hpsPos
);
4277 if (nCount
>= nSize
) break;
4278 rSt
.ReadUChar( aChpx
.icoBi
);
4281 if (nCount
>= nSize
) break;
4282 rSt
.ReadUInt16( aChpx
.lid
);
4285 if (nCount
>= nSize
) break;
4286 rSt
.ReadUInt16( aChpx
.ftcBi
);
4289 if (nCount
>= nSize
) break;
4290 rSt
.ReadUInt16( aChpx
.hpsBi
);
4293 if (nCount
>= nSize
) break;
4294 rSt
.ReadUInt16( aChpx
.lidBi
);
4297 if (nCount
>= nSize
) break;
4298 rSt
.ReadUInt32( aChpx
.fcPic
);
4304 rSt
.SeekRel(nSize
-nCount
);
4310 struct pxoffset
{ std::size_t mnOffset
; sal_uInt8 mnSize
; };
4313 void WW8RStyle::ImportOldFormatStyles()
4315 for (sal_uInt16 i
=0; i
< m_cstd
; ++i
)
4317 mpIo
->m_vColl
[i
].m_bColl
= true;
4318 //every chain must end eventually at the null style (style code 222)
4319 mpIo
->m_vColl
[i
].m_nBase
= 222;
4322 rtl_TextEncoding eStructChrSet
= WW8Fib::GetFIBCharset(
4323 mpIo
->m_xWwFib
->m_chseTables
, mpIo
->m_xWwFib
->m_lid
);
4325 sal_uInt16
cstcStd(0);
4326 m_rStream
.ReadUInt16( cstcStd
);
4328 size_t nMaxByteCount
= m_rStream
.remainingSize();
4329 sal_uInt16
cbName(0);
4330 m_rStream
.ReadUInt16(cbName
);
4331 if (cbName
> nMaxByteCount
)
4333 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4334 << cbName
<< " to " << nMaxByteCount
);
4335 cbName
= nMaxByteCount
;
4337 sal_uInt16 nByteCount
= 2;
4339 while (nByteCount
< cbName
)
4341 sal_uInt8
nCount(0);
4342 m_rStream
.ReadUChar( nCount
);
4345 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4346 if (stc
>=mpIo
->m_vColl
.size())
4349 SwWW8StyInf
&rSI
= mpIo
->m_vColl
[stc
];
4352 if (nCount
!= 0xFF) // undefined style
4354 if (nCount
!= 0) // user style
4356 OString aTmp
= read_uInt8s_ToOString(m_rStream
, nCount
);
4357 nByteCount
+= aTmp
.getLength();
4358 sName
= OStringToOUString(aTmp
, eStructChrSet
);
4360 rSI
.m_bImported
= true;
4363 if (sName
.isEmpty())
4365 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4366 if (const char *pStr
= GetEnglishNameFromSti(eSti
))
4367 sName
= OUString(pStr
, strlen(pStr
), RTL_TEXTENCODING_ASCII_US
);
4370 if (sName
.isEmpty())
4371 sName
= "Unknown Style: " + OUString::number(stc
);
4373 rSI
.SetOrgWWIdent(sName
, stc
);
4377 sal_uInt16 nStyles
=stcp
;
4379 std::vector
<pxoffset
> aCHPXOffsets(stcp
);
4380 nMaxByteCount
= m_rStream
.remainingSize();
4381 sal_uInt16
cbChpx(0);
4382 m_rStream
.ReadUInt16(cbChpx
);
4383 if (cbChpx
> nMaxByteCount
)
4385 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4386 << cbChpx
<< " to " << nMaxByteCount
);
4387 cbChpx
= nMaxByteCount
;
4391 std::vector
< std::vector
<sal_uInt8
> > aConvertedChpx
;
4392 while (nByteCount
< cbChpx
)
4394 if (stcp
== aCHPXOffsets
.size())
4396 //more data than style slots, skip remainder
4397 m_rStream
.SeekRel(cbChpx
-nByteCount
);
4402 m_rStream
.ReadUChar( cb
);
4405 aCHPXOffsets
[stcp
].mnSize
= 0;
4409 sal_uInt8 nRemainder
= cb
;
4411 aCHPXOffsets
[stcp
].mnOffset
= m_rStream
.Tell();
4412 aCHPXOffsets
[stcp
].mnSize
= nRemainder
;
4414 Word2CHPX aChpx
= ReadWord2Chpx(m_rStream
, aCHPXOffsets
[stcp
].mnOffset
,
4415 aCHPXOffsets
[stcp
].mnSize
);
4416 aConvertedChpx
.push_back( ChpxToSprms(aChpx
) );
4418 nByteCount
+= nRemainder
;
4421 aConvertedChpx
.emplace_back( );
4426 std::vector
<pxoffset
> aPAPXOffsets(stcp
);
4427 nMaxByteCount
= m_rStream
.remainingSize();
4428 sal_uInt16
cbPapx(0);
4429 m_rStream
.ReadUInt16(cbPapx
);
4430 if (cbPapx
> nMaxByteCount
)
4432 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4433 << cbPapx
<< " to " << nMaxByteCount
);
4434 cbPapx
= nMaxByteCount
;
4438 while (nByteCount
< cbPapx
)
4440 if (stcp
== aPAPXOffsets
.size())
4442 m_rStream
.SeekRel(cbPapx
-nByteCount
);
4447 m_rStream
.ReadUChar( cb
);
4450 aPAPXOffsets
[stcp
].mnSize
= 0;
4455 m_rStream
.ReadUChar( stc2
);
4456 m_rStream
.SeekRel(6);
4458 sal_uInt8 nRemainder
= cb
-7;
4460 aPAPXOffsets
[stcp
].mnOffset
= m_rStream
.Tell();
4461 aPAPXOffsets
[stcp
].mnSize
= nRemainder
;
4463 m_rStream
.SeekRel(nRemainder
);
4464 nByteCount
+= nRemainder
;
4471 m_rStream
.ReadUInt16( iMac
);
4473 if (iMac
> nStyles
) iMac
= nStyles
;
4475 std::map
<OUString
, sal_Int32
> aParaCollisions
;
4476 std::map
<OUString
, sal_Int32
> aCharCollisions
;
4478 for (stcp
= 0; stcp
< iMac
; ++stcp
)
4480 sal_uInt8
stcNext(0), stcBase(0);
4481 m_rStream
.ReadUChar( stcNext
);
4482 m_rStream
.ReadUChar( stcBase
);
4484 sal_uInt8 stc
= static_cast< sal_uInt8
>((stcp
- cstcStd
) & 255);
4487 #i64557# style based on itself
4488 every chain must end eventually at the null style (style code 222)
4493 SwWW8StyInf
&rSI
= mpIo
->m_vColl
[stc
];
4494 rSI
.m_nBase
= stcBase
;
4496 ww::sti eSti
= ww::GetCanonicalStiFromStc(stc
);
4498 if (eSti
== ww::stiNil
)
4501 if (stcp
>= aPAPXOffsets
.size())
4504 rSI
.m_bValid
= true;
4506 if (ww::StandardStiIsCharStyle(eSti
) && !aPAPXOffsets
[stcp
].mnSize
)
4507 mpIo
->m_vColl
[stc
].m_bColl
= false;
4509 bool bOldNoImp
= PrepareStyle(rSI
, eSti
, stc
, stcNext
,
4513 ImportSprms(aPAPXOffsets
[stcp
].mnOffset
, aPAPXOffsets
[stcp
].mnSize
,
4516 if (!aConvertedChpx
[stcp
].empty())
4517 ImportSprms(aConvertedChpx
[stcp
].data(),
4518 static_cast< short >(aConvertedChpx
[stcp
].size()),
4521 PostStyle(rSI
, bOldNoImp
);
4525 void WW8RStyle::ImportNewFormatStyles()
4527 ScanStyles(); // Scan Based On
4529 std::map
<OUString
, sal_Int32
> aParaCollisions
;
4530 std::map
<OUString
, sal_Int32
> aCharCollisions
;
4532 for (sal_uInt16 i
= 0; i
< m_cstd
; ++i
) // import Styles
4533 if (mpIo
->m_vColl
[i
].m_bValid
)
4534 Import1Style(i
, aParaCollisions
, aCharCollisions
);
4537 void WW8RStyle::Import()
4539 mpIo
->m_pDfltTextFormatColl
= mpIo
->m_rDoc
.GetDfltTextFormatColl();
4540 mpIo
->m_pStandardFormatColl
=
4541 mpIo
->m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
, false);
4543 if( mpIo
->m_nIniFlags
& WW8FL_NO_STYLES
)
4546 if (mpIo
->m_xWwFib
->GetFIBVersion() <= ww::eWW2
)
4547 ImportOldFormatStyles();
4549 ImportNewFormatStyles();
4551 for (sal_uInt16 i
= 0; i
< m_cstd
; ++i
)
4554 SwWW8StyInf
* pi
= &mpIo
->m_vColl
[i
];
4555 sal_uInt16 j
= pi
->m_nFollow
;
4558 SwWW8StyInf
* pj
= &mpIo
->m_vColl
[j
];
4559 if ( j
!= i
// rational Index ?
4560 && pi
->m_pFormat
// Format ok ?
4561 && pj
->m_pFormat
// Derived-Format ok ?
4562 && pi
->m_bColl
// only possible for paragraph templates (WW)
4563 && pj
->m_bColl
){ // identical Type ?
4564 static_cast<SwTextFormatColl
*>(pi
->m_pFormat
)->SetNextTextFormatColl(
4565 *static_cast<SwTextFormatColl
*>(pj
->m_pFormat
) ); // ok, register
4570 // Missing special handling for default character template
4571 // "Absatz-Standardschriftart" ( Style-ID 65 ).
4572 // That is empty by default ( WW6 dt and US ) and not changeable
4573 // via WW-UI so this does not matter.
4574 // This could be done by:
4575 // if( bNew ) rDoc.SetDefault( pDefCharFormat->GetAttrSet() );
4577 // for e.g. tables an always valid Std-Style is necessary
4579 if( mpIo
->StyleExists(0) && !mpIo
->m_vColl
.empty() &&
4580 mpIo
->m_vColl
[0].m_pFormat
&& mpIo
->m_vColl
[0].m_bColl
&& mpIo
->m_vColl
[0].m_bValid
)
4581 mpIo
->m_pDfltTextFormatColl
= static_cast<SwTextFormatColl
*>(mpIo
->m_vColl
[0].m_pFormat
);
4583 mpIo
->m_pDfltTextFormatColl
= mpIo
->m_rDoc
.GetDfltTextFormatColl();
4585 // set Hyphenation flag on BASIC para-style
4586 if (mpIo
->m_bNewDoc
&& mpIo
->m_pStandardFormatColl
)
4588 if (mpIo
->m_xWDop
->fAutoHyphen
4589 && SfxItemState::SET
!= mpIo
->m_pStandardFormatColl
->GetItemState(
4590 RES_PARATR_HYPHENZONE
, false) )
4592 SvxHyphenZoneItem
aAttr(true, RES_PARATR_HYPHENZONE
);
4593 aAttr
.GetMinLead() = 2;
4594 aAttr
.GetMinTrail() = 2;
4595 aAttr
.GetMaxHyphens() = 0;
4597 mpIo
->m_pStandardFormatColl
->SetFormatAttr( aAttr
);
4601 // we do not read styles anymore:
4602 mpIo
->m_pCurrentColl
= nullptr;
4605 rtl_TextEncoding
SwWW8StyInf::GetCharSet() const
4607 if (m_pFormat
&& (m_pFormat
->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_RL_TB
))
4608 return m_eRTLFontSrcCharSet
;
4609 return m_eLTRFontSrcCharSet
;
4612 rtl_TextEncoding
SwWW8StyInf::GetCJKCharSet() const
4614 if (m_pFormat
&& (m_pFormat
->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_RL_TB
))
4615 return m_eRTLFontSrcCharSet
;
4616 return m_eCJKFontSrcCharSet
;
4619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */