LibreOffice Module sw (master) 1
ww8par2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21#include <sal/log.hxx>
22
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>
39#include <editeng/pgrditem.hxx>
40#include <msfilter.hxx>
41#include <pam.hxx>
42#include <deletelistener.hxx>
43#include <doc.hxx>
45#include <docary.hxx>
46#include <ndtxt.hxx>
47#include <paratr.hxx>
48#include <poolfmt.hxx>
49#include <swtable.hxx>
50#include <tblsel.hxx>
51#include <mdiexp.hxx>
52#include <txtftn.hxx>
53#include <frmfmt.hxx>
54#include <ftnidx.hxx>
55#include <fmtftn.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"
65#include "ww8par.hxx"
66#include "ww8par2.hxx"
67
68#include <frmatr.hxx>
69#include <itabenum.hxx>
70#include <unocrsr.hxx>
71
72#include <iostream>
73#include <memory>
74
75using namespace ::com::sun::star;
76
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{}
83{
84 for (sal_uInt16 & rn : maDirections)
85 rn = 4;
86}
87
89{
90 delete[] pTCs;
91 delete[] pSHDs;
92 delete[] pNewSHDs;
93}
94
96 RedlineType eType, WW8TabDesc* pTabDesc )
97{
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 ) )
101 {
102 if( pTabDesc && pTabDesc->getOldRedlineStack() )
103 {
104 bool const bResult =
105 pTabDesc->getOldRedlineStack()->close(rPos, eType);
106 OSL_ENSURE( bResult, "close without open!");
107 }
108 }
109}
110
112{
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;
117}
118
119void wwSectionManager::SetCurrentSectionVerticalAdjustment(const drawing::TextVerticalAdjust nVA)
120{
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;
125}
126
128{
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();
133 return false;
134}
135
137{
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());
142 return false;
143}
144
146{
147 return !maSegments.empty() ? maSegments.back().m_nPgLeft : 0;
148}
149
151{
152 return !maSegments.empty() ? maSegments.back().m_nPgRight : 0;
153}
154
156{
157 return !maSegments.empty() ? maSegments.back().GetPageWidth() : 0;
158}
159
161{
162 return !maSegments.empty() ? maSegments.back().GetTextAreaWidth() : 0;
163}
164
166{
167 return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
168}
169
171{
172 /*
173 Ignoring Footnote outside of the normal Text. People will put footnotes
174 into field results and field commands.
175 */
176 if (m_bIgnoreText ||
177 m_pPaM->GetPoint()->GetNode() < m_rDoc.GetNodes().GetEndOfExtras())
178 {
179 return 0;
180 }
181
182 OSL_ENSURE(!m_aFootnoteStack.empty(), "footnote end without start");
183 if (m_aFootnoteStack.empty())
184 return 0;
185
186 bool bFtEdOk = false;
187 const FootnoteDescriptor &rDesc = m_aFootnoteStack.back();
188
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();
193
194 OUString sChar;
195 SwTextFootnote* pFN = nullptr;
196 //There should have been a footnote char, we will replace this.
197 if (pText && nPos)
198 {
199 sChar += OUStringChar(pText->GetText()[--nPos]);
200 m_pPaM->SetMark();
201 m_pPaM->GetMark()->AdjustContent(-1);
202 std::shared_ptr<SwUnoCursor> xLastAnchorCursor(m_oLastAnchorPos ? m_rDoc.CreateUnoCursor(*m_oLastAnchorPos) : nullptr);
203 m_oLastAnchorPos.reset();
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));
210 }
211 OSL_ENSURE(pFN, "Problems creating the footnote text");
212 if (pFN)
213 {
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;
218
219 const SwNodeIndex* pSttIdx = pFN->GetStartNode();
220 assert(pSttIdx && "Problems creating footnote text");
221
223
224 bool bOld = m_bFootnoteEdn;
225 m_bFootnoteEdn = true;
226
227 SwFormatFootnote& rFormatFootnote = static_cast<SwFormatFootnote&>(pFN->GetAttr());
228
229 SvtDeleteListener aDeleteListener(rFormatFootnote.GetNotifier());
230
231 // read content of Ft-/End-Note
232 Read_HdFtFootnoteText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, rDesc.meType);
233
234 m_bFootnoteEdn = bOld;
235
236 SAL_WARN_IF(aDeleteListener.WasDeleted(), "sw.ww8", "Footnode deleted during its import");
237 if (!aDeleteListener.WasDeleted())
238 {
239 bFtEdOk = true;
240
241 OSL_ENSURE(sChar.getLength()==1 && ((rDesc.mbAutoNum == (sChar[0] == 2))),
242 "footnote autonumbering must be 0x02, and everything else must not be");
243
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);
248
249 /*
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.
252 #i14737#
253 */
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())
258 {
259 const OUString &rText = pTNd->GetText();
260 if (rText[0] == sChar[0])
261 {
262 // Allow MSO to emulate LO footnote text starting at left margin - only meaningful with hanging indent
263 sal_Int32 nFirstLineIndent=0;
265 if ( pTNd->GetAttr(aSet) )
266 {
267 const SvxLRSpaceItem* pLRSpace = aSet.GetItem<SvxLRSpaceItem>(RES_LR_SPACE);
268 if ( pLRSpace )
269 nFirstLineIndent = pLRSpace->GetTextFirstLineOffset();
270 }
271
272 rPaMPointPos.SetContent(0);
273 m_pPaM->SetMark();
274 // Strip out aesthetic tabs we may have inserted on export #i24762#
275 if (nFirstLineIndent < 0 && rText.getLength() > 1 && rText[1] == 0x09)
276 m_pPaM->GetMark()->AdjustContent(1);
277 m_pPaM->GetMark()->AdjustContent(1);
278 m_xReffingStck->Delete(*m_pPaM);
280 m_pPaM->DeleteMark();
281 }
282 }
283 }
284
285 *m_pPaM->GetPoint() = aTmpPos; // restore Cursor
286
287 m_xPlcxMan = xOldPlcxMan; // Restore attributes
288 m_xPlcxMan->RestoreAllPLCFx( aSave );
289 }
290
291 if (bFtEdOk)
292 m_aSectionManager.SetCurrentSectionHasFootnote();
293
294 m_aFootnoteStack.pop_back();
295 return 0;
296}
297
299{
300 /*
301 Ignoring Footnote outside of the normal Text. People will put footnotes
302 into field results and field commands.
303 */
304 if (m_bIgnoreText ||
305 m_pPaM->GetPoint()->GetNode() < m_rDoc.GetNodes().GetEndOfExtras())
306 {
307 return 0;
308 }
309
310 FootnoteDescriptor aDesc;
311 aDesc.mbAutoNum = true;
312 if (eEDN == pRes->nSprmId)
313 {
314 aDesc.meType = MAN_EDN;
315 WW8PLCFx_SubDoc* pEndNote = m_xPlcxMan->GetEdn();
316 if (const void* pData = pEndNote ? pEndNote->GetData() : nullptr)
317 aDesc.mbAutoNum = 0 != *static_cast<short const*>(pData);
318 }
319 else
320 {
321 aDesc.meType = MAN_FTN;
322 WW8PLCFx_SubDoc* pFootNote = m_xPlcxMan->GetFootnote();
323 if (const void* pData = pFootNote ? pFootNote->GetData() : nullptr)
324 aDesc.mbAutoNum = 0 != *static_cast<short const*>(pData);
325 }
326
327 aDesc.mnStartCp = pRes->nCp2OrIdx;
328 aDesc.mnLen = pRes->nMemLen;
329
330 m_aFootnoteStack.push_back(aDesc);
331
332 return 0;
333}
334
336 int nLevel) const
337{
338 WW8PLCFxDesc aRes;
339 aRes.pMemPos = nullptr;
340 aRes.nEndPos = rStartCp;
341 std::set<std::pair<WW8_CP, WW8_CP>> aPrevRes;
342
343 while (pPap->HasFkp() && rStartCp != WW8_CP_MAX)
344 {
345 if (pPap->Where() != WW8_CP_MAX)
346 {
347 SprmResult aSprmRes = pPap->HasSprm(TabRowSprm(nLevel));
348 const sal_uInt8* pB = aSprmRes.pSprm;
349 if (pB && aSprmRes.nRemainingData >= 1 && *pB == 1)
350 {
351 aSprmRes = pPap->HasSprm(0x6649);
352 const sal_uInt8 *pLevel = aSprmRes.pSprm;
353 if (pLevel && aSprmRes.nRemainingData >= 1)
354 {
355 if (nLevel + 1 == *pLevel)
356 return true;
357 }
358 else
359 {
360 OSL_ENSURE(!nLevel || pLevel, "sublevel without level sprm");
361 return true; // RowEnd found
362 }
363 }
364 }
365
366 aRes.nStartPos = aRes.nEndPos;
367 aRes.pMemPos = nullptr;
368 //Seek to our next block of properties
369 if (!(pPap->SeekPos(aRes.nStartPos)))
370 {
371 aRes.nEndPos = WW8_CP_MAX;
372 pPap->SetDirty(true);
373 }
374 pPap->GetSprms(&aRes);
375 pPap->SetDirty(false);
376 auto aBounds(std::make_pair(aRes.nStartPos, aRes.nEndPos));
377 if (!aPrevRes.insert(aBounds).second) //already seen these bounds, infinite loop
378 {
379 SAL_WARN("sw.ww8", "SearchRowEnd, loop in paragraph property chain");
380 break;
381 }
382 //Update our aRes to get the new starting point of the next properties
383 rStartCp = aRes.nEndPos;
384 }
385
386 return false;
387}
388
390{
391 if (m_bVer67)
392 // The below SPRM is for WW8 only.
393 return false;
394
395 WW8PLCFxDesc aRes;
396 aRes.pMemPos = nullptr;
397 aRes.nEndPos = pPap->Where();
398 std::set<std::pair<WW8_CP, WW8_CP>> aPrevRes;
399
400 while (pPap->HasFkp() && pPap->Where() != WW8_CP_MAX)
401 {
402 // See if the current pap is outside the table.
404 const sal_uInt8* pB = aSprmRes.pSprm;
405 if (!pB || aSprmRes.nRemainingData < 1 || *pB != 1)
406 // Yes, this is the position after the end of the table.
407 return true;
408
409 // It is, so seek to the next pap.
410 aRes.nStartPos = aRes.nEndPos;
411 aRes.pMemPos = nullptr;
412 if (!pPap->SeekPos(aRes.nStartPos))
413 return false;
414
415 // Read the sprms and make sure we moved forward to avoid infinite loops.
416 pPap->GetSprms(&aRes);
417 auto aBounds(std::make_pair(aRes.nStartPos, aRes.nEndPos));
418 if (!aPrevRes.insert(aBounds).second) //already seen these bounds, infinite loop
419 {
420 SAL_WARN("sw.ww8", "SearchTableEnd, loop in paragraph property chain");
421 break;
422 }
423 }
424
425 return false;
426}
427
428ApoTestResults SwWW8ImplReader::TestApo(int nCellLevel, bool bTableRowEnd,
429 const WW8_TablePos *pTabPos)
430{
431 const WW8_TablePos *pTopLevelTable = nCellLevel <= 1 ? pTabPos : nullptr;
432 ApoTestResults aRet;
433 // Frame in Style Definition (word appears to ignore them if inside an
434 // text autoshape)
435 sal_uInt16 const nStyle(m_xPlcxMan->GetColl());
436 if (!m_bTxbxFlySection && nStyle < m_vColl.size())
437 aRet.mpStyleApo = StyleExists(nStyle) ? m_vColl[nStyle].m_xWWFly.get() : nullptr;
438
439 /*
440 #i1140#
441 If I have a table and apply a style to one of its frames that should cause
442 a paragraph that it is applied to it to only exist as a separate floating
443 frame, then the behaviour depends on which cell that it has been applied
444 to. If it is the first cell of a row then the whole table row jumps into the
445 new frame, if it isn't then the paragraph attributes are applied
446 "except" for the floating frame stuff. i.e. it's ignored. So if there's a
447 table, and we're not in the first cell then we ignore the fact that the
448 paragraph style wants to be in a different frame.
449
450 This sort of mindbending inconsistency is surely why frames are deprecated
451 in word 97 onwards and hidden away from the user
452
453 #i1532# & #i5379#
454 If we are already a table in a frame then we must grab the para properties
455 to see if we are still in that frame.
456 */
457
458 aRet.m_bHasSprm37 = m_xPlcxMan->HasParaSprm(m_bVer67 ? 37 : 0x2423).pSprm != nullptr;
459 SprmResult aSrpm29 = m_xPlcxMan->HasParaSprm(m_bVer67 ? 29 : 0x261B);
460 const sal_uInt8 *pSrpm29 = aSrpm29.pSprm;
461 aRet.m_bHasSprm29 = pSrpm29 != nullptr;
462 aRet.m_nSprm29 = (pSrpm29 && aSrpm29.nRemainingData >= 1) ? *pSrpm29 : 0;
463
464 // Is there some frame data here
465 bool bNowApo = aRet.HasFrame() || pTopLevelTable;
466 if (bNowApo)
467 {
468 if (!ConstructApo(aRet, pTabPos))
469 bNowApo = false;
470 }
471
472 bool bTestAllowed = !m_bTxbxFlySection && !bTableRowEnd;
473 if (bTestAllowed)
474 {
475 //Test is allowed if there is no table.
476 //Otherwise only allowed if we are in the
477 //first paragraph of the first cell of a row.
478 //(And only if the row we are inside is at the
479 //same level as the previous row, think tables
480 //in tables)
481 if (nCellLevel == m_nInTable)
482 {
483
484 if (!m_nInTable)
485 bTestAllowed = true;
486 else
487 {
488 if (!m_xTableDesc)
489 {
490 OSL_ENSURE(m_xTableDesc, "What!");
491 bTestAllowed = false;
492 }
493 else
494 {
495 // #i39468#
496 // If current cell isn't valid, the test is allowed.
497 // The cell isn't valid, if e.g. there is a new row
498 // <pTableDesc->nCurrentRow> >= <pTableDesc->pTabLines->Count()>
499 bTestAllowed =
500 m_xTableDesc->GetCurrentCol() == 0 &&
501 ( !m_xTableDesc->IsValidCell( m_xTableDesc->GetCurrentCol() ) ||
502 m_xTableDesc->InFirstParaInCell() );
503 }
504 }
505 }
506 }
507
508 if (!bTestAllowed)
509 return aRet;
510
511 aRet.mbStartApo = bNowApo && !InEqualOrHigherApo(1); // APO-start
512 aRet.mbStopApo = InEqualOrHigherApo(nCellLevel) && !bNowApo; // APO-end
513
514 //If it happens that we are in a table, then if it's not the first cell
515 //then any attributes that might otherwise cause the contents to jump
516 //into another frame don't matter, a table row sticks together as one
517 //unit no matter what else happens. So if we are not in a table at
518 //all, or if we are in the first cell then test that the last frame
519 //data is the same as the current one
520 if (bNowApo && InEqualApo(nCellLevel))
521 {
522 // two bordering each other
523 if (!TestSameApo(aRet, pTabPos))
524 aRet.mbStopApo = aRet.mbStartApo = true;
525 }
526
527 return aRet;
528}
529
530// helper methods for outline, numbering and bullets
531
532static void SetBaseAnlv(SwNumFormat &rNum, WW8_ANLV const &rAV, sal_uInt8 nSwLevel )
533{
537
538 static const SvxAdjust eAdjA[4] = { SvxAdjust::Left,
539 SvxAdjust::Right, SvxAdjust::Left, SvxAdjust::Left };
540 if (rAV.nfc < 8) {
541 rNum.SetNumberingType( eNumA[ rAV.nfc ] );
542 } else {
544 switch( rAV.nfc ) {
545 case 14:
546 case 19:nType = SVX_NUM_FULL_WIDTH_ARABIC; break;
547 case 30:nType = SVX_NUM_TIAN_GAN_ZH; break;
548 case 31:nType = SVX_NUM_DI_ZI_ZH; break;
549 case 35:
550 case 36:
551 case 37:
552 case 39:nType = SVX_NUM_NUMBER_LOWER_ZH; break;
553 case 34:nType = SVX_NUM_NUMBER_UPPER_ZH_TW; break;
554 case 38:nType = SVX_NUM_NUMBER_UPPER_ZH; break;
555 case 10:
556 case 11:nType = SVX_NUM_NUMBER_TRADITIONAL_JA; break;
557 case 20:nType = SVX_NUM_AIU_FULLWIDTH_JA; break;
558 case 12:nType = SVX_NUM_AIU_HALFWIDTH_JA; break;
559 case 21:nType = SVX_NUM_IROHA_FULLWIDTH_JA; break;
560 case 13:nType = SVX_NUM_IROHA_HALFWIDTH_JA; break;
561 case 24:nType = SVX_NUM_HANGUL_SYLLABLE_KO; break;
562 case 25:nType = SVX_NUM_HANGUL_JAMO_KO; break;
563 case 41:nType = SVX_NUM_NUMBER_HANGUL_KO; break;
564 //case 42:
565 //case 43:
566 case 44:nType = SVX_NUM_NUMBER_UPPER_KO; break;
567 default:
568 nType= SVX_NUM_ARABIC;break;
569 }
570 rNum.SetNumberingType( nType );
571 }
572
573 if ((rAV.aBits1 & 0x4) >> 2)
574 {
575 rNum.SetIncludeUpperLevels(nSwLevel + 1);
576 }
577 rNum.SetStart( SVBT16ToUInt16( rAV.iStartAt ) );
578 rNum.SetNumAdjust( eAdjA[ rAV.aBits1 & 0x3] );
579
580 rNum.SetCharTextDistance( SVBT16ToUInt16( rAV.dxaSpace ) );
581 sal_Int16 nIndent = std::abs(static_cast<sal_Int16>(SVBT16ToUInt16( rAV.dxaIndent )));
582 if( rAV.aBits1 & 0x08 ) //fHang
583 {
584 rNum.SetFirstLineOffset( -nIndent );
585 rNum.SetAbsLSpace( nIndent );
586 }
587 else
588 rNum.SetCharTextDistance( nIndent ); // width of number is missing
589
590 if( rAV.nfc == 5 || rAV.nfc == 7 )
591 {
592 OUString sP = "." + rNum.GetSuffix();
593 rNum.SetListFormat("", sP, nSwLevel); // ordinal number
594 }
595 else
596 rNum.SetListFormat("", "", nSwLevel);
597}
598
599void SwWW8ImplReader::SetAnlvStrings(SwNumFormat &rNum, int nLevel, WW8_ANLV const &rAV,
600 const sal_uInt8* pText, size_t nStart, size_t nElements, bool bOutline)
601{
602 if (nStart > nElements)
603 return;
604
605 pText += nStart;
606 nElements -= nStart;
607
608 bool bInsert = false; // Default
609 rtl_TextEncoding eCharSet = m_eStructCharSet;
610
611 const WW8_FFN* pF = m_xFonts->GetFont(SVBT16ToUInt16(rAV.ftc)); // FontInfo
612 bool bListSymbol = pF && ( pF->aFFNBase.chs == 2 ); // Symbol/WingDings/...
613
614 sal_uInt32 nLen = rAV.cbTextBefore + rAV.cbTextAfter;
615 OUStringBuffer sText(static_cast<sal_Int32>(nLen));
616 if (m_bVer67)
617 {
618 if (nLen > nElements)
619 {
620 SAL_WARN("sw.ww8", "SetAnlvStrings: ignoring out of range "
621 << nLen << " vs " << nElements << " max");
622 return;
623 }
624 sText = OUString(reinterpret_cast<char const *>(pText), nLen, eCharSet);
625 // ofz#23961 in case of multi-byte input encoding resulting in shorter
626 // output pad to full length with something semi-arbitrary
628 }
629 else
630 {
631 if (nLen > nElements / 2)
632 {
633 SAL_WARN("sw.ww8", "SetAnlvStrings: ignoring out of range "
634 << nLen << " vs " << nElements / 2 << " max");
635 return;
636 }
637 for(sal_uInt32 i = 0; i < nLen; ++i, pText += 2)
638 {
639 sText.append(static_cast<sal_Unicode>(SVBT16ToUInt16(*reinterpret_cast<SVBT16 const *>(pText))));
640 }
641 }
642
643 if( bOutline )
644 { // outline
645 if( !rNum.GetIncludeUpperLevels() // there are <= 1 number to show
646 || rNum.GetNumberingType() == SVX_NUM_NUMBER_NONE ) // or this level has none
647 {
648 // if self defined digits
649 bInsert = true; // then apply character
650
651 // replace by simple Bullet ?
652 if( bListSymbol )
653 {
654 // use cBulletChar for correct mapping on MAC
655 sText.setLength(0);
657 + rAV.cbTextAfter, cBulletChar);
658 }
659 }
660 }
661 else
662 { // numbering / bullets
663 bInsert = true;
664 if( bListSymbol )
665 {
666 FontFamily eFamily;
667 OUString aName;
668 FontPitch ePitch;
669
670 if( GetFontParams( SVBT16ToUInt16( rAV.ftc ), eFamily, aName,
671 ePitch, eCharSet ) ){
672
673 vcl::Font aFont;
674 aFont.SetFamilyName( aName );
675 aFont.SetFamily( eFamily );
676
677 aFont.SetCharSet( eCharSet );
679
680 rNum.SetBulletFont( &aFont );
681
682 // take only the very first character
683 if (rAV.cbTextBefore || rAV.cbTextAfter)
684 {
685 rNum.SetBulletChar(
686 OUString::unacquired(sText).iterateCodePoints(&o3tl::temporary(sal_Int32(0))));
687 }
688 else
689 rNum.SetBulletChar( 0x2190 );
690 }
691 }
692 }
693 if( !bInsert )
694 return;
695
696 OUString sPrefix;
697 OUString sSuffix;
698 if (rAV.cbTextBefore)
699 {
700 sPrefix = sText.copy( 0, rAV.cbTextBefore ).makeStringAndClear();
701 }
702 if( rAV.cbTextAfter )
703 {
704 sSuffix = rNum.GetSuffix() + sText.subView( rAV.cbTextBefore, rAV.cbTextAfter);
705 }
706
707 rNum.SetListFormat(sPrefix, sSuffix, nLevel);
708
709// The characters before and after multiple digits do not apply because
710// those are handled differently by the writer and the result is in most
711// cases worse than without.
712}
713
714// SetAnld gets a WW-ANLD-Descriptor and a Level and modifies the NumRules
715// which are provided by pNumR. This is used for everything beside
716// outline inside the text.
717void SwWW8ImplReader::SetAnld(SwNumRule* pNumR, WW8_ANLD const * pAD, sal_uInt8 nSwLevel,
718 bool bOutLine)
719{
720 SwNumFormat aNF;
721 aNF.SetListFormat("", "", nSwLevel);
722 if (pAD)
723 { // there is an Anld-Sprm
724 m_bCurrentAND_fNumberAcross = 0 != pAD->fNumberAcross;
725 WW8_ANLV const &rAV = pAD->eAnlv;
726 SetBaseAnlv(aNF, rAV, nSwLevel); // set the base format
727 SetAnlvStrings(aNF, nSwLevel, rAV, pAD->rgchAnld, 0, SAL_N_ELEMENTS(pAD->rgchAnld), bOutLine); // set the rest
728 }
729 pNumR->Set(nSwLevel, aNF);
730}
731
732// chapter numbering and bullets
733
734// Chapter numbering happens in the style definition.
735// Sprm 13 provides the level, Sprm 12 the content.
736
738{
739 if( m_xStyles->mpStyRule ) // Bullet-Style already present
740 return m_xStyles->mpStyRule;
741
742 const OUString aBaseName("WW8StyleNum");
743 const OUString aName( m_rDoc.GetUniqueNumRuleName( &aBaseName, false) );
744
745 // #i86652#
746 sal_uInt16 nRul = m_rDoc.MakeNumRule( aName, nullptr, false,
748 m_xStyles->mpStyRule = m_rDoc.GetNumRuleTable()[nRul];
749 // Auto == false-> numbering style
750 m_xStyles->mpStyRule->SetAutoRule(false);
751
752 return m_xStyles->mpStyRule;
753}
754
755// Sprm 13
756void SwWW8ImplReader::Read_ANLevelNo( sal_uInt16, const sal_uInt8* pData, short nLen )
757{
758 m_nSwNumLevel = 0xff; // Default: invalid
759
760 if( nLen <= 0 )
761 return;
762
763 // StyleDef ?
764 if( m_pCurrentColl )
765 {
766 // only for SwTextFormatColl, not CharFormat
767 // WW: 0 = no Numbering
768 SwWW8StyInf * pColl = GetStyle(m_nCurrentColl);
769 if (pColl != nullptr && pColl->m_bColl && *pData)
770 {
771 // Range WW:1..9 -> SW:0..8 no bullets / numbering
772
773 if (*pData <= 9)
774 {
775 m_nSwNumLevel = *pData - 1;
776 if (!m_bNoAttrImport)
777 static_cast<SwTextFormatColl*>(m_pCurrentColl)->AssignToListLevelOfOutlineStyle( m_nSwNumLevel );
778 // For WW-NoNumbering also NO_NUMBERING could be used.
779 // ( For normal numberierung NO_NUM has to be used:
780 // NO_NUM : pauses numbering,
781 // NO_NUMBERING : no numbering at all )
782
783 }
784 else if( *pData == 10 || *pData == 11 )
785 {
786 // remember type, the rest happens at Sprm 12
787 m_xStyles->mnWwNumLevel = *pData;
788 }
789 }
790 }
791 else
792 {
793 //Not StyleDef
794 if (!m_bAnl)
795 StartAnl(pData); // begin of outline / bullets
796 NextAnlLine(pData);
797 }
798}
799
800void SwWW8ImplReader::Read_ANLevelDesc( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm 12
801{
802 SwWW8StyInf * pStyInf = GetStyle(m_nCurrentColl);
803 if( !m_pCurrentColl || nLen <= 0 // only for Styledef
804 || (pStyInf && !pStyInf->m_bColl) // ignore CharFormat ->
805 || ( m_nIniFlags & WW8FL_NO_OUTLINE ) )
806 {
807 m_nSwNumLevel = 0xff;
808 return;
809 }
810
811 if (o3tl::make_unsigned(nLen) < sizeof(WW8_ANLD))
812 {
813 SAL_WARN("sw.ww8", "ANLevelDesc property is " << nLen << " long, needs to be at least " << sizeof(WW8_ANLD));
814 m_nSwNumLevel = 0xff;
815 return;
816 }
817
818 if (m_nSwNumLevel <= 9) // Value range mapping WW:1..9 -> SW:0..8
819 {
820
821 // If NumRuleItems were set, either directly or through inheritance, disable them now
822 m_pCurrentColl->SetFormatAttr( SwNumRuleItem() );
823
824 const OUString aName("Outline");
827 OUTLINE_RULE );
828 aNR = *m_rDoc.GetOutlineNumRule();
829
830 SetAnld(&aNR, reinterpret_cast<WW8_ANLD const *>(pData), m_nSwNumLevel, true);
831
832 // Missing Levels need not be replenished
834 }
835 else if( m_xStyles->mnWwNumLevel == 10 || m_xStyles->mnWwNumLevel == 11 ){
836 SwNumRule* pNR = GetStyRule();
837 SetAnld(pNR, reinterpret_cast<WW8_ANLD const *>(pData), 0, false);
838 m_pCurrentColl->SetFormatAttr( SwNumRuleItem( pNR->GetName() ) );
839
840 pStyInf = GetStyle(m_nCurrentColl);
841 if (pStyInf != nullptr)
842 pStyInf->m_bHasStyNumRule = true;
843 }
844}
845
846// Numbering / Bullets
847
848// SetNumOlst() carries the Numrules for this cell to SwNumFormat.
849// For this the info is fetched from OLST and not from ANLD ( see later )
850// ( only for outline inside text; Bullets / numbering use ANLDs )
852{
853 SwNumFormat aNF;
854 WW8_ANLV &rAV = pO->rganlv[nSwLevel];
855 SetBaseAnlv(aNF, rAV, nSwLevel);
856 // ... and then the Strings
857 int nTextOfs = 0;
858 sal_uInt8 i;
859 WW8_ANLV* pAV1; // search String-Positions
860 for (i = 0, pAV1 = pO->rganlv; i < nSwLevel; ++i, ++pAV1)
861 nTextOfs += pAV1->cbTextBefore + pAV1->cbTextAfter;
862
863 if (!m_bVer67)
864 nTextOfs *= 2;
865 SetAnlvStrings(aNF, nSwLevel, rAV, pO->rgch, nTextOfs, SAL_N_ELEMENTS(pO->rgch), true); // and apply
866 pNumR->Set(nSwLevel, aNF);
867}
868
869// The OLST is at the beginning of each section that contains outlines.
870// The ANLDs that are connected to each outline-line contain only nonsense,
871// so the OLSTs are remembered for the section to have usable information
872// when outline-paragraphs occur.
873void SwWW8ImplReader::Read_OLST( sal_uInt16, const sal_uInt8* pData, short nLen )
874{
875 m_xNumOlst.reset();
876 if (nLen <= 0)
877 return;
878
879 if (o3tl::make_unsigned(nLen) < sizeof(WW8_OLST))
880 {
881 SAL_WARN("sw.ww8", "WW8_OLST property is " << nLen << " long, needs to be at least " << sizeof(WW8_OLST));
882 return;
883 }
884
885 m_xNumOlst.reset(new WW8_OLST);
886 *m_xNumOlst = *reinterpret_cast<WW8_OLST const *>(pData);
887}
888
890{
891 WW8LvlType nRet = WW8_None;
892 if( nWwLevelNo == 12 )
893 nRet = WW8_Pause;
894 else if( nWwLevelNo == 10 )
895 nRet = WW8_Numbering;
896 else if( nWwLevelNo == 11 )
897 nRet = WW8_Sequence;
898 else if( nWwLevelNo > 0 && nWwLevelNo <= 9 )
899 nRet = WW8_Outline;
900 return nRet;
901}
902
904{
905 const OUString& rNumRule = WW8_Numbering == nNumType ? msNumberingNumRule : msOutlineNumRule;
906 if (rNumRule.isEmpty())
907 return nullptr;
908 return rDoc.FindNumRulePtr(rNumRule);
909}
910
911void ANLDRuleMap::SetNumRule(const OUString& rNumRule, sal_uInt8 nNumType)
912{
913 if (WW8_Numbering == nNumType)
914 msNumberingNumRule = rNumRule;
915 else
916 msOutlineNumRule = rNumRule;
917}
918
919// StartAnl is called at the beginning of a row area that contains
920// outline / numbering / bullets
922{
923 m_bCurrentAND_fNumberAcross = false;
924
925 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType(*pSprm13));
926 if (nT == WW8_Pause || nT == WW8_None)
927 return;
928
929 m_nWwNumType = nT;
930 SwNumRule *pNumRule = m_aANLDRules.GetNumRule(m_rDoc, m_nWwNumType);
931
932 // check for COL numbering:
933 SprmResult aS12; // sprmAnld
934 OUString sNumRule;
935
936 if (m_xTableDesc)
937 {
938 sNumRule = m_xTableDesc->GetNumRuleName();
939 if (!sNumRule.isEmpty())
940 {
941 pNumRule = m_rDoc.FindNumRulePtr(sNumRule);
942 if (!pNumRule)
943 sNumRule.clear();
944 else
945 {
946 // this is ROW numbering ?
947 aS12 = m_xPlcxMan->HasParaSprm(m_bVer67 ? 12 : NS_sprm::LN_PAnld); // sprmAnld
948 if (aS12.pSprm && aS12.nRemainingData >= sal_Int32(sizeof(WW8_ANLD)) && 0 != reinterpret_cast<WW8_ANLD const *>(aS12.pSprm)->fNumberAcross)
949 sNumRule.clear();
950 }
951 }
952 }
953
954 SwWW8StyInf * pStyInf = GetStyle(m_nCurrentColl);
955 if (sNumRule.isEmpty() && pStyInf != nullptr && pStyInf->m_bHasStyNumRule)
956 {
957 sNumRule = pStyInf->m_pFormat->GetNumRule().GetValue();
958 pNumRule = m_rDoc.FindNumRulePtr(sNumRule);
959 if (!pNumRule)
960 sNumRule.clear();
961 }
962
963 if (sNumRule.isEmpty())
964 {
965 if (!pNumRule)
966 {
967 // #i86652#
968 pNumRule = m_rDoc.GetNumRuleTable()[
969 m_rDoc.MakeNumRule( sNumRule, nullptr, false,
971 }
972 if (m_xTableDesc)
973 {
974 if (!aS12.pSprm)
975 aS12 = m_xPlcxMan->HasParaSprm(m_bVer67 ? 12 : NS_sprm::LN_PAnld); // sprmAnld
976 if (!aS12.pSprm || aS12.nRemainingData < sal_Int32(sizeof(WW8_ANLD)) || !reinterpret_cast<WW8_ANLD const *>(aS12.pSprm)->fNumberAcross)
977 m_xTableDesc->SetNumRuleName(pNumRule->GetName());
978 }
979 }
980
981 m_bAnl = true;
982
983 sNumRule = pNumRule ? pNumRule->GetName() : OUString();
984 // set NumRules via stack
985 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(),
987
988 m_aANLDRules.SetNumRule(sNumRule, m_nWwNumType);
989}
990
991// NextAnlLine() is called once for every row of a
992// outline / numbering / bullet
994{
995 if (!m_bAnl)
996 return;
997
998 SwNumRule *pNumRule = m_aANLDRules.GetNumRule(m_rDoc, m_nWwNumType);
999
1000 // pNd->UpdateNum without a set of rules crashes at the latest whilst storing as sdw3
1001
1002 // WW:10 = numbering -> SW:0 & WW:11 = bullets -> SW:0
1003 if (*pSprm13 == 10 || *pSprm13 == 11)
1004 {
1005 m_nSwNumLevel = 0;
1006 if (pNumRule && !pNumRule->GetNumFormat(m_nSwNumLevel))
1007 {
1008 // not defined yet
1009 // sprmAnld o. 0
1010 SprmResult aS12 = m_xPlcxMan->HasParaSprm(m_bVer67 ? 12 : NS_sprm::LN_PAnld);
1011 if (aS12.nRemainingData >= sal_Int32(sizeof(WW8_ANLD)))
1012 SetAnld(pNumRule, reinterpret_cast<WW8_ANLD const *>(aS12.pSprm), m_nSwNumLevel, false);
1013 }
1014 }
1015 else if( *pSprm13 > 0 && *pSprm13 <= MAXLEVEL ) // range WW:1..9 -> SW:0..8
1016 {
1017 m_nSwNumLevel = *pSprm13 - 1; // outline
1018 // undefined
1019 if (pNumRule && !pNumRule->GetNumFormat(m_nSwNumLevel))
1020 {
1021 if (m_xNumOlst) // there was a OLST
1022 {
1023 //Assure upper levels are set, #i9556#
1024 for (sal_uInt8 nI = 0; nI < m_nSwNumLevel; ++nI)
1025 {
1026 if (!pNumRule->GetNumFormat(nI))
1027 SetNumOlst(pNumRule, m_xNumOlst.get(), nI);
1028 }
1029
1030 SetNumOlst(pNumRule, m_xNumOlst.get(), m_nSwNumLevel);
1031 }
1032 else // no Olst -> use Anld
1033 {
1034 // sprmAnld
1035 SprmResult aS12 = m_xPlcxMan->HasParaSprm(m_bVer67 ? 12 : NS_sprm::LN_PAnld);
1036 if (aS12.nRemainingData >= sal_Int32(sizeof(WW8_ANLD)))
1037 SetAnld(pNumRule, reinterpret_cast<WW8_ANLD const *>(aS12.pSprm), m_nSwNumLevel, false);
1038 }
1039 }
1040 }
1041 else
1042 m_nSwNumLevel = 0xff; // no number
1043
1044 SwTextNode* pNd = m_pPaM->GetPointNode().GetTextNode();
1045 if (!pNd)
1046 return;
1047
1048 if (m_nSwNumLevel < MAXLEVEL)
1049 pNd->SetAttrListLevel( m_nSwNumLevel );
1050 else
1051 {
1052 pNd->SetAttrListLevel(0);
1053 pNd->SetCountedInList( false );
1054 }
1055}
1056
1058{
1059 //Of course we're not restarting, but we'll make use of our knowledge
1060 //of the implementation to do it.
1061 StopAnlToRestart(WW8_None, bGoBack);
1062}
1063
1065{
1066 if (bGoBack)
1067 {
1068 SwPosition aTmpPos(*m_pPaM->GetPoint());
1069 m_pPaM->Move(fnMoveBackward, GoInContent);
1070 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FLTR_NUMRULE);
1071 *m_pPaM->GetPoint() = aTmpPos;
1072 }
1073 else
1074 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FLTR_NUMRULE);
1075
1076 m_aANLDRules.msNumberingNumRule.clear();
1077 /*
1078 #i18816#
1079 my take on this problem is that moving either way from an outline to a
1080 numbering doesn't halt the outline, while the numbering is always halted
1081 */
1082 bool bNumberingNotStopOutline =
1083 (((m_nWwNumType == WW8_Outline) && (nNewType == WW8_Numbering)) ||
1084 ((m_nWwNumType == WW8_Numbering) && (nNewType == WW8_Outline)));
1085 if (!bNumberingNotStopOutline)
1086 m_aANLDRules.msOutlineNumRule.clear();
1087
1088 m_nSwNumLevel = 0xff;
1089 m_nWwNumType = WW8_None;
1090 m_bAnl = false;
1091}
1092
1094{
1095 *this = rBand;
1096 if( rBand.pTCs )
1097 {
1098 pTCs = reinterpret_cast<WW8_TCell *>(new char[nWwCols * sizeof (WW8_TCell)]);
1099 // create uninitialized
1100 memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1101 }
1102 if( rBand.pSHDs )
1103 {
1104 pSHDs = new WW8_SHD[nWwCols];
1105 memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1106 }
1107 if( rBand.pNewSHDs )
1108 {
1109 pNewSHDs = new Color[nWwCols];
1110 memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(Color));
1111 }
1112 memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1113}
1114
1115// ReadDef reads the cell position and the borders of a band
1116void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS, short nLen)
1117{
1118 --nLen; //reduce len by expected nCols arg
1119 if (nLen < 0)
1120 return;
1121 sal_uInt8 nCols = *pS; // number of cells
1122
1123 if (nCols > MAX_COL)
1124 return;
1125
1126 nLen -= 2 * (nCols + 1); //reduce len by claimed amount of next x-borders arguments
1127 if (nLen < 0)
1128 return;
1129
1130 short nOldCols = nWwCols;
1131 nWwCols = nCols;
1132
1133 const sal_uInt8* pT = &pS[1];
1134 for (int i = 0; i <= nCols; i++, pT+=2)
1135 nCenter[i] = static_cast<sal_Int16>(SVBT16ToUInt16( pT )); // X-borders
1136
1137 if( nCols != nOldCols ) // different column count
1138 {
1139 delete[] pTCs;
1140 pTCs = nullptr;
1141 delete[] pSHDs;
1142 pSHDs = nullptr;
1143 delete[] pNewSHDs;
1144 pNewSHDs = nullptr;
1145 }
1146
1147 short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // really saved
1148
1149 if (!pTCs && nCols)
1150 {
1151 // create empty TCs
1152 pTCs = new WW8_TCell[nCols];
1153 }
1154
1155 short nColsToRead = std::min<short>(nFileCols, nCols);
1156
1157 if (nColsToRead <= 0)
1158 return;
1159
1160 // read TCs
1161
1162 /*
1163 Attention: Beginning with Ver8 there is an extra ushort per TC
1164 added and the size of the border code is doubled.
1165 Because of this a simple copy (pTCs[i] = *pTc;)
1166 is not possible.
1167 ---
1168 Advantage: The work structure suits better.
1169 */
1170 WW8_TCell* pCurrentTC = pTCs;
1171 if( bVer67 )
1172 {
1173 WW8_TCellVer6 const * pTc = reinterpret_cast<WW8_TCellVer6 const *>(pT);
1174 for (int i = 0; i < nColsToRead; i++, ++pCurrentTC,++pTc)
1175 {
1176 // TC from file ?
1177 sal_uInt8 aBits1 = pTc->aBits1Ver6;
1178 pCurrentTC->bFirstMerged = sal_uInt8( ( aBits1 & 0x01 ) != 0 );
1179 pCurrentTC->bMerged = sal_uInt8( ( aBits1 & 0x02 ) != 0 );
1180 pCurrentTC->rgbrc[ WW8_TOP ]
1181 = WW8_BRCVer9(WW8_BRC( pTc->rgbrcVer6[ WW8_TOP ] ));
1182 pCurrentTC->rgbrc[ WW8_LEFT ]
1183 = WW8_BRCVer9(WW8_BRC( pTc->rgbrcVer6[ WW8_LEFT ] ));
1184 pCurrentTC->rgbrc[ WW8_BOT ]
1185 = WW8_BRCVer9(WW8_BRC( pTc->rgbrcVer6[ WW8_BOT ] ));
1186 pCurrentTC->rgbrc[ WW8_RIGHT ]
1187 = WW8_BRCVer9(WW8_BRC( pTc->rgbrcVer6[ WW8_RIGHT ] ));
1188 if( ( pCurrentTC->bMerged )
1189 && ( i > 0 ) )
1190 {
1191 // Cell merged -> remember
1192 //bWWMergedVer6[i] = true;
1193 pTCs[i-1].rgbrc[ WW8_RIGHT ]
1194 = WW8_BRCVer9(WW8_BRC( pTc->rgbrcVer6[ WW8_RIGHT ] ));
1195 // apply right border to previous cell
1196 // bExist must not be set to false, because WW
1197 // does not count this cells in text boxes...
1198 }
1199 }
1200 }
1201 else
1202 {
1203 WW8_TCellVer8 const * pTc = reinterpret_cast<WW8_TCellVer8 const *>(pT);
1204 for (int k = 0; k < nColsToRead; ++k, ++pCurrentTC, ++pTc )
1205 {
1206 sal_uInt16 aBits1 = SVBT16ToUInt16( pTc->aBits1Ver8 );
1207 pCurrentTC->bFirstMerged = sal_uInt8( ( aBits1 & 0x0001 ) != 0 );
1208 pCurrentTC->bMerged = sal_uInt8( ( aBits1 & 0x0002 ) != 0 );
1209 pCurrentTC->bVertical = sal_uInt8( ( aBits1 & 0x0004 ) != 0 );
1210 pCurrentTC->bBackward = sal_uInt8( ( aBits1 & 0x0008 ) != 0 );
1211 pCurrentTC->bRotateFont = sal_uInt8( ( aBits1 & 0x0010 ) != 0 );
1212 pCurrentTC->bVertMerge = sal_uInt8( ( aBits1 & 0x0020 ) != 0 );
1213 pCurrentTC->bVertRestart = sal_uInt8( ( aBits1 & 0x0040 ) != 0 );
1214 pCurrentTC->nVertAlign = ( ( aBits1 & 0x0180 ) >> 7 );
1215 // note: in aBits1 there are 7 bits unused,
1216 // followed by another 16 unused bits
1217
1218 pCurrentTC->rgbrc[ WW8_TOP ] = WW8_BRCVer9(pTc->rgbrcVer8[ WW8_TOP ]);
1219 pCurrentTC->rgbrc[ WW8_LEFT ] = WW8_BRCVer9(pTc->rgbrcVer8[ WW8_LEFT ]);
1220 pCurrentTC->rgbrc[ WW8_BOT ] = WW8_BRCVer9(pTc->rgbrcVer8[ WW8_BOT ]);
1221 pCurrentTC->rgbrc[ WW8_RIGHT ] = WW8_BRCVer9(pTc->rgbrcVer8[ WW8_RIGHT ]);
1222 }
1223 }
1224
1225 // #i25071 In '97 text direction appears to be only set using TC properties
1226 // not with sprmTTextFlow so we need to cycle through the maDirections and
1227 // double check any non-default directions
1228 for (int k = 0; k < nCols; ++k)
1229 {
1230 if(maDirections[k] == 4)
1231 {
1232 if(pTCs[k].bVertical)
1233 {
1234 if(pTCs[k].bBackward)
1235 maDirections[k] = 3;
1236 else
1237 maDirections[k] = 1;
1238 }
1239 }
1240 }
1241}
1242
1243void WW8TabBandDesc::ProcessSprmTSetBRC(int nBrcVer, const sal_uInt8* pParamsTSetBRC, sal_uInt16 nParamsLen)
1244{
1245 if( !pParamsTSetBRC || !pTCs ) // set one or more cell border(s)
1246 return;
1247
1248 if (nParamsLen < 3)
1249 {
1250 SAL_WARN("sw.ww8", "table border property is too short");
1251 return;
1252 }
1253
1254 sal_uInt8 nitcFirst= pParamsTSetBRC[0];// first col to be changed
1255 sal_uInt8 nitcLim = pParamsTSetBRC[1];// (last col to be changed)+1
1256 sal_uInt8 nFlag = *(pParamsTSetBRC+2);
1257
1258 if (nitcFirst >= nWwCols)
1259 return;
1260
1261 if (nitcLim > nWwCols)
1262 nitcLim = nWwCols;
1263
1264 bool bChangeRight = (nFlag & 0x08) != 0;
1265 bool bChangeBottom = (nFlag & 0x04) != 0;
1266 bool bChangeLeft = (nFlag & 0x02) != 0;
1267 bool bChangeTop = (nFlag & 0x01) != 0;
1268
1269 WW8_TCell* pCurrentTC = pTCs + nitcFirst;
1270 WW8_BRCVer9 brcVer9;
1271 if( nBrcVer == 6 )
1272 {
1273 if (nParamsLen < sizeof(WW8_BRCVer6) + 3)
1274 {
1275 SAL_WARN("sw.ww8", "table border property is too short");
1276 return;
1277 }
1278 brcVer9 = WW8_BRCVer9(WW8_BRC(*reinterpret_cast<WW8_BRCVer6 const *>(pParamsTSetBRC+3)));
1279 }
1280 else if( nBrcVer == 8 )
1281 {
1282 static_assert(sizeof (WW8_BRC) == 4, "this has to match the msword size");
1283 if (nParamsLen < sizeof(WW8_BRC) + 3)
1284 {
1285 SAL_WARN("sw.ww8", "table border property is too short");
1286 return;
1287 }
1288 brcVer9 = WW8_BRCVer9(*reinterpret_cast<WW8_BRC const *>(pParamsTSetBRC+3));
1289 }
1290 else
1291 {
1292 if (nParamsLen < sizeof(WW8_BRCVer9) + 3)
1293 {
1294 SAL_WARN("sw.ww8", "table border property is too short");
1295 return;
1296 }
1297 brcVer9 = *reinterpret_cast<WW8_BRCVer9 const *>(pParamsTSetBRC+3);
1298 }
1299
1300 for( int i = nitcFirst; i < nitcLim; ++i, ++pCurrentTC )
1301 {
1302 if( bChangeTop )
1303 pCurrentTC->rgbrc[ WW8_TOP ] = brcVer9;
1304 if( bChangeLeft )
1305 pCurrentTC->rgbrc[ WW8_LEFT ] = brcVer9;
1306 if( bChangeBottom )
1307 pCurrentTC->rgbrc[ WW8_BOT ] = brcVer9;
1308 if( bChangeRight )
1309 pCurrentTC->rgbrc[ WW8_RIGHT ] = brcVer9;
1310 }
1311}
1312
1313void WW8TabBandDesc::ProcessSprmTTableBorders(int nBrcVer, const sal_uInt8* pParams, sal_uInt16 nParamsLen)
1314{
1315 // sprmTTableBorders
1316 if( nBrcVer == 6 )
1317 {
1318 if (nParamsLen < sizeof(WW8_BRCVer6) * 6)
1319 {
1320 SAL_WARN("sw.ww8", "table border property is too short");
1321 return;
1322 }
1323 WW8_BRCVer6 const *pVer6 = reinterpret_cast<WW8_BRCVer6 const *>(pParams);
1324 for (int i = 0; i < 6; ++i)
1325 aDefBrcs[i] = WW8_BRCVer9(WW8_BRC(pVer6[i]));
1326 }
1327 else if ( nBrcVer == 8 )
1328 {
1329 static_assert(sizeof (WW8_BRC) == 4, "this has to match the msword size");
1330 if (nParamsLen < sizeof(WW8_BRC) * 6)
1331 {
1332 SAL_WARN("sw.ww8", "table border property is too short");
1333 return;
1334 }
1335 for( int i = 0; i < 6; ++i )
1336 aDefBrcs[i] = WW8_BRCVer9(reinterpret_cast<WW8_BRC const *>(pParams)[i]);
1337 }
1338 else
1339 {
1340 if (nParamsLen < sizeof( aDefBrcs ))
1341 {
1342 SAL_WARN("sw.ww8", "table border property is too short");
1343 return;
1344 }
1345 memcpy( aDefBrcs, pParams, sizeof( aDefBrcs ) );
1346 }
1347}
1348
1350{
1351 // sprmTDxaCol (opcode 0x7623) changes the width of cells
1352 // whose index is within a certain range to be a certain value.
1353
1354 if( !(nWwCols && pParamsTDxaCol) ) // set one or more cell length(s)
1355 return;
1356
1357 sal_uInt8 nitcFirst= pParamsTDxaCol[0]; // first col to be changed
1358 sal_uInt8 nitcLim = pParamsTDxaCol[1]; // (last col to be changed)+1
1359 short nDxaCol = static_cast<sal_Int16>(SVBT16ToUInt16( pParamsTDxaCol + 2 ));
1360
1361 for( int i = nitcFirst; (i < nitcLim) && (i < nWwCols); i++ )
1362 {
1363 const short nOrgWidth = nCenter[i+1] - nCenter[i];
1364 const short nDelta = nDxaCol - nOrgWidth;
1365 for( int j = i+1; j <= nWwCols; j++ )
1366 {
1367 nCenter[j] = nCenter[j] + nDelta;
1368 }
1369 }
1370}
1371
1373{
1374 if( !nWwCols || !pParamsTInsert ) // set one or more cell length(s)
1375 return;
1376
1377 sal_uInt8 nitcInsert = pParamsTInsert[0]; // position at which to insert
1378 if (nitcInsert >= MAX_COL) // cannot insert into cell outside max possible index
1379 return;
1380 sal_uInt8 nctc = pParamsTInsert[1]; // number of cells
1381 sal_uInt16 ndxaCol = SVBT16ToUInt16( pParamsTInsert+2 );
1382
1383 short nNewWwCols;
1384 if (nitcInsert > nWwCols)
1385 {
1386 nNewWwCols = nitcInsert+nctc;
1387 //if new count would be outside max possible count, clip it, and calc a new replacement
1388 //legal nctc
1389 if (nNewWwCols > MAX_COL)
1390 {
1391 nNewWwCols = MAX_COL;
1392 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nitcInsert);
1393 }
1394 }
1395 else
1396 {
1397 nNewWwCols = nWwCols+nctc;
1398 //if new count would be outside max possible count, clip it, and calc a new replacement
1399 //legal nctc
1400 if (nNewWwCols > MAX_COL)
1401 {
1402 nNewWwCols = MAX_COL;
1403 nctc = ::sal::static_int_cast<sal_uInt8>(nNewWwCols-nWwCols);
1404 }
1405 }
1406
1407 WW8_TCell *pTC2s = new WW8_TCell[nNewWwCols];
1408
1409 if (pTCs)
1410 {
1411 memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1412 delete[] pTCs;
1413 }
1414 pTCs = pTC2s;
1415
1416 //If we have to move some cells
1417 if (nitcInsert <= nWwCols)
1418 {
1419 // adjust the left x-position of the dummy at the very end
1420 nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1421 for( int i = nWwCols-1; i >= nitcInsert; i--)
1422 {
1423 // adjust the left x-position
1424 nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1425
1426 // adjust the cell's borders
1427 pTCs[i + nctc] = pTCs[i];
1428 }
1429 }
1430
1431 //if itcMac is larger than full size, fill in missing ones first
1432 for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1433 nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1434
1435 //now add in our new cells
1436 for( int j = 0;j < nctc; j++)
1437 nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1438
1439 nWwCols = nNewWwCols;
1440
1441}
1442
1444{
1445 sal_uInt8 nStartCell = *pParams++;
1446 sal_uInt8 nEndCell = *pParams++;
1447 sal_uInt16 nCode = SVBT16ToUInt16(pParams);
1448
1449 OSL_ENSURE(nStartCell < nEndCell, "not as I thought");
1450 OSL_ENSURE(nEndCell < MAX_COL + 1, "not as I thought");
1451 if (nStartCell > MAX_COL)
1452 return;
1453 if (nEndCell > MAX_COL + 1)
1454 nEndCell = MAX_COL + 1;
1455
1456 for (;nStartCell < nEndCell; ++nStartCell)
1457 maDirections[nStartCell] = nCode;
1458}
1459
1461{
1462 sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1463 OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1464 if (nLen != 6)
1465 return;
1466 mbHasSpacing=true;
1467#if OSL_DEBUG_LEVEL > 0
1468 sal_uInt8 nWhichCell = *pParams;
1469 OSL_ENSURE(nWhichCell == 0, "Expected cell to be 0!");
1470#endif
1471 ++pParams; //Skip which cell
1472 ++pParams; //unknown byte
1473
1474 sal_uInt8 nSideBits = *pParams++;
1475 OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1476 ++pParams; //unknown byte
1477 sal_uInt16 nValue = SVBT16ToUInt16( pParams );
1478 for (int i = wwTOP; i <= wwRIGHT; i++)
1479 {
1480 switch (nSideBits & (1 << i))
1481 {
1482 case 1 << wwTOP:
1483 mnDefaultTop = nValue;
1484 break;
1485 case 1 << wwLEFT:
1486 mnDefaultLeft = nValue;
1487 break;
1488 case 1 << wwBOTTOM:
1489 mnDefaultBottom = nValue;
1490 break;
1491 case 1 << wwRIGHT:
1492 mnDefaultRight = nValue;
1493 break;
1494 case 0:
1495 break;
1496 default:
1497 OSL_ENSURE(false, "Impossible");
1498 break;
1499 }
1500 }
1501}
1502
1504{
1505 sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1506 OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1507 if (nLen != 6)
1508 return;
1509
1510 const sal_uInt8 nStartCell = *pParams++; // The first cell these margins could apply to.
1511 const sal_uInt8 nEndCell = *pParams++; // The cell that does NOT apply these margins.
1512 OSL_ENSURE(nStartCell < MAX_COL + 1, "Cell out of range in spacings");
1513 if ( nStartCell >= nEndCell || nEndCell > MAX_COL+1 )
1514 return;
1515
1516 sal_uInt8 nSideBits = *pParams++;
1517 OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1518
1519 const sal_uInt8 nSizeType = *pParams++; // Fts: FtsDxa(0x3) is the only type that mentions cellMargin
1520 OSL_ENSURE(nSizeType == 0x3, "Unexpected non-twip value for margin width");
1521 if ( nSizeType != 0x3 ) // i.e FtsNil: The size is wrong (or unconverted) and MUST be ignored
1522 return;
1523
1524 sal_uInt16 nValue = SVBT16ToUInt16( pParams );
1525
1526 for (int nCell = nStartCell; nCell < nEndCell; ++nCell)
1527 {
1528 nOverrideSpacing[ nCell ] |= nSideBits;
1529 OSL_ENSURE(nOverrideSpacing[ nCell ] < 0x10, "Unexpected value for nSideBits");
1530
1531 for (int i=0; i < 4; i++)
1532 {
1533 if (nSideBits & (1 << i))
1534 nOverrideValues[ nCell ][ i ] = nValue;
1535 }
1536 }
1537}
1538
1540{
1541 if( !(nWwCols && pParamsTDelete) ) // set one or more cell length(s)
1542 return;
1543
1544 sal_uInt8 nitcFirst= pParamsTDelete[0]; // first col to be deleted
1545 if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1546 return;
1547 sal_uInt8 nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1548 if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1549 return;
1550
1551 /*
1552 * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1553 * greater than or equal to itcLim to be moved
1554 */
1555 int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1556
1557 if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1558 {
1559 WW8_TCell* pCurrentTC = pTCs + nitcFirst;
1560 int i = 0;
1561 while( i < nShlCnt )
1562 {
1563 // adjust the left x-position
1564 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1565
1566 // adjust the cell's borders
1567 *pCurrentTC = pTCs[ nitcLim + i];
1568
1569 ++i;
1570 ++pCurrentTC;
1571 }
1572 // adjust the left x-position of the dummy at the very end
1573 nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1574 }
1575
1576 short nCellsDeleted = nitcLim - nitcFirst;
1577 //clip delete request to available number of cells
1578 if (nCellsDeleted > nWwCols)
1579 nCellsDeleted = nWwCols;
1580 nWwCols -= nCellsDeleted;
1581}
1582
1583// ReadShd reads the background color of a cell
1584// ReadDef must be called before
1586{
1587 sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1588 if( !nLen )
1589 return;
1590
1591 if( !pSHDs )
1592 {
1593 pSHDs = new WW8_SHD[nWwCols];
1594 }
1595
1596 short nCount = nLen >> 1;
1597 if (nCount > nWwCols)
1598 nCount = nWwCols;
1599
1600 SVBT16 const * pShd;
1601 int i;
1602 for(i=0, pShd = reinterpret_cast<SVBT16 const *>(pS); i<nCount; i++, pShd++ )
1603 pSHDs[i].SetWWValue( *pShd );
1604}
1605
1606void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67, sal_uInt8 nStart)
1607{
1608 sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1609 if (!nLen || nStart >= nWwCols)
1610 return;
1611
1612 if (!pNewSHDs)
1613 pNewSHDs = new Color[nWwCols];
1614
1615 short nCount = nLen / 10 + nStart; //10 bytes each
1616 if (nCount > nWwCols)
1617 nCount = nWwCols;
1618
1619 int i=nStart;
1620 while (i < nCount)
1621 pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1622
1623 while (i < nWwCols)
1624 pNewSHDs[i++] = COL_AUTO;
1625}
1626
1627namespace
1628{
1629 SprmResult HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1630 {
1631 if (bVer67)
1632 return pPap->HasSprm(24);
1633 SprmResult aRes = pPap->HasSprm(0x244B);
1634 if (aRes.pSprm == nullptr)
1635 aRes = pPap->HasSprm(0x2416);
1636 return aRes;
1637 }
1638}
1639
1640namespace {
1641
1642enum wwTableSprm
1643{
1644 sprmNil,
1645
1646 sprmTTableWidth, sprmTTextFlow, sprmTFCantSplit, sprmTJc, sprmTFBiDi,
1649 sprmTTableHeader, sprmTDxaGapHalf, sprmTTableBorders, sprmTTableBorders90,
1650 sprmTDefTableNewShd, sprmTDefTableNewShd2nd, sprmTDefTableNewShd3rd,
1651 sprmTCellPadding, sprmTCellPaddingDefault
1652};
1653
1654}
1655
1656static wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1657{
1658 switch (eVer)
1659 {
1660 case ww::eWW8:
1661 switch (nId)
1662 {
1664 return sprmTTableWidth;
1666 return sprmTTextFlow;
1668 return sprmTTableHeader;
1670 return sprmTFCantSplit;
1672 return sprmTJc;
1674 return sprmTFBiDi;
1676 return sprmTDelete;
1678 return sprmTInsert;
1680 return sprmTDxaCol;
1682 return sprmTDyaRowHeight;
1684 return sprmTDxaLeft;
1686 return sprmTDxaGapHalf;
1688 return sprmTTableBorders;
1690 return sprmTDefTable;
1692 return sprmTDefTableShd;
1694 return sprmTDefTableNewShd;
1696 return sprmTDefTableNewShd2nd;
1698 return sprmTDefTableNewShd3rd;
1700 return sprmTTableBorders90;
1702 return sprmTSetBrc;
1704 return sprmTSetBrc90;
1706 return sprmTCellPadding;
1708 return sprmTCellPaddingDefault;
1709 }
1710 break;
1711 case ww::eWW7:
1712 case ww::eWW6:
1713 switch (nId)
1714 {
1715 case 182:
1716 return sprmTJc;
1717 case 183:
1718 return sprmTDxaLeft;
1719 case 184:
1720 return sprmTDxaGapHalf;
1721 case 186:
1722 return sprmTTableHeader;
1723 case 187:
1724 return sprmTTableBorders;
1725 case 189:
1726 return sprmTDyaRowHeight;
1727 case 190:
1728 return sprmTDefTable;
1729 case 191:
1730 return sprmTDefTableShd;
1731 case 193:
1732 return sprmTSetBrc;
1733 case 194:
1734 return sprmTInsert;
1735 case 195:
1736 return sprmTDelete;
1737 case 196:
1738 return sprmTDxaCol;
1739 }
1740 break;
1741 case ww::eWW1:
1742 case ww::eWW2:
1743 switch (nId)
1744 {
1745 case 146:
1746 return sprmTJc;
1747 case 147:
1748 return sprmTDxaLeft;
1749 case 148:
1750 return sprmTDxaGapHalf;
1751 case 153:
1752 return sprmTDyaRowHeight;
1753 case 154:
1754 return sprmTDefTable;
1755 case 155:
1756 return sprmTDefTableShd;
1757 case 157:
1758 return sprmTSetBrc;
1759 case 158:
1760 return sprmTInsert;
1761 case 159:
1762 return sprmTDelete;
1763 case 160:
1764 return sprmTDxaCol;
1765 }
1766 break;
1767 }
1768 return sprmNil;
1769}
1770
1772 m_pIo(pIoClass),
1773 m_pFirstBand(nullptr),
1774 m_pActBand(nullptr),
1775 m_pTableNd(nullptr),
1776 m_pTabLines(nullptr),
1777 m_pTabLine(nullptr),
1778 m_pTabBoxes(nullptr),
1779 m_pTabBox(nullptr),
1780 m_pCurrentWWCell(nullptr),
1781 m_nRows(0),
1782 m_nDefaultSwCols(0),
1783 m_nBands(0),
1784 m_nMinLeft(0),
1785 m_nMaxRight(0),
1786 m_nSwWidth(0),
1787 m_nPreferredWidth(0),
1788 m_nPercentWidth(0),
1789 m_bOk(true),
1790 m_bClaimLineFormat(false),
1791 m_eOri(text::HoriOrientation::LEFT),
1792 m_bIsBiDi(false),
1793 m_nCurrentRow(0),
1794 m_nCurrentBandRow(0),
1795 m_nCurrentCol(0),
1796 m_nRowsToRepeat(0),
1797 m_pTable(nullptr),
1798 m_pParentPos(nullptr),
1799 m_pFlyFormat(nullptr),
1800 m_aItemSet(m_pIo->m_rDoc.GetAttrPool(),svl::Items<RES_FRMATR_BEGIN,RES_FRMATR_END-1>)
1801{
1803
1804 static const sal_Int16 aOriArr[] =
1805 {
1806 text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1807 };
1808
1809 bool bOldVer = ww::IsSevenMinus(m_pIo->GetFib().GetFIBVersion());
1810 WW8_TablePos aTabPos;
1811
1812 WW8PLCFxSave1 aSave;
1813 m_pIo->m_xPlcxMan->GetPap()->Save( aSave );
1814
1815 WW8PLCFx_Cp_FKP* pPap = m_pIo->m_xPlcxMan->GetPapPLCF();
1816
1817 WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1818
1819 wwSprmParser aSprmParser(m_pIo->GetFib());
1820
1821 std::set<std::pair<WW8_CP, WW8_CP>> aPrevRes;
1822
1823 // process pPap until end of table found
1824 do
1825 {
1826 short nTabeDxaNew = SHRT_MAX;
1827 bool bTabRowJustRead = false;
1828 const sal_uInt8* pShadeSprm = nullptr;
1829 const sal_uInt8* pNewShadeSprm[3] = {nullptr, nullptr, nullptr};
1830 const sal_uInt8* pTableBorders = nullptr;
1831 sal_uInt16 nTableBordersLen = 0;
1832 const sal_uInt8* pTableBorders90 = nullptr;
1833 sal_uInt16 nTableBorders90Len = 0;
1834 // params, len
1835 std::vector<std::pair<const sal_uInt8*, sal_uInt16>> aTSetBrcs, aTSetBrc90s;
1836 WW8_TablePos *pTabPos = nullptr;
1837
1838 // search end of a tab row
1839 if(!(m_pIo->SearchRowEnd(pPap, nStartCp, m_pIo->m_nInTable)))
1840 {
1841 m_bOk = false;
1842 break;
1843 }
1844
1845 // Get the SPRM chains:
1846 // first from PAP and then from PCD (of the Piece Table)
1847 WW8PLCFxDesc aDesc;
1848 pPap->GetSprms( &aDesc );
1849 WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1850
1851 for (int nLoop = 0; nLoop < 2; ++nLoop)
1852 {
1853 const sal_uInt8* pParams;
1854 while (aSprmIter.GetSprms() && nullptr != (pParams = aSprmIter.GetCurrentParams()))
1855 {
1856 sal_uInt16 nId = aSprmIter.GetCurrentId();
1857 sal_Int32 nFixedLen = aSprmParser.DistanceToData(nId);
1858 sal_Int32 nL = aSprmParser.GetSprmSize(nId, aSprmIter.GetSprms(), aSprmIter.GetRemLen());
1859 sal_Int32 nLen = nL - nFixedLen;
1860 wwTableSprm eSprm = GetTableSprm(nId, m_pIo->GetFib().GetFIBVersion());
1861 switch (eSprm)
1862 {
1863 case sprmTTableWidth:
1864 {
1865 const sal_uInt8 b0 = pParams[0];
1866 const sal_uInt8 b1 = pParams[1];
1867 const sal_uInt8 b2 = pParams[2];
1868 if (b0 == 3) // Twips
1869 m_nPreferredWidth = b2 * 0x100 + b1;
1870 else if (b0 == 2) // percent in fiftieths of a percent
1871 {
1872 m_nPercentWidth = (b2 * 0x100 + b1);
1873 // MS documentation: non-negative, and 600% max
1874 if ( m_nPercentWidth >= 0 && m_nPercentWidth <= 30000 )
1875 m_nPercentWidth *= .02;
1876 else
1877 m_nPercentWidth = 100;
1878 }
1879 }
1880 break;
1881 case sprmTTextFlow:
1882 pNewBand->ProcessDirection(pParams);
1883 break;
1884 case sprmTFCantSplit:
1885 pNewBand->bCantSplit = *pParams;
1886 m_bClaimLineFormat = true;
1887 break;
1888 case sprmTTableBorders:
1889 pTableBorders = pParams; // process at end
1890 nTableBordersLen = nLen;
1891 break;
1892 case sprmTTableBorders90:
1893 pTableBorders90 = pParams; // process at end
1894 nTableBorders90Len = nLen;
1895 break;
1896 case sprmTTableHeader:
1897 // tdf#105570
1898 if ( m_nRowsToRepeat == m_nRows )
1899 m_nRowsToRepeat = (m_nRows + 1);
1900 break;
1901 case sprmTJc:
1902 // sprmTJc - Justification Code
1903 if (m_nRows == 0)
1904 m_eOri = aOriArr[*pParams & 0x3];
1905 break;
1906 case sprmTFBiDi:
1907 m_bIsBiDi = SVBT16ToUInt16(pParams) != 0;
1908 break;
1909 case sprmTDxaGapHalf:
1910 pNewBand->nGapHalf = static_cast<sal_Int16>(SVBT16ToUInt16( pParams ));
1911 break;
1912 case sprmTDyaRowHeight:
1913 pNewBand->nLineHeight = static_cast<sal_Int16>(SVBT16ToUInt16( pParams ));
1914 m_bClaimLineFormat = true;
1915 break;
1916 case sprmTDefTable:
1917 pNewBand->ReadDef(bOldVer, pParams, nLen);
1918 bTabRowJustRead = true;
1919 break;
1920 case sprmTDefTableShd:
1921 pShadeSprm = pParams;
1922 break;
1923 case sprmTDefTableNewShd:
1924 pNewShadeSprm[0] = pParams;
1925 break;
1926 case sprmTDefTableNewShd2nd:
1927 pNewShadeSprm[1] = pParams;
1928 break;
1929 case sprmTDefTableNewShd3rd:
1930 pNewShadeSprm[2] = pParams;
1931 break;
1932 case sprmTDxaLeft:
1933 // our Writer cannot shift single table lines
1934 // horizontally so we have to find the smallest
1935 // parameter (meaning the left-most position) and then
1936 // shift the whole table to that margin (see below)
1937 {
1938 short nDxaNew = static_cast<sal_Int16>(SVBT16ToUInt16( pParams ));
1939 if( nDxaNew < nTabeDxaNew )
1940 nTabeDxaNew = nDxaNew;
1941 }
1942 break;
1943 case sprmTSetBrc:
1944 aTSetBrcs.emplace_back(pParams, nLen); // process at end
1945 break;
1946 case sprmTSetBrc90:
1947 aTSetBrc90s.emplace_back(pParams, nLen); // process at end
1948 break;
1949 case sprmTDxaCol:
1950 pNewBand->ProcessSprmTDxaCol(pParams);
1951 break;
1952 case sprmTInsert:
1953 pNewBand->ProcessSprmTInsert(pParams);
1954 break;
1955 case sprmTDelete:
1956 pNewBand->ProcessSprmTDelete(pParams);
1957 break;
1958 case sprmTCellPaddingDefault:
1959 pNewBand->ProcessSpacing(pParams);
1960 break;
1961 case sprmTCellPadding:
1962 pNewBand->ProcessSpecificSpacing(pParams);
1963 break;
1964 default:
1965 ;
1966 }
1967 aSprmIter.advance();
1968 }
1969
1970 if( !nLoop )
1971 {
1972 pPap->GetPCDSprms( aDesc );
1973 aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1974 }
1975 }
1976
1977 // WW-Tables can contain Fly-changes. For this abort tables here
1978 // and start again. *pPap is still before TabRowEnd, so TestApo()
1979 // can be called with the last parameter set to false and therefore
1980 // take effect.
1981
1982 if (bTabRowJustRead)
1983 {
1984 // Some SPRMs need to be processed *after* ReadDef is called
1985 // so they were saved up until here
1986 if (pShadeSprm)
1987 pNewBand->ReadShd(pShadeSprm);
1988 if (pNewShadeSprm[0])
1989 pNewBand->ReadNewShd(pNewShadeSprm[0], bOldVer, /*nStart=*/0);
1990 if (pNewShadeSprm[1])
1991 pNewBand->ReadNewShd(pNewShadeSprm[1], bOldVer, /*nStart=*/22);
1992 if (pNewShadeSprm[2])
1993 pNewBand->ReadNewShd(pNewShadeSprm[2], bOldVer, /*nStart=*/44);
1994 if (pTableBorders90)
1995 pNewBand->ProcessSprmTTableBorders(9, pTableBorders90, nTableBorders90Len);
1996 else if (pTableBorders)
1997 pNewBand->ProcessSprmTTableBorders(bOldVer ? 6 : 8,
1998 pTableBorders, nTableBordersLen);
1999 for (const auto& a : aTSetBrcs)
2000 pNewBand->ProcessSprmTSetBRC(bOldVer ? 6 : 8, a.first, a.second);
2001 for (const auto& a : aTSetBrc90s)
2002 pNewBand->ProcessSprmTSetBRC(9, a.first, a.second);
2003 }
2004
2005 if( nTabeDxaNew < SHRT_MAX )
2006 {
2007 short* pCenter = pNewBand->nCenter;
2008 short firstDxaCenter = *pCenter;
2009 for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
2010 {
2011 // #i30298# Use sprmTDxaLeft to adjust the left indent
2012 // #i40461# Use dxaGapHalf during calculation
2013 *pCenter +=
2014 (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
2015 }
2016 }
2017
2018 if (!m_pActBand)
2019 m_pActBand = m_pFirstBand = pNewBand;
2020 else
2021 {
2022 m_pActBand->pNextBand = pNewBand;
2023 m_pActBand = pNewBand;
2024 }
2025 m_nBands++;
2026
2027 pNewBand = new WW8TabBandDesc;
2028
2029 m_nRows++;
2030 m_pActBand->nRows++;
2031
2032 //Seek our pap to its next block of properties
2033 WW8PLCFxDesc aRes;
2034 aRes.pMemPos = nullptr;
2035 aRes.nStartPos = nStartCp;
2036
2037 if (!(pPap->SeekPos(aRes.nStartPos)))
2038 {
2039 aRes.nEndPos = WW8_CP_MAX;
2040 pPap->SetDirty(true);
2041 }
2042 pPap->GetSprms(&aRes);
2043 pPap->SetDirty(false);
2044
2045 //Are we at the end of available properties
2046 if (
2047 !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
2048 aRes.nStartPos == WW8_CP_MAX
2049 )
2050 {
2051 m_bOk = false;
2052 break;
2053 }
2054
2055 //Are we still in a table cell
2056 SprmResult aParamsRes = HasTabCellSprm(pPap, bOldVer);
2057 const sal_uInt8* pParams = aParamsRes.pSprm;
2058 SprmResult aLevelRes = pPap->HasSprm(0x6649);
2059 const sal_uInt8 *pLevel = aLevelRes.pSprm;
2060 // InTable
2061 if (!pParams || aParamsRes.nRemainingData < 1 || (1 != *pParams) ||
2062 (pLevel && aLevelRes.nRemainingData >= 1 && (*pLevel <= m_pIo->m_nInTable)))
2063 {
2064 break;
2065 }
2066
2067 //Get the end of row new table positioning data
2068 WW8_CP nMyStartCp=nStartCp;
2069 if (m_pIo->SearchRowEnd(pPap, nMyStartCp, m_pIo->m_nInTable))
2070 if (m_pIo->ParseTabPos(&aTabPos, pPap))
2071 pTabPos = &aTabPos;
2072
2073 //Move back to this cell
2074 aRes.pMemPos = nullptr;
2075 aRes.nStartPos = nStartCp;
2076
2077 // PlcxMan currently points too far ahead so we need to bring
2078 // it back to where we are trying to make a table
2079 m_pIo->m_xPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2080 m_pIo->m_xPlcxMan->GetPap()->nCpOfs = aRes.nCpOfs;
2081 if (!(pPap->SeekPos(aRes.nStartPos)))
2082 {
2083 aRes.nEndPos = WW8_CP_MAX;
2084 pPap->SetDirty(true);
2085 }
2086 pPap->GetSprms(&aRes);
2087 pPap->SetDirty(false);
2088
2089 //Does this row match up with the last row closely enough to be
2090 //considered part of the same table
2091 ApoTestResults aApo = m_pIo->TestApo(m_pIo->m_nInTable + 1, false, pTabPos);
2092
2093 /*
2094 ##513##, #79474# If this is not sufficient, then we should look at
2095 sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2096 part of this table, but instead is an absolutely positioned table
2097 outside of this one
2098 */
2099 if (aApo.mbStopApo)
2100 break;
2101 if (aApo.mbStartApo)
2102 {
2103 //if there really is a fly here, and not a "null" fly then break.
2104 if (m_pIo->ConstructApo(aApo, pTabPos))
2105 break;
2106 }
2107
2108 auto aBounds(std::make_pair(aRes.nStartPos, aRes.nEndPos));
2109 if (!aPrevRes.insert(aBounds).second) //already seen these bounds, infinite loop
2110 {
2111 SAL_WARN("sw.ww8", "WW8TabDesc, loop in paragraph property chain");
2112 break;
2113 }
2114 nStartCp = aRes.nEndPos;
2115 }
2116 while(true);
2117
2118 if( m_bOk )
2119 {
2120 if( m_pActBand->nRows > 1 )
2121 {
2122 // last band has more than 1 cell
2123 delete pNewBand;
2124 pNewBand = new WW8TabBandDesc( *m_pActBand ); // create new
2125 m_pActBand->nRows--; // because of special treatment of border defaults
2126 pNewBand->nRows = 1;
2127 m_pActBand->pNextBand = pNewBand; // append at the end
2128 m_nBands++;
2129 pNewBand = nullptr; // do not delete
2130 }
2131 CalcDefaults();
2132 }
2133 delete pNewBand;
2134
2135 m_pIo->m_xPlcxMan->GetPap()->Restore( aSave );
2136}
2137
2139{
2141 while(pR)
2142 {
2143 WW8TabBandDesc* pR2 = pR->pNextBand;
2144 delete pR;
2145 pR = pR2;
2146 }
2147
2148 delete m_pParentPos;
2149}
2150
2152{
2153 short nMinCols = SHRT_MAX;
2154 WW8TabBandDesc* pR;
2155
2156 m_nMinLeft = SHRT_MAX;
2157 m_nMaxRight = SHRT_MIN;
2158
2159 /*
2160 If we are an honestly inline centered table, then the normal rules of
2161 engagement for left and right margins do not apply. The multiple rows are
2162 centered regardless of the actual placement of rows, so we cannot have
2163 mismatched rows as is possible in other configurations.
2164
2165 e.g. change the example bugdoc in word from text wrapping of none (inline)
2166 to around (in frame (bApo)) and the table splits into two very disjoint
2167 rows as the beginning point of each row are very different
2168 */
2169 if ((!m_pIo->InLocalApo()) && (m_eOri == text::HoriOrientation::CENTER))
2170 {
2171 for (pR = m_pFirstBand; pR; pR = pR->pNextBand)
2172 for( short i = pR->nWwCols; i >= 0; --i)
2173 pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2174 }
2175
2176 // First loop: find outermost L and R borders
2177 for( pR = m_pFirstBand; pR; pR = pR->pNextBand )
2178 {
2179 if( pR->nCenter[0] < m_nMinLeft )
2180 m_nMinLeft = pR->nCenter[0];
2181
2182 // Following adjustment moves a border and then uses it to find width
2183 // of next cell, so collect current widths, to avoid situation when width
2184 // adjustment to too narrow cell makes next cell have negative width
2185 short nOrigWidth[MAX_COL + 1];
2186 for( short i = 0; i < pR->nWwCols; i++ )
2187 {
2188 nOrigWidth[i] = pR->nCenter[i+1] - pR->nCenter[i];
2189 }
2190
2191 for( short i = 0; i < pR->nWwCols; i++ )
2192 {
2193 /*
2194 If the margins are so large as to make the displayable
2195 area inside them smaller than the minimum allowed then adjust the
2196 width to fit. But only do it if the two cells are not the exact
2197 same value, if they are then the cell does not really exist and will
2198 be blended together into the same cell through the use of the
2199 nTrans(late) array.
2200 #i28333# If the nGapHalf is greater than the cell width best to ignore it
2201 */
2202 int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2203 if (nCellWidth != nOrigWidth[i])
2204 {
2205 if (nOrigWidth[i] == 0)
2206 nCellWidth = 0; // restore zero-width "cell"
2207 else if ((pR->nGapHalf >= nCellWidth) && (pR->nGapHalf < nOrigWidth[i]))
2208 nCellWidth = pR->nGapHalf + 1; // avoid false ignore
2209 else if ((nCellWidth <= 0) && (nOrigWidth[i] > 0))
2210 nCellWidth = 1; // minimal non-zero width to minimize distortion
2211 }
2212 if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2213 {
2214 nCellWidth = MINLAY + pR->nGapHalf * 2;
2215 }
2216 pR->nCenter[i + 1] = pR->nCenter[i] + nCellWidth;
2217 }
2218
2219 if( pR->nCenter[pR->nWwCols] > m_nMaxRight )
2220 m_nMaxRight = pR->nCenter[pR->nWwCols];
2221 }
2223
2224 // If the table is right aligned we need to align all rows to the
2225 // row that has the furthest right point
2226
2227 if(m_eOri == text::HoriOrientation::RIGHT)
2228 {
2229 for( pR = m_pFirstBand; pR; pR = pR->pNextBand )
2230 {
2231 int adjust = m_nMaxRight - pR->nCenter[pR->nWwCols];
2232 for( short i = 0; i < pR->nWwCols + 1; i++ )
2233 {
2234 pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2235 }
2236
2237 }
2238 }
2239
2240 // 2. pass: Detect number of writer columns. This can exceed the count
2241 // of columns in WW by 2, because SW in contrast to WW does not provide
2242 // fringed left and right borders and has to fill with empty boxes.
2243 // Non existent cells can reduce the number of columns.
2244
2245 // 3. pass: Replace border with defaults if needed
2246 for( pR = m_pFirstBand ; pR; pR = pR->pNextBand )
2247 {
2248 if( !pR->pTCs )
2249 {
2250 pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2251 }
2252 for (int k = 0; k < pR->nWwCols; ++k)
2253 {
2254 WW8_TCell& rT = pR->pTCs[k];
2255 for (int i = 0; i < 4; ++i)
2256 {
2257 if (rT.rgbrc[i].brcType()==0)
2258 {
2259 // if shadow is set, its invalid
2260 int j = i;
2261 switch( i )
2262 {
2263 case 0:
2264 // outer top / horizontally inside
2265 j = (pR == m_pFirstBand) ? 0 : 4;
2266 break;
2267 case 1:
2268 // outer left / vertically inside
2269 j = k ? 5 : 1;
2270 break;
2271 case 2:
2272 // outer bottom / horizontally inside
2273 j = pR->pNextBand ? 4 : 2;
2274 break;
2275 case 3:
2276 // outer right / vertically inside
2277 j = (k == pR->nWwCols - 1) ? 3 : 5;
2278 break;
2279 }
2280 // merge with above defaults
2281 rT.rgbrc[i] = pR->aDefBrcs[j];
2282 }
2283 }
2284 }
2285 }
2286
2287 for( pR = m_pFirstBand; pR; pR = pR->pNextBand )
2288 {
2289 pR->nSwCols = pR->nWwCols;
2290 pR->bLEmptyCol = pR->nCenter[0] - m_nMinLeft >= MINLAY;
2291 pR->bREmptyCol = (m_nMaxRight - pR->nCenter[pR->nWwCols]) >= MINLAY;
2292
2293 short nAddCols = short(pR->bLEmptyCol) + short(pR->bREmptyCol);
2294 sal_uInt16 i;
2295 sal_uInt16 j = ( pR->bLEmptyCol ) ? 1 : 0;
2296 for (i = 0; i < pR->nWwCols; ++i)
2297 {
2298 pR->nTransCell[i] = static_cast<sal_Int8>(j);
2299 if ( pR->nCenter[i] < pR->nCenter[i+1] )
2300 {
2301 pR->bExist[i] = true;
2302 j++;
2303 }
2304 else
2305 {
2306 pR->bExist[i] = false;
2307 nAddCols--;
2308 }
2309 }
2310
2311 OSL_ENSURE(i,"no columns in row ?");
2312
2313 /*
2314 If the last cell was "false" then there is no valid cell following it,
2315 so the default mapping forward won't work. So map it (and
2316 contiguous invalid cells backwards to the last valid cell instead.)
2317 */
2318 if (i && !pR->bExist[i-1])
2319 {
2320 sal_uInt16 k=i-1;
2321 while (k && !pR->bExist[k])
2322 k--;
2323 for (sal_uInt16 n=k+1;n<i;n++)
2324 pR->nTransCell[n] = pR->nTransCell[k];
2325 }
2326
2327 pR->nTransCell[i++] = static_cast<sal_Int8>(j++); // Can exceed by 2 among other
2328 pR->nTransCell[i] = static_cast<sal_Int8>(j); // things because of bREmptyCol
2329
2330 pR->nSwCols = pR->nSwCols + nAddCols;
2331 if( pR->nSwCols < nMinCols )
2332 nMinCols = pR->nSwCols;
2333 }
2334
2335 if ((m_nMinLeft && !m_bIsBiDi && text::HoriOrientation::LEFT == m_eOri) ||
2336 (m_nMinLeft != -108 && m_bIsBiDi && text::HoriOrientation::RIGHT == m_eOri)) // Word sets the first nCenter value to -108 when no indent is used
2337 m_eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2338
2339 m_nDefaultSwCols = nMinCols; // because inserting cells is cheaper than merging
2340 if( m_nDefaultSwCols == 0 )
2341 m_bOk = false;
2344 OSL_ENSURE( m_pActBand, "pActBand is 0" );
2345}
2346
2348{
2349 SwFrameFormat* pApply = pFrameFormat;
2350 if (!pApply )
2351 pApply = m_pTable->GetFrameFormat();
2352 OSL_ENSURE(pApply,"No frame");
2353 pApply->SetFormatAttr(m_aItemSet);
2354 if (pFrameFormat)
2355 {
2356 SwFormatFrameSize aSize = pFrameFormat->GetFrameSize();
2358 aSize.SetHeight(MINLAY);
2359 pFrameFormat->SetFormatAttr(aSize);
2360 m_pTable->GetFrameFormat()->SetFormatAttr(SwFormatHoriOrient(0,text::HoriOrientation::FULL));
2361 }
2362}
2363
2365 const SwNode &rNode)
2366{
2367 OSL_ENSURE(!maSegments.empty(),
2368 "should not be possible, must be at least one segment");
2369 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.GetNode()))
2370 maSegments.back().maStart.Assign(rNode);
2371}
2372
2374{
2376
2377 // if there is already some content on the Node append new node to ensure
2378 // that this content remains ABOVE the table
2379 SwPosition* pPoint = m_pIo->m_pPaM->GetPoint();
2380 bool bInsNode = pPoint->GetContentIndex() != 0;
2381 bool bSetMinHeight = false;
2382
2383 /*
2384 #i8062#
2385 Set fly anchor to its anchor pos, so that if a table starts immediately
2386 at this position a new node will be inserted before inserting the table.
2387 */
2388 SwFrameFormat* pFormat = (!bInsNode && m_pIo->m_xFormatOfJustInsertedApo)
2389 ? m_pIo->m_xFormatOfJustInsertedApo->GetFormat() : nullptr;
2390 if (pFormat)
2391 {
2392 const SwPosition* pAPos =
2393 pFormat->GetAnchor().GetContentAnchor();
2394 if (pAPos && pAPos->GetNode() == pPoint->GetNode())
2395 {
2396 bInsNode = true;
2397 bSetMinHeight = true;
2398
2399 SwFormatSurround aSur(pFormat->GetSurround());
2400 aSur.SetAnchorOnly(true);
2401 pFormat->SetFormatAttr(aSur);
2402 }
2403 }
2404
2405 if (bSetMinHeight)
2406 {
2407 // minimize Fontsize to minimize height growth of the header/footer
2408 // set font size to 1 point to minimize y-growth of Hd/Ft
2410 m_pIo->NewAttr( aSz );
2411 m_pIo->m_xCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2412 }
2413
2414 if (bInsNode)
2415 m_pIo->AppendTextNode(*pPoint);
2416
2418
2419 // Because SW cannot handle multi-page floating frames,
2420 // _any unnecessary_ floating tables have been converted to inline.
2421 tools::Long nLeft = 0;
2422 if (m_pIo->m_xSFlyPara && !m_pIo->m_xSFlyPara->GetFlyFormat())
2423 {
2424 // Get the table orientation from the fly
2425 // Do we also need to check m_pIo->m_xSFlyPara->bTogglePos/IsPosToggle()? [Probably not - layout-only concern]
2426 const bool bAdjustMargin = m_pIo->m_xSFlyPara->eHRel == text::RelOrientation::PAGE_FRAME || m_pIo->m_xSFlyPara->nXPos;
2427 const bool bIsInsideMargin = m_bIsBiDi ? m_pIo->m_xSFlyPara->eHAlign == text::HoriOrientation::RIGHT
2428 : m_pIo->m_xSFlyPara->eHAlign == text::HoriOrientation::LEFT;
2429 if ( bIsInsideMargin && bAdjustMargin )
2430 m_eOri = text::HoriOrientation::LEFT_AND_WIDTH;
2431 else if ( m_pIo->m_xSFlyPara->eHAlign != text::HoriOrientation::NONE )
2432 m_eOri = m_pIo->m_xSFlyPara->eHAlign;
2433 if ( m_eOri == text::HoriOrientation::LEFT_AND_WIDTH )
2434 {
2435 nLeft = m_pIo->m_xSFlyPara->nXPos;
2436 if ( m_pIo->m_xSFlyPara->eHRel == text::RelOrientation::PAGE_FRAME )
2437 {
2438 if ( !m_bIsBiDi )
2440 else
2442 }
2443 }
2444 }
2445
2446 // The table is small: The number of columns is the lowest count of
2447 // columns of the origin, because inserting is faster than deleting.
2448 // The number of rows is the count of bands because (identically)
2449 // rows of a band can be duplicated easy.
2452 *m_xTmpPos->GetPoint(), m_nBands, m_nDefaultSwCols, m_eOri );
2453
2454 OSL_ENSURE(m_pTable && m_pTable->GetFrameFormat(), "insert table failed");
2455 if (!m_pTable || !m_pTable->GetFrameFormat())
2456 return;
2457
2458 SwTableNode* pTableNode = m_pTable->GetTableNode();
2459 OSL_ENSURE(pTableNode, "no table node!");
2460 if (pTableNode)
2461 {
2463 *pTableNode);
2464 }
2465
2466 // Check if the node into which the table should be inserted already
2467 // contains a Pagedesc. If so that Pagedesc would be moved to the
2468 // row after the table, that would be wrong. So delete and
2469 // set later to the table format.
2470 if (SwTextNode *const pNd = m_xTmpPos->GetPoint()->GetNode().GetTextNode())
2471 {
2472 if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2473 {
2474 std::unique_ptr<SfxPoolItem> pSetAttr;
2475
2476 if (const SvxFormatBreakItem* pBreakItem = pSet->GetItemIfSet(RES_BREAK, false))
2477 {
2478 pSetAttr.reset(new SvxFormatBreakItem( *pBreakItem ));
2479 pNd->ResetAttr( RES_BREAK );
2480 }
2481
2482 // eventually set the PageDesc/Break now to the table
2483 if (pSetAttr)
2484 {
2485 m_aItemSet.Put(std::move(pSetAttr));
2486 }
2487 }
2488 }
2489
2490 // total width of table
2492 {
2494 // Don't set relative width if the table is in a floating frame
2495 if ( m_nPercentWidth && (!m_pIo->m_xSFlyPara || !m_pIo->m_xSFlyPara->GetFlyFormat()) )
2496 aFrameSize.SetWidthPercent(m_nPercentWidth);
2497 m_pTable->GetFrameFormat()->SetFormatAttr(aFrameSize);
2498 m_aItemSet.Put(aFrameSize);
2499 }
2500
2502 m_bIsBiDi ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR );
2504
2505 if (text::HoriOrientation::LEFT_AND_WIDTH == m_eOri)
2506 {
2508 m_pIo->m_xSFlyPara->GetFlyFormat() && GetMinLeft())
2509 {
2510 //If we are inside a frame and we have a border, the frames
2511 //placement does not consider the tables border, which word
2512 //displays outside the frame, so adjust here.
2513 SwFormatHoriOrient aHori(m_pIo->m_xSFlyPara->GetFlyFormat()->GetHoriOrient());
2514 sal_Int16 eHori = aHori.GetHoriOrient();
2515 if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2516 (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2517 {
2518 //With multiple table, use last table settings. Perhaps
2519 //the maximum is what word does ?
2520 aHori.SetPos(m_pIo->m_xSFlyPara->nXPos + GetMinLeft());
2522 m_pIo->m_xSFlyPara->GetFlyFormat()->SetFormatAttr(aHori);
2523 }
2524 }
2525 else // Not directly in a floating frame.
2526 {
2527 //Historical note: If InLocalApo(), then this table is being placed in a floating
2528 //frame, and the frame matches the left and right *lines* of the
2529 //table, so the space to the left of the table isn't to be used
2530 //inside the frame, in word the dialog involved greys out the
2531 //ability to set the margin.
2533
2534 if (!m_bIsBiDi)
2535 nLeft += GetMinLeft();
2536 else
2537 {
2538 const short nTableWidth = m_nPreferredWidth ? m_nPreferredWidth : m_nSwWidth;
2540 nLeft = nLeft - nTableWidth - GetMinLeft();
2541 }
2542 aL.SetLeft(nLeft);
2543
2544 m_aItemSet.Put(aL);
2545 }
2546 }
2547
2550}
2551
2553{
2554 // init global Vars
2557
2558 m_pTableNd = const_cast<SwTableNode*>((*m_pTabLines)[0]->GetTabBoxes()[0]->
2559 GetSttNd()->FindTableNode());
2560 OSL_ENSURE( m_pTableNd, "Where is my table node" );
2561
2562 // #i69519# - Restrict rows to repeat to a decent value
2563 if ( m_nRowsToRepeat == o3tl::narrowing<sal_uInt16>(m_nRows) )
2564 m_nRowsToRepeat = 1;
2565
2567 // insert extra cells if needed and something like this
2568 AdjustNewBand();
2569
2571 m_pIo->m_xCtrlStck->SetAttr(*m_pIo->m_pPaM->GetPoint(), 0, false);
2572
2573 // now set the correct PaM and prepare first merger group if any
2575 aDup.Insert(*m_pIo->m_pPaM->GetPoint());
2576
2577 m_pIo->m_bWasTabRowEnd = false;
2578 m_pIo->m_bWasTabCellEnd = false;
2579}
2580
2582{
2583 short nRow;
2584
2586 {
2587 // insert current box into merge group if appropriate.
2588 // The algorithm must ensure proper row and column order in WW8SelBoxInfo!
2589 if( m_pActBand->pTCs )
2590 {
2591 for( short j = 0; j < m_pActBand->nRows; j++, nRow++ )
2592 for( short i = 0; i < m_pActBand->nWwCols; i++ )
2593 {
2594 WW8SelBoxInfo* pActMGroup = nullptr;
2595
2596 // start a new merge group if appropriate
2597
2598 OSL_ENSURE(nRow < o3tl::narrowing<sal_uInt16>(m_pTabLines->size()),
2599 "Too few lines, table ended early");
2600 if (nRow >= o3tl::narrowing<sal_uInt16>(m_pTabLines->size()))
2601 return;
2602 m_pTabLine = (*m_pTabLines)[ nRow ];
2604
2605 sal_uInt16 nCol = m_pActBand->nTransCell[ i ];
2606 if (!m_pActBand->bExist[i])
2607 continue;
2608 OSL_ENSURE(nCol < m_pTabBoxes->size(),
2609 "Too few columns, table ended early");
2610 if (nCol >= m_pTabBoxes->size())
2611 return;
2612 m_pTabBox = (*m_pTabBoxes)[nCol];
2613 WW8_TCell& rCell = m_pActBand->pTCs[ i ];
2614 // is this the left upper cell of a merge group ?
2615
2616 bool bMerge = false;
2617 if ( rCell.bVertRestart && !rCell.bMerged )
2618 bMerge = true;
2619 else if (rCell.bFirstMerged && m_pActBand->bExist[i])
2620 {
2621 // Some tests to avoid merging cells which previously were
2622 // declared invalid because of sharing the exact same dimensions
2623 // as their previous cell
2624
2625 //If there's anything underneath/above we're ok.
2626 if (rCell.bVertMerge || rCell.bVertRestart)
2627 bMerge = true;
2628 else
2629 {
2630 //If it's a hori merge only, and the only things in
2631 //it are invalid cells then it's already taken care
2632 //of, so don't merge.
2633 for (sal_uInt16 i2 = i+1; i2 < m_pActBand->nWwCols; i2++ )
2634 if (m_pActBand->pTCs[ i2 ].bMerged &&
2635 !m_pActBand->pTCs[ i2 ].bFirstMerged )
2636 {
2637 if (m_pActBand->bExist[i2])
2638 {
2639 bMerge = true;
2640 break;
2641 }
2642 }
2643 else
2644 break;
2645 }
2646 }
2647
2648 // remove numbering from cells that will be disabled in the merge
2649 if( rCell.bVertMerge && !rCell.bVertRestart )
2650 {
2651 SwPaM aPam( *m_pTabBox->GetSttNd(), 0 );
2652 aPam.GetPoint()->Adjust(SwNodeOffset(1));
2653 SwTextNode* pNd = aPam.GetPointNode().GetTextNode();
2654 while( pNd )
2655 {
2656 pNd->SetCountedInList( false );
2657
2658 aPam.GetPoint()->Adjust(SwNodeOffset(1));
2659 pNd = aPam.GetPointNode().GetTextNode();
2660 }
2661 }
2662
2663 if (bMerge)
2664 {
2665 short nX1 = m_pActBand->nCenter[ i ];
2666 short nWidth = m_pActBand->nWidth[ i ];
2667
2668 // 2. create current merge group
2669 pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2670
2671 // determine size of new merge group
2672 // before inserted the new merge group.
2673 // Needed to correctly locked previously created merge groups.
2674 // Calculate total width and set
2675 short nSizCell = m_pActBand->nWidth[ i ];
2676 for (sal_uInt16 i2 = i+1; i2 < m_pActBand->nWwCols; i2++ )
2677 if (m_pActBand->pTCs[ i2 ].bMerged &&
2678 !m_pActBand->pTCs[ i2 ].bFirstMerged )
2679 {
2680 nSizCell = nSizCell + m_pActBand->nWidth[ i2 ];
2681 }
2682 else
2683 break;
2684 pActMGroup->m_nGroupWidth = nSizCell;
2685
2686 // locked previously created merge groups,
2687 // after determining the size for the new merge group.
2688 // 1. If necessary close old merge group(s) that overlap
2689 // the X-area of the new group
2690 for (;;)
2691 {
2693 nX1, pActMGroup->m_nGroupWidth, false );
2694 if (p == nullptr)
2695 {
2696 break;
2697 }
2698 p->m_bGroupLocked = true;
2699 }
2700
2701 // 3. push to group array
2702 m_MergeGroups.push_back(std::unique_ptr<WW8SelBoxInfo>(pActMGroup));
2703 }
2704
2705 // if necessary add the current box to a merge group
2706 // (that can be a newly created or another group)
2707 UpdateTableMergeGroup( rCell, pActMGroup, m_pTabBox, i );
2708 }
2709 }
2710 }
2711}
2712
2713//There is a limbo area in word at the end of the row marker
2714//where properties can live in word, there is no location in
2715//writer equivalent, so try and park the cursor in the best
2716//match, see #i23022#/#i18644#
2718{
2719 SwTableBox *pTabBox2 = nullptr;
2720 short nRow = m_nCurrentRow + 1;
2721 if (nRow < o3tl::narrowing<sal_uInt16>(m_pTabLines->size()))
2722 {
2723 if (SwTableLine *pLine = (*m_pTabLines)[nRow])
2724 {
2725 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2726 pTabBox2 = rBoxes.empty() ? nullptr : rBoxes.front();
2727 }
2728 }
2729
2730 if (!pTabBox2 || !pTabBox2->GetSttNd())
2731 {
2733 return;
2734 }
2735
2736 SwNodeOffset nSttNd = pTabBox2->GetSttIdx() + 1,
2737 nEndNd = pTabBox2->GetSttNd()->EndOfSectionIndex();
2738
2739 if (m_pIo->m_pPaM->GetPoint()->GetNodeIndex() != nSttNd)
2740 {
2741 do
2742 {
2743 m_pIo->m_pPaM->GetPoint()->Assign(nSttNd);
2744 }
2745 while (m_pIo->m_pPaM->GetPointNode().GetNodeType() != SwNodeType::Text && ++nSttNd < nEndNd);
2746
2749 }
2750}
2751
2753{
2754 OSL_ENSURE(m_xTmpPos && m_pIo, "I've forgotten where the table is anchored");
2755 if (m_xTmpPos && m_pIo)
2756 *m_pIo->m_pPaM->GetPoint() = *m_xTmpPos->GetPoint();
2757}
2758
2760{
2761 m_pIo->m_xRedlineStack->closeall(*m_pIo->m_pPaM->GetPoint());
2762
2763 // ofz#38011 drop m_pLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
2764 // place, or somewhere close if that place got destroyed
2765 std::shared_ptr<SwUnoCursor> xLastAnchorCursor(m_pIo->m_oLastAnchorPos ? m_pIo->m_rDoc.CreateUnoCursor(*m_pIo->m_oLastAnchorPos) : nullptr);
2766 m_pIo->m_oLastAnchorPos.reset();
2767
2768 SwTableNode* pTableNode = m_pTable->GetTableNode();
2769 SwDeleteListener aListener(*pTableNode);
2771
2772 if (xLastAnchorCursor)
2773 m_pIo->m_oLastAnchorPos.emplace(*xLastAnchorCursor->GetPoint());
2774
2776 m_pIo->m_xCtrlStck->SetAttr( *m_pIo->m_pPaM->GetPoint(), 0, false);
2777
2779 m_xTmpPos.reset();
2780
2781 aDup.Insert(*m_pIo->m_pPaM->GetPoint());
2782
2783 m_pIo->m_bWasTabRowEnd = false;
2784 m_pIo->m_bWasTabCellEnd = false;
2785
2787
2788 if (aListener.WasDeleted())
2789 throw std::runtime_error("table unexpectedly destroyed by applying redlines");
2790
2791 MergeCells();
2792
2793 // if needed group cells together that should be merged
2794 if (m_MergeGroups.empty())
2795 return;
2796
2797 // process all merge groups one by one
2798 for (auto const& groupIt : m_MergeGroups)
2799 {
2800 if((1 < groupIt->size()) && groupIt->row(0)[0])
2801 {
2802 SwFrameFormat* pNewFormat = groupIt->row(0)[0]->ClaimFrameFormat();
2803 pNewFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Variable, groupIt->m_nGroupWidth, 0));
2804 const sal_uInt16 nRowSpan = groupIt->rowsCount();
2805 for (sal_uInt16 n = 0; n < nRowSpan; ++n)
2806 {
2807 auto& rRow = groupIt->row(n);
2808 for (size_t i = 0; i<rRow.size(); ++i)
2809 {
2810 const sal_Int32 nRowSpanSet = (n == 0) && (i == 0) ?
2811 nRowSpan :
2812 (-1 * (nRowSpan - n));
2813 SwTableBox* pCurrentBox = rRow[i];
2814 pCurrentBox->setRowSpan(nRowSpanSet);
2815
2816 if (i == 0)
2817 pCurrentBox->ChgFrameFormat(static_cast<SwTableBoxFormat*>(pNewFormat));
2818 else
2819 {
2820 SwFrameFormat* pFormat = pCurrentBox->ClaimFrameFormat();
2822 }
2823 }
2824 }
2825 }
2826 }
2828 m_MergeGroups.clear();
2829}
2830
2831// browse m_MergeGroups, detect the index of the first fitting group or -1 otherwise
2832
2833// Parameter: nXcenter = center position of asking box
2834// nWidth = width of asking box
2835// bExact = flag, if box has to fit into group
2836// or only has to touch
2837
2838WW8SelBoxInfo* WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact)
2839{
2840 if (!m_MergeGroups.empty())
2841 {
2842 // still valid area near the boundary
2843 const short nTolerance = 4;
2844 // box boundary
2845 short nX2 = nX1 + nWidth;
2846 // approximate group boundary
2847 short nGrX1;
2848 short nGrX2;
2849
2850 // improvement: search backwards
2851 for (short iGr = m_MergeGroups.size() - 1; iGr >= 0; --iGr)
2852 {
2853 // the currently inspected group
2854 WW8SelBoxInfo& rActGroup = *m_MergeGroups[ iGr ];
2855 if (!rActGroup.m_bGroupLocked)
2856 {
2857 // approximate group boundary with room (tolerance) to the *outside*
2858 nGrX1 = rActGroup.m_nGroupXStart - nTolerance;
2859 nGrX2 = rActGroup.m_nGroupXStart
2860 + rActGroup.m_nGroupWidth + nTolerance;
2861
2862 // If box fits report success
2863
2864 if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2865 {
2866 return &rActGroup;
2867 }
2868
2869 // does the box share areas with the group?
2870
2871 if( !bExact )
2872 {
2873 // successful if nX1 *or* nX2 are inside the group
2874 if( ( ( nX1 > nGrX1 )
2875 && ( nX1 < nGrX2 - 2*nTolerance ) )
2876 || ( ( nX2 > nGrX1 + 2*nTolerance )
2877 && ( nX2 < nGrX2 ) )
2878 // or nX1 and nX2 surround the group
2879 || ( ( nX1 <=nGrX1 )
2880 && ( nX2 >=nGrX2 ) ) )
2881 {
2882 return &rActGroup;
2883 }
2884 }
2885 }
2886 }
2887 }
2888 return nullptr;
2889}
2890
2891bool WW8TabDesc::IsValidCell(short nCol) const
2892{
2894 m_pActBand->bExist[nCol] &&
2896}
2897
2899{
2900 //e.g. #i19718#
2901 if (!m_pTabBox || !m_pTabBox->GetSttNd())
2902 {
2903 OSL_FAIL("Problem with table");
2904 return false;
2905 }
2906
2907 if (!IsValidCell(GetCurrentCol()))
2908 return false;
2909
2910 return m_pIo->m_pPaM->GetPoint()->GetNodeIndex() == m_pTabBox->GetSttIdx() + 1;
2911}
2912
2913void WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2914{
2915 OSL_ENSURE( m_pActBand, "pActBand is 0" );
2916 if (!m_pActBand)
2917 return;
2918
2919 sal_uInt16 nCol = m_pActBand->transCell(nWwCol);
2920
2922 {
2923 OSL_ENSURE(false, "Actual row bigger than expected." );
2924 if (bPam)
2926 return;
2927 }
2928
2929 m_pTabLine = (*m_pTabLines)[m_nCurrentRow];
2931
2932 if (nCol >= m_pTabBoxes->size())
2933 {
2934 if (bPam)
2935 {
2936 // The first paragraph in a cell with upper autospacing has upper
2937 // spacing set to 0
2938 if (
2940 !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing
2941 )
2942 {
2944 }
2945
2946 // The last paragraph in a cell with lower autospacing has lower
2947 // spacing set to 0
2948 if (m_pIo->m_bParaAutoAfter && !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing)
2950
2951 ParkPaM();
2952 }
2953 return;
2954 }
2955 m_pTabBox = (*m_pTabBoxes)[nCol];
2956 if( !m_pTabBox->GetSttNd() )
2957 {
2958 OSL_ENSURE(m_pTabBox->GetSttNd(), "Problems building the table");
2959 if (bPam)
2961 return;
2962 }
2963 if (!bPam)
2964 return;
2965
2966 m_pCurrentWWCell = &m_pActBand->pTCs[ nWwCol ];
2967
2968 // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2969 if(m_pIo->m_bParaAutoBefore && m_pIo->m_bFirstPara && !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing)
2971
2972 // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2973 if(m_pIo->m_bParaAutoAfter && !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing)
2975
2976 //We need to set the pPaM on the first cell, invalid
2977 //or not so that we can collect paragraph properties over
2978 //all the cells, but in that case on the valid cell we do not
2979 //want to reset the fmt properties
2980 SwNodeOffset nSttNd = m_pTabBox->GetSttIdx() + 1,
2981 nEndNd = m_pTabBox->GetSttNd()->EndOfSectionIndex();
2982 if (m_pIo->m_pPaM->GetPoint()->GetNodeIndex() != nSttNd)
2983 {
2984 do
2985 {
2986 m_pIo->m_pPaM->GetPoint()->Assign(nSttNd);
2987 }
2988 while (m_pIo->m_pPaM->GetPointNode().GetNodeType() != SwNodeType::Text && ++nSttNd < nEndNd);
2990 // Precautionally set now, otherwise the style is not set for cells
2991 // that are inserted for margin balancing.
2993 // because this cells are invisible helper constructions only to simulate
2994 // the frayed view of WW-tables we do NOT need SetTextFormatCollAndListLevel()
2995 }
2996
2997 // Better to turn Snap to Grid off for all paragraphs in tables
2998 SwPosition* pGridPos = m_pIo->m_pPaM->GetPoint();
2999 SwTextNode *pNd = pGridPos->GetNode().GetTextNode();
3000 if(!pNd)
3001 return;
3002
3003 const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_PARATR_SNAPTOGRID);
3004 const SvxParaGridItem &rSnapToGrid = static_cast<const SvxParaGridItem&>(rItm);
3005
3006 if(!rSnapToGrid.GetValue())
3007 return;
3008
3009 SvxParaGridItem aGridItem( rSnapToGrid );
3010 aGridItem.SetValue(false);
3011
3012 const sal_Int32 nEnd = pGridPos->GetContentIndex();
3013 pGridPos->SetContent(0);
3014 m_pIo->m_xCtrlStck->NewAttr(*pGridPos, aGridItem);
3015 pGridPos->SetContent(nEnd);
3016 m_pIo->m_xCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
3017}
3018
3019void WW8TabDesc::InsertCells( short nIns )
3020{
3021 m_pTabLine = (*m_pTabLines)[m_nCurrentRow];
3023 m_pTabBox = (*m_pTabBoxes)[0];
3024
3026 const_cast<SwTextFormatColl*>(m_pIo->m_pDfltTextFormatColl), nullptr, m_pTabBoxes->size(), nIns );
3027 // The third parameter contains the FrameFormat of the boxes.
3028 // Here it is possible to optimize to save (reduce) FrameFormats.
3029}
3030
3031void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3032{
3033 if( nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols )
3034 return; // faked cells -> no border
3035
3036 SvxBoxItem aFormatBox( RES_BOX );
3037 if (m_pActBand->pTCs) // neither Cell Border nor Default Border defined ?
3038 {
3039 WW8_TCell* pT = &m_pActBand->pTCs[nWwIdx];
3041 SwWW8ImplReader::SetBorder(aFormatBox, pT->rgbrc);
3042 }
3043
3045 {
3046 aFormatBox.SetDistance(
3048 SvxBoxItemLine::TOP);
3049 }
3050 else
3051 aFormatBox.SetDistance(m_pActBand->mnDefaultTop, SvxBoxItemLine::TOP);
3053 {
3054 aFormatBox.SetDistance(
3056 SvxBoxItemLine::BOTTOM);
3057 }
3058 else
3059 aFormatBox.SetDistance(m_pActBand->mnDefaultBottom,SvxBoxItemLine::BOTTOM);
3060
3061 // nGapHalf for WW is a *horizontal* gap between table cell and content.
3062 short nLeftDist =
3064 short nRightDist =
3067 {
3068 aFormatBox.SetDistance(
3070 SvxBoxItemLine::LEFT);
3071 }
3072 else
3073 aFormatBox.SetDistance(nLeftDist, SvxBoxItemLine::LEFT);
3075 {
3076 aFormatBox.SetDistance(
3078 SvxBoxItemLine::RIGHT);
3079 }
3080 else
3081 aFormatBox.SetDistance(nRightDist,SvxBoxItemLine::RIGHT);
3082
3083 pBox->GetFrameFormat()->SetFormatAttr(aFormatBox);
3084}
3085
3086void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3087{
3088 if( nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols )
3089 return; // faked cells -> no color
3090
3091 bool bFound=false;
3092 if (m_pActBand->pNewSHDs && m_pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3093 {
3094 Color aColor(m_pActBand->pNewSHDs[nWwIdx]);
3096 bFound = true;
3097 }
3098
3099 //If there was no new shades, or no new shade setting
3100 if (m_pActBand->pSHDs && !bFound)
3101 {
3102 WW8_SHD& rSHD = m_pActBand->pSHDs[nWwIdx];
3103 if (!rSHD.GetValue()) // auto
3104 return;
3105
3106 SwWW8Shade aSh( m_pIo->m_bVer67, rSHD );
3108 }
3109}
3110
3111static SvxFrameDirection MakeDirection(sal_uInt16 nCode, bool bIsBiDi)
3112{
3113 SvxFrameDirection eDir = SvxFrameDirection::Environment;
3114 // 1: Asian layout with rotated CJK characters
3115 // 5: Asian layout
3116 // 3: Western layout rotated by 90 degrees
3117 // 4: Western layout
3118 switch (nCode)
3119 {
3120 default:
3121 OSL_ENSURE(eDir == SvxFrameDirection::Environment, "unknown direction code, maybe it's a bitfield");
3122 [[fallthrough]];
3123 case 3:
3124 eDir = SvxFrameDirection::Vertical_LR_BT;
3125 break;
3126 case 5:
3127 eDir = SvxFrameDirection::Vertical_RL_TB;
3128 break;
3129 case 1:
3130 eDir = SvxFrameDirection::Vertical_RL_TB;
3131 break;
3132 case 4:
3133 eDir = bIsBiDi ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB; // #i38158# - Consider RTL tables
3134 break;
3135 }
3136 return eDir;
3137}
3138
3140{
3141 if (nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols)
3142 return;
3144 pBox->GetFrameFormat()->SetFormatAttr(aItem);
3145}
3146
3147void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3148{
3149 if( nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols )
3150 return;
3151
3152 sal_Int16 eVertOri=text::VertOrientation::TOP;
3153
3154 if( m_pActBand->pTCs )
3155 {
3156 WW8_TCell* pT = &m_pActBand->pTCs[nWwIdx];
3157 switch (pT->nVertAlign)
3158 {
3159 case 0:
3160 default:
3161 eVertOri = text::VertOrientation::TOP;
3162 break;
3163 case 1:
3164 eVertOri = text::VertOrientation::CENTER;
3165 break;
3166 case 2:
3167 eVertOri = text::VertOrientation::BOTTOM;
3168 break;
3169 }
3170 }
3171
3172 pBox->GetFrameFormat()->SetFormatAttr( SwFormatVertOrient(0,eVertOri) );
3173}
3174
3176{
3177 if( m_pActBand->nSwCols > m_nDefaultSwCols ) // split cells
3179
3180 SetPamInCell( 0, false);
3181 OSL_ENSURE( m_pTabBoxes && m_pTabBoxes->size() == o3tl::narrowing<sal_uInt16>(m_pActBand->nSwCols),
3182 "Wrong column count in table" );
3183
3184 if( m_bClaimLineFormat )
3185 {
3186 m_pTabLine->ClaimFrameFormat(); // necessary because of cell height
3187 SwFormatFrameSize aF( SwFrameSize::Minimum, 0, 0 ); // default
3188
3189 if (m_pActBand->nLineHeight == 0) // 0 = Auto
3191 else
3192 {
3193 if (m_pActBand->nLineHeight < 0) // positive = min, negative = exact
3194 {
3197 }
3198 if (m_pActBand->nLineHeight < MINLAY) // invalid cell height
3200
3201 aF.SetHeight(m_pActBand->nLineHeight);// set min/exact height
3202 }
3204 }
3205
3206 //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3207 //we can split the row
3208 bool bSetCantSplit = m_pActBand->bCantSplit;
3210
3211 // if table is only a single row, and row is set as don't split, set the same value for the whole table.
3212 if (bSetCantSplit && m_pTabLines->size() == 1)
3214
3215 short i; // SW-Index
3216 short j; // WW-Index
3217 short nW; // Width
3219 j = m_pActBand->bLEmptyCol ? -1 : 0;
3220
3221 for( i = 0; i < m_pActBand->nSwCols; i++ )
3222 {
3223 // set cell width
3224 if( j < 0 )
3225 nW = m_pActBand->nCenter[0] - m_nMinLeft;
3226 else
3227 {
3228 //Set j to first non invalid cell
3229 while ((j < m_pActBand->nWwCols) && (!m_pActBand->bExist[j]))
3230 j++;
3231
3232 if( j < m_pActBand->nWwCols )
3233 nW = m_pActBand->nCenter[j+1] - m_pActBand->nCenter[j];
3234 else
3235 nW = m_nMaxRight - m_pActBand->nCenter[j];
3236 m_pActBand->nWidth[ j ] = nW;
3237 }
3238
3239 SwTableBox* pBox = (*m_pTabBoxes)[i];
3240 // could be reduced further by intelligent moving of FrameFormats
3241 pBox->ClaimFrameFormat();
3242
3243 SetTabBorders(pBox, j);
3244
3245 SvxBoxItem aCurrentBox(pBox->GetFrameFormat()->GetFormatAttr(RES_BOX));
3246 pBox->GetFrameFormat()->SetFormatAttr(aCurrentBox);
3247
3248 SetTabVertAlign(pBox, j);
3249 SetTabDirection(pBox, j);
3251 SetTabShades(pBox, j);
3252 j++;
3253
3254 aFS.SetWidth( nW );
3255 pBox->GetFrameFormat()->SetFormatAttr( aFS );
3256
3257 // skip non existing cells
3258 while( ( j < m_pActBand->nWwCols ) && !m_pActBand->bExist[j] )
3259 {
3261 j++;
3262 }
3263 }
3264}
3265
3267{
3269
3270 // new line/row
3271 if( m_pIo->m_bWasTabRowEnd )
3272 {
3273 // bWasTabRowEnd will be deactivated in
3274 // SwWW8ImplReader::ProcessSpecial()
3275
3276 sal_uInt16 iCol = GetLogicalWWCol();
3277 if (iCol < m_aNumRuleNames.size())
3278 {
3279 m_aNumRuleNames.erase(m_aNumRuleNames.begin() + iCol,
3280 m_aNumRuleNames.end());
3281 }
3282
3283 m_nCurrentCol = 0;
3284 m_nCurrentRow++;
3286 OSL_ENSURE( m_pActBand , "pActBand is 0" );
3287 if( m_pActBand )
3288 {
3289 if( m_nCurrentRow >= m_nRows ) // nothing to at end of table
3290 return;
3291
3292 bool bNewBand = m_nCurrentBandRow >= m_pActBand->nRows;
3293 if( bNewBand )
3294 { // new band needed ?
3297 OSL_ENSURE( m_pActBand, "pActBand is 0" );
3298 AdjustNewBand();
3299 }
3300 else
3301 {
3302 SwTableBox* pBox = (*m_pTabBoxes)[0];
3303 SwSelBoxes aBoxes;
3304 m_pIo->m_rDoc.InsertRow( SwTable::SelLineFromBox( pBox, aBoxes ) );
3305 }
3306 }
3307 }
3308 else
3309 { // new column ( cell )
3310 m_nCurrentCol++;
3311 }
3313
3314 // finish Annotated Level Numbering ?
3317}
3318
3319// if necessary register the box for the merge group for this column
3321 WW8SelBoxInfo* pActGroup,
3322 SwTableBox* pActBox,
3323 sal_uInt16 nCol )
3324{
3325 // check if the box has to be merged
3326 // If cell is the first one to be merged, a new merge group has to be provided.
3327 // E.g., it could be that a cell is the first one to be merged, but no
3328 // new merge group is provided, because the potential other cell to be merged
3329 // doesn't exist - see method <WW8TabDesc::MergeCells>.
3330 if ( !(m_pActBand->bExist[ nCol ] &&
3331 ( ( rCell.bFirstMerged && pActGroup ) ||
3332 rCell.bMerged ||
3333 rCell.bVertMerge ||
3334 rCell.bVertRestart )) )
3335 return;
3336
3337 // detect appropriate merge group
3338 WW8SelBoxInfo* pTheMergeGroup = nullptr;
3339 if( pActGroup )
3340 // assign group
3341 pTheMergeGroup = pActGroup;
3342 else
3343 {
3344 // find group
3345 pTheMergeGroup = FindMergeGroup(
3346 m_pActBand->nCenter[ nCol ], m_pActBand->nWidth[ nCol ], true );
3347 }
3348 if( pTheMergeGroup )
3349 {
3350 // add current box to merge group
3351 pTheMergeGroup->push_back(pActBox);
3352 }
3353}
3354
3355sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3356{
3357 sal_uInt16 nCol = 0;
3358 if( m_pActBand && m_pActBand->pTCs)
3359 {
3360 for( sal_uInt16 iCol = 1; iCol <= m_nCurrentCol && iCol <= m_pActBand->nWwCols; ++iCol )
3361 {
3362 if( !m_pActBand->pTCs[ iCol-1 ].bMerged )
3363 ++nCol;
3364 }
3365 }
3366 return nCol;
3367}
3368
3369// find name of numrule valid for current WW-COL
3371{
3372 sal_uInt16 nCol = GetLogicalWWCol();
3373 if (nCol < m_aNumRuleNames.size())
3374 return m_aNumRuleNames[nCol];
3375 return OUString();
3376}
3377
3378void WW8TabDesc::SetNumRuleName( const OUString& rName )
3379{
3380 sal_uInt16 nCol = GetLogicalWWCol();
3381 for (sal_uInt16 nSize = static_cast< sal_uInt16 >(m_aNumRuleNames.size()); nSize <= nCol; ++nSize)
3382 m_aNumRuleNames.emplace_back();
3383 m_aNumRuleNames[nCol] = rName;
3384}
3385
3387{
3388 // Entering a table so make sure the FirstPara flag gets set
3389 m_bFirstPara = true;
3390 // no recursive table, not with InsertFile in table or foot note
3391 if (m_bReadNoTable)
3392 return false;
3393
3394 if (m_xTableDesc)
3395 m_aTableStack.push(std::move(m_xTableDesc));
3396
3397 // #i33818# - determine absolute position object attributes,
3398 // if possible. It's needed for nested tables.
3399 std::unique_ptr<WW8FlyPara> pTableWFlyPara;
3400 WW8SwFlyPara* pTableSFlyPara( nullptr );
3401 // #i45301# - anchor nested table inside Writer fly frame
3402 // only at-character, if absolute position object attributes are available.
3403 // Thus, default anchor type is as-character anchored.
3404 RndStdIds eAnchor( RndStdIds::FLY_AS_CHAR );
3405 if ( m_nInTable )
3406 {
3407 WW8_TablePos* pNestedTabPos( nullptr );
3408 WW8_TablePos aNestedTabPos;
3409 WW8PLCFxSave1 aSave;
3410 m_xPlcxMan->GetPap()->Save( aSave );
3411 WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
3412 WW8_CP nMyStartCp = nStartCp;
3413 if ( SearchRowEnd( pPap, nMyStartCp, m_nInTable ) &&
3414 ParseTabPos( &aNestedTabPos, pPap ) )
3415 {
3416 pNestedTabPos = &aNestedTabPos;
3417 }
3418 m_xPlcxMan->GetPap()->Restore( aSave );
3419 if ( pNestedTabPos )
3420 {
3421 ApoTestResults aApo = TestApo( m_nInTable + 1, false, pNestedTabPos );
3422 pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3423 if ( pTableWFlyPara )
3424 {
3425 // <WW8SwFlyPara> constructor has changed - new 4th parameter
3426 // containing WW8 page top margin.
3427 pTableSFlyPara = new WW8SwFlyPara(*m_pPaM, *this, *pTableWFlyPara,
3431
3432 // #i45301# - anchor nested table Writer fly frame at-character
3433 eAnchor = RndStdIds::FLY_AT_CHAR;
3434 }
3435 }
3436 }
3437 // if first paragraph in table has break-before-page, transfer that setting to the table itself.
3438 else if( StyleExists(m_nCurrentColl) )
3439 {
3440 const SwFormat* pStyleFormat = m_vColl[m_nCurrentColl].m_pFormat;
3441 if( pStyleFormat && pStyleFormat->GetBreak().GetBreak() == SvxBreak::PageBefore )
3442 NewAttr( pStyleFormat->GetBreak() );
3443 }
3444
3445 m_xTableDesc.reset(new WW8TabDesc(this, nStartCp));
3446
3447 if( m_xTableDesc->Ok() )
3448 {
3449 int nNewInTable = m_nInTable + 1;
3450
3451 if ((eAnchor == RndStdIds::FLY_AT_CHAR)
3452 && !m_aTableStack.empty() && !InEqualApo(nNewInTable) )
3453 {
3454 m_xTableDesc->m_pParentPos = new SwPosition(*m_pPaM->GetPoint());
3456 // #i33818# - anchor the Writer fly frame for the nested table at-character.
3457 // #i45301#
3458 SwFormatAnchor aAnchor( eAnchor );
3459 aAnchor.SetAnchor( m_xTableDesc->m_pParentPos );
3460 aItemSet.Put( aAnchor );
3461 m_xTableDesc->m_pFlyFormat = m_rDoc.MakeFlySection( eAnchor,
3462 m_xTableDesc->m_pParentPos, &aItemSet);
3463 OSL_ENSURE( m_xTableDesc->m_pFlyFormat->GetAnchor().GetAnchorId() == eAnchor,
3464 "Not the anchor type requested!" );
3465 MoveInsideFly(m_xTableDesc->m_pFlyFormat);
3466 }
3467 m_xTableDesc->CreateSwTable();
3468 if (m_xTableDesc->m_pFlyFormat)
3469 {
3470 m_xTableDesc->SetSizePosition(m_xTableDesc->m_pFlyFormat);
3471 // #i33818# - Use absolute position object attributes,
3472 // if existing, and apply them to the created Writer fly frame.
3473 if ( pTableWFlyPara && pTableSFlyPara )
3474 {
3475 WW8FlySet aFlySet( *this, pTableWFlyPara.get(), pTableSFlyPara, false );
3476 SwFormatAnchor aAnchor( RndStdIds::FLY_AT_CHAR );
3477 aAnchor.SetAnchor( m_xTableDesc->m_pParentPos );
3478 aFlySet.Put( aAnchor );
3479 m_xTableDesc->m_pFlyFormat->SetFormatAttr( aFlySet );
3480 }
3481 else
3482 {
3483 SwFormatHoriOrient aHori =
3484 m_xTableDesc->m_pTable->GetFrameFormat()->GetHoriOrient();
3485 m_xTableDesc->m_pFlyFormat->SetFormatAttr(aHori);
3486 m_xTableDesc->m_pFlyFormat->SetFormatAttr( SwFormatSurround( css::text::WrapTextMode_NONE ) );
3487 }
3488 // #i33818# - The nested table doesn't have to leave
3489 // the table cell. Thus, the Writer fly frame has to follow the text flow.
3490 m_xTableDesc->m_pFlyFormat->SetFormatAttr( SwFormatFollowTextFlow( true ) );
3491 }
3492 else
3493 m_xTableDesc->SetSizePosition(nullptr);
3494 m_xTableDesc->UseSwTable();
3495 }
3496 else
3497 PopTableDesc();
3498
3499 // #i33818#
3500 delete pTableSFlyPara;
3501
3502 return m_xTableDesc != nullptr;
3503}
3504
3506{
3507 if (m_nInTable && m_xTableDesc)
3508 m_xTableDesc->TableCellEnd();
3509
3510 m_bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3511 m_bReadTable = false;
3512}
3513
3514void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16, const sal_uInt8* pData, short nLen)
3515{
3516 if( ( nLen > 0 ) && ( *pData == 1 ) )
3517 m_bWasTabCellEnd = true;
3518}
3519
3520void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm25
3521{
3522 if( ( nLen > 0 ) && ( *pData == 1 ) )
3523 m_bWasTabRowEnd = true;
3524}
3525
3527{
3528 if (m_xTableDesc && m_xTableDesc->m_pFlyFormat)
3529 {
3530 MoveOutsideFly(m_xTableDesc->m_pFlyFormat, *m_xTableDesc->m_pParentPos);
3531 }
3532
3533 m_xTableDesc.reset();
3534 if (!m_aTableStack.empty())
3535 {
3536 m_xTableDesc = std::move(m_aTableStack.top());
3537 m_aTableStack.pop();
3538 }
3539}
3540
3542{
3543 OSL_ENSURE(m_xTableDesc, "Panic, stop table with no table!");
3544 if (!m_xTableDesc)
3545 return;
3546
3547 // We are leaving a table so make sure the next paragraph doesn't think
3548 // it's the first paragraph
3549 m_bFirstPara = false;
3550
3551 m_xTableDesc->FinishSwTable();
3552 PopTableDesc();
3553
3554 m_bReadTable = true;
3555}
3556
3558{
3559 if( !m_xTableDesc )
3560 return false;
3561
3562 const WW8_TCell* pCell = m_xTableDesc->GetCurrentWWCell();
3563
3564 return !m_xTableDesc->IsValidCell( m_xTableDesc->GetCurrentCol() )
3565 || ( pCell
3566 && ( !pCell->bFirstMerged
3567 && ( pCell->bMerged
3568 || ( pCell->bVertMerge
3569 && !pCell->bVertRestart
3570 )
3571 )
3572 )
3573 );
3574}
3575
3576sal_uInt16 SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex ) const
3577{
3578 sal_uInt16 nRes = USHRT_MAX;
3579 if( !m_vColl.empty() )
3580 {
3581 for(sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); nI++ )
3582 if( m_vColl[ nI ].m_bValid
3583 && (nLFOIndex == m_vColl[ nI ].m_nLFOIndex) )
3584 nRes = nI;
3585 }
3586 return nRes;
3587}
3588
3589const SwFormat* SwWW8ImplReader::GetStyleWithOrgWWName( std::u16string_view rName ) const
3590{
3591 SwFormat* pRet = nullptr;
3592 if( !m_vColl.empty() )
3593 {
3594 for(sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); nI++ )
3595 if( m_vColl[ nI ].m_bValid
3596 && (rName == m_vColl[ nI ].GetOrgWWName()) )
3597 {
3598 pRet = m_vColl[ nI ].m_pFormat;
3599 break;
3600 }
3601 }
3602 return pRet;
3603}
3604
3605
3607{
3608 if( !mpParaSprms || !mnSprmsLen )
3609 return SprmResult();
3610
3612}
3613
3614void WW8RStyle::ImportSprms(sal_uInt8 *pSprms, short nLen, bool bPap)
3615{
3616 if (!nLen)
3617 return;
3618
3619 if( bPap )
3620 {
3621 mpParaSprms = pSprms; // for HasParaSprms()
3622 mnSprmsLen = nLen;
3623 }
3624
3625 WW8SprmIter aSprmIter(pSprms, nLen, maSprmParser);
3626 while (const sal_uInt8* pSprm = aSprmIter.GetSprms())
3627 {
3628#ifdef DEBUGSPRMREADER
3629 fprintf(stderr, "id is %x\n", aIter.GetCurrentId());
3630#endif
3631 mpIo->ImportSprm(pSprm, aSprmIter.GetRemLen(), aSprmIter.GetCurrentId());
3632 aSprmIter.advance();
3633 }
3634
3635 mpParaSprms = nullptr;
3636 mnSprmsLen = 0;
3637}
3638
3639void WW8RStyle::ImportSprms(std::size_t nPosFc, short nLen, bool bPap)
3640{
3641 if (!nLen)
3642 return;
3643
3644 if (checkSeek(*mpStStrm, nPosFc))
3645 {
3646 std::unique_ptr<sal_uInt8[]> pSprms( new sal_uInt8[nLen] );
3647 nLen = mpStStrm->ReadBytes(pSprms.get(), nLen);
3648 ImportSprms(pSprms.get(), nLen, bPap);
3649 }
3650}
3651
3652static short WW8SkipOdd(SvStream* pSt )
3653{
3654 if ( pSt->Tell() & 0x1 )
3655 {
3656 sal_uInt8 c;
3657 return pSt->ReadBytes( &c, 1 );
3658 }
3659 return 0;
3660}
3661
3662static short WW8SkipEven(SvStream* pSt )
3663{
3664 if (!(pSt->Tell() & 0x1))
3665 {
3666 sal_uInt8 c;
3667 return pSt->ReadBytes( &c, 1 );
3668 }
3669 return 0;
3670}
3671
3672short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3673{
3674 if( 0 < nLen ) // Empty ?
3675 {
3676 if (bOdd)
3677 nLen = nLen - WW8SkipEven( mpStStrm );
3678 else
3679 nLen = nLen - WW8SkipOdd( mpStStrm );
3680
3681 sal_Int16 cbUPX(0);
3682 mpStStrm->ReadInt16( cbUPX );
3683
3684 nLen-=2;
3685
3686 if ( cbUPX > nLen )
3687 cbUPX = nLen; // shrink cbUPX to nLen
3688
3689 if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3690 {
3691 if( bPAP )
3692 {
3693 sal_uInt16 id;
3694 mpStStrm->ReadUInt16( id );
3695
3696 cbUPX-= 2;
3697 nLen-= 2;
3698 }
3699
3700 if( 0 < cbUPX )
3701 {
3702 sal_uInt64 const nPos = mpStStrm->Tell(); // if something is interpreted wrong,
3703 // this should make it work again
3704 ImportSprms( nPos, cbUPX, bPAP );
3705
3706 if ( mpStStrm->Tell() != nPos + cbUPX )
3707 mpStStrm->Seek( nPos+cbUPX );
3708
3709 nLen = nLen - cbUPX;
3710 }
3711 }
3712 }
3713 return nLen;
3714}
3715
3716void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3717{
3718 if( nLen <= 0 )
3719 return;
3720 if (bOdd)
3721 nLen = nLen - WW8SkipEven( mpStStrm );
3722 else
3723 nLen = nLen - WW8SkipOdd( mpStStrm );
3724
3725 if( bPara ) // Grupx.Papx
3726 nLen = ImportUPX(nLen, true, bOdd);
3727 ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3728}
3729
3731 : WW8Style(*pI->m_pTableStream, _rFib)
3732 , maSprmParser(_rFib)
3733 , mpIo(pI)
3734 , mpStStrm(pI->m_pTableStream)
3735 , mpStyRule(nullptr)
3736 , mpParaSprms(nullptr)
3737 , mnSprmsLen(0)
3738 , mnWwNumLevel(0)
3739 , mbTextColChanged(false)
3740 , mbFontChanged(false)
3741 , mbCJKFontChanged(false)
3742 , mbCTLFontChanged(false)
3743 , mbFSizeChanged(false)
3744 , mbFCTLSizeChanged(false)
3745 , mbWidowsChanged(false)
3746 , mbBidiChanged(false)
3747{
3748 mpIo->m_vColl.resize(m_cstd);
3749}
3750
3752{
3753 // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3754 if (!mbCJKFontChanged) // Style no CJK Font? set the default
3756
3757 if (!mbCTLFontChanged) // Style no CTL Font? set the default
3759
3760 // western 2nd to make western charset conversion the default
3761 if (!mbFontChanged) // Style has no Font? set the default,
3763
3764 if( mpIo->m_bNoAttrImport )
3765 return;
3766
3767 // Style has no text color set, winword default is auto
3768 if ( !mbTextColChanged )
3770
3771 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3772 if( !mbFSizeChanged )
3773 {
3774 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3776 aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3778 }
3779
3780 // Style has no FontSize ? WinWord Default is 10pt for western and asian
3781 if( !mbFCTLSizeChanged )
3782 {
3783 SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3784 aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3786 }
3787
3788 if( !mbWidowsChanged ) // Widows ?
3789 {
3792 }
3793
3794 // Word defaults to ltr, not inheriting from the environment like Writer. Regardless of
3795 // the page/sections rtl setting, the standard/no-inherit styles lack of rtl still means ltr
3796 if( !mbBidiChanged ) // likely, since no UI to change LTR except in default style
3797 {
3799 SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
3800 }
3801}
3802
3803bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle,
3804 sal_uInt16 nNextStyle,
3805 std::map<OUString, sal_Int32>& rParaCollisions,
3806 std::map<OUString, sal_Int32>& rCharCollisions)
3807{
3808 SwFormat* pColl;
3809 bool bStyExist;
3810
3811 if (rSI.m_bColl)
3812 {
3813 // Para-Style
3815 mpIo->m_aParaStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti, rParaCollisions);
3816 pColl = aResult.first;
3817 bStyExist = aResult.second;
3818 }
3819 else
3820 {
3821 // Char-Style
3823 mpIo->m_aCharStyleMapper.GetStyle(rSI.GetOrgWWName(), eSti, rCharCollisions);
3824 pColl = aResult.first;
3825 bStyExist = aResult.second;
3826 }
3827
3828 bool bImport = !bStyExist || mpIo->m_bNewDoc; // import content ?
3829
3830 // Do not override character styles the list import code created earlier.
3831 if (bImport && bStyExist && rSI.GetOrgWWName().startsWith("WW8Num"))
3832 bImport = false;
3833
3834 bool bOldNoImp = mpIo->m_bNoAttrImport;
3835 rSI.m_bImportSkipped = !bImport;
3836
3837 if( !bImport )
3838 mpIo->m_bNoAttrImport = true;
3839 else
3840 {
3841 if (bStyExist)
3842 {
3843 pColl->ResetAllFormatAttr(); // #i73790# - method renamed
3844 }
3845 pColl->SetAuto(false); // suggested by JP
3846 } // but changes the UI
3847 mpIo->m_pCurrentColl = pColl;
3848 rSI.m_pFormat = pColl; // remember translation WW->SW
3849 rSI.m_bImportSkipped = !bImport;
3850
3851 // Set Based on style
3852 sal_uInt16 j = rSI.m_nBase;
3853 if (j != nThisStyle && j < m_cstd )
3854 {
3855 SwWW8StyInf* pj = &mpIo->m_vColl[j];
3856 if (rSI.m_pFormat && pj->m_pFormat && rSI.m_bColl == pj->m_bColl)
3857 {
3858 rSI.m_pFormat->SetDerivedFrom( pj->m_pFormat ); // ok, set Based on
3862 rSI.m_n81Flags = pj->m_n81Flags;
3864 if (!rSI.IsWW8BuiltInHeadingStyle())
3865 {
3867 }
3870
3871 if (pj->m_xWWFly)
3872 rSI.m_xWWFly = std::make_shared<WW8FlyPara>(mpIo->m_bVer67, pj->m_xWWFly.get());
3873 }
3874 }
3875 else if( mpIo->m_bNewDoc && bStyExist )
3877
3878 rSI.m_nFollow = nNextStyle; // remember Follow
3879
3880 mpStyRule = nullptr; // recreate if necessary
3883 mpIo->SetNCurrentColl( nThisStyle );
3884 mpIo->m_bStyNormal = nThisStyle == 0;
3885 return bOldNoImp;
3886}
3887
3888void WW8RStyle::PostStyle(SwWW8StyInf const &rSI, bool bOldNoImp)
3889{
3890 // Reset attribute flags, because there are no style-ends.
3891
3893 mpIo->m_nCharFormat = -1;
3894
3895 // if style is based on nothing or base ignored
3896 if ((rSI.m_nBase >= m_cstd || mpIo->m_vColl[rSI.m_nBase].m_bImportSkipped) && rSI.m_bColl)
3897 {
3898 // If Char-Styles does not work
3899 // -> set hard WW-Defaults
3901 }
3902
3903 mpStyRule = nullptr; // to be on the safe side
3904 mpIo->m_bStyNormal = false;
3905 mpIo->SetNCurrentColl( 0 );
3906 mpIo->m_bNoAttrImport = bOldNoImp;
3907 // reset the list-remember-fields, if used when reading styles
3908 mpIo->m_nLFOPosition = USHRT_MAX;
3910}
3911
3912void WW8RStyle::Import1Style(sal_uInt16 nNr,
3913 std::map<OUString, sal_Int32>& rParaCollisions,
3914 std::map<OUString, sal_Int32>& rCharCollisions)
3915{
3916 if (nNr >= mpIo->m_vColl.size())
3917 return;
3918
3919 SwWW8StyInf &rSI = mpIo->m_vColl[nNr];
3920
3921 if( rSI.m_bImported || !rSI.m_bValid )
3922 return;
3923
3924 rSI.m_bImported = true; // set flag now to avoid endless loops
3925
3926 // valid and not NUL and not yet imported
3927
3928 if( rSI.m_nBase < m_cstd && !mpIo->m_vColl[rSI.m_nBase].m_bImported )
3929 Import1Style(rSI.m_nBase, rParaCollisions, rCharCollisions);
3930
3931 mpStStrm->Seek( rSI.m_nFilePos );
3932
3933 sal_uInt16 nSkip;
3934 OUString sName;
3935
3936 std::unique_ptr<WW8_STD> xStd(Read1Style(nSkip, &sName)); // read Style
3937
3938 if (xStd)
3939 rSI.SetOrgWWIdent( sName, xStd->sti );
3940
3941 // either no Name or unused Slot or unknown Style
3942
3943 if ( !xStd || sName.isEmpty() || ((1 != xStd->sgc) && (2 != xStd->sgc)) )
3944 {
3945 nSkip = std::min<sal_uInt64>(nSkip, mpStStrm->remainingSize());
3946 mpStStrm->Seek(mpStStrm->Tell() + nSkip);
3947 return;
3948 }
3949
3950 bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(xStd->sti),
3951 nNr, xStd->istdNext,
3952 rParaCollisions, rCharCollisions);
3953
3954 // if something is interpreted wrong, this should make it work again
3955 sal_uInt64 nPos = mpStStrm->Tell();
3956
3957 //Variable parts of the STD start at even byte offsets, but "inside
3958 //the STD", which I take to meaning even in relation to the starting
3959 //position of the STD, which matches findings in #89439#, generally it
3960 //doesn't matter as the STSHI starts off nearly always on an even
3961 //offset
3962
3963 //Import of the Style Contents
3964 ImportGrupx(nSkip, xStd->sgc == 1, rSI.m_nFilePos & 1);
3965
3966 PostStyle(rSI, bOldNoImp);
3967
3968 mpStStrm->Seek( nPos+nSkip );
3969}
3970
3971void WW8RStyle::RecursiveReg(sal_uInt16 nNr)
3972{
3973 if (nNr >= mpIo->m_vColl.size())
3974 return;
3975
3976 SwWW8StyInf &rSI = mpIo->m_vColl[nNr];
3977 if( rSI.m_bImported || !rSI.m_bValid )
3978 return;
3979
3980 rSI.m_bImported = true;
3981
3982 if( rSI.m_nBase < m_cstd && !mpIo->m_vColl[rSI.m_nBase].m_bImported )
3983 RecursiveReg(rSI.m_nBase);
3984
3986
3987}
3988
3989/*
3990 After all styles are imported then we can recursively apply numbering
3991 styles to them, and change their tab stop settings if they turned out
3992 to have special first line indentation.
3993*/
3995{
3996 sal_uInt16 i;
3997 /*
3998 Clear all imported flags so that we can recursively apply numbering
3999 formats and use it to mark handled ones
4000 */
4001 for (i=0; i < m_cstd; ++i)
4002 mpIo->m_vColl[i].m_bImported = false;
4003
4004 /*
4005 Register the num formats and tabstop changes on the styles recursively.
4006 */
4007
4008 /*
4009 In the same loop apply the tabstop changes required because we need to
4010 change their location if there's a special indentation for the first line,
4011 By avoiding making use of each styles margins during reading of their
4012 tabstops we don't get problems with doubly adjusting tabstops that
4013 are inheritied.
4014 */
4015 for (i=0; i < m_cstd; ++i)
4016 {
4017 if (mpIo->m_vColl[i].m_bValid)
4018 {
4019 RecursiveReg(i);
4020 }
4021 }
4022}
4023
4024void WW8RStyle::ScanStyles() // investigate style dependencies
4025{ // and detect Filepos for each Style
4026 for (sal_uInt16 i = 0; i < m_cstd; ++i)
4027 {
4028 SwWW8StyInf &rSI = mpIo->m_vColl[i];
4029
4030 rSI.m_nFilePos = mpStStrm->Tell(); // remember FilePos
4031 sal_uInt16 nSkip;
4032 std::unique_ptr<WW8_STD> xStd(Read1Style(nSkip, nullptr)); // read STD
4033 rSI.m_bValid = xStd != nullptr;
4034 if (rSI.m_bValid)
4035 {
4036 rSI.m_nBase = xStd->istdBase; // remember Basis
4037 rSI.m_bColl = xStd->sgc == 1; // Para-Style
4038 }
4039 else
4040 rSI = SwWW8StyInf();
4041
4042 xStd.reset();
4043 nSkip = std::min<sal_uInt64>(nSkip, mpStStrm->remainingSize());
4044 mpStStrm->Seek(mpStStrm->Tell() + nSkip); // skip Names and Sprms
4045 }
4046}
4047
4048std::vector<sal_uInt8> ChpxToSprms(const Word2CHPX &rChpx)
4049{
4050 std::vector<sal_uInt8> aRet
4051 {
4052 60,
4053 static_cast< sal_uInt8 >(128 + rChpx.fBold),
4054
4055 61,
4056 static_cast< sal_uInt8 >(128 + rChpx.fItalic),
4057
4058 62,
4059 static_cast< sal_uInt8 >(128 + rChpx.fStrike),
4060
4061 63,
4062 static_cast< sal_uInt8 >(128 + rChpx.fOutline),
4063
4064 65,
4065 static_cast< sal_uInt8 >(128 + rChpx.fSmallCaps),
4066
4067 66,
4068 static_cast< sal_uInt8 >(128 + rChpx.fCaps),
4069
4070 67,
4071 static_cast< sal_uInt8 >(128 + rChpx.fVanish)
4072 };
4073 if (rChpx.fsFtc)
4074 {
4075 aRet.push_back(68);
4076 SVBT16 a;
4077 ShortToSVBT16(rChpx.ftc, a);
4078 aRet.push_back(a[1]);
4079 aRet.push_back(a[0]);
4080 }
4081
4082 if (rChpx.fsKul)
4083 {
4084 aRet.push_back(69);
4085 aRet.push_back(rChpx.kul);
4086 }
4087
4088 if (rChpx.fsLid)
4089 {
4090 aRet.push_back(72);
4091 SVBT16 a;
4092 ShortToSVBT16(rChpx.lid, a);
4093 aRet.push_back(a[1]);
4094 aRet.push_back(a[0]);
4095 }
4096
4097 if (rChpx.fsIco)
4098 {
4099 aRet.push_back(73);
4100 aRet.push_back(rChpx.ico);
4101 }
4102
4103 if (rChpx.fsHps)
4104 {
4105 aRet.push_back(74);
4106
4107 SVBT16 a;
4108 ShortToSVBT16(rChpx.hps, a);
4109 aRet.push_back(a[0]);
4110 }
4111
4112 if (rChpx.fsPos)
4113 {
4114 aRet.push_back(76);
4115 aRet.push_back(rChpx.hpsPos);
4116 }
4117
4118 aRet.push_back(80);
4119 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBoldBi) );
4120
4121 aRet.push_back(81);
4122 aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalicBi) );
4123
4124 if (rChpx.fsFtcBi)
4125 {
4126 aRet.push_back(82);
4127 SVBT16 a;
4128 ShortToSVBT16(rChpx.fsFtcBi, a);
4129 aRet.push_back(a[1]);
4130 aRet.push_back(a[0]);
4131 }
4132
4133 if (rChpx.fsLidBi)
4134 {
4135 aRet.push_back(83);
4136 SVBT16 a;
4137 ShortToSVBT16(rChpx.lidBi, a);
4138 aRet.push_back(a[1]);
4139 aRet.push_back(a[0]);
4140 }
4141
4142 if (rChpx.fsIcoBi)
4143 {
4144 aRet.push_back(84);
4145 aRet.push_back(rChpx.icoBi);
4146 }
4147
4148 if (rChpx.fsHpsBi)
4149 {
4150 aRet.push_back(85);
4151 SVBT16 a;
4152 ShortToSVBT16(rChpx.hpsBi, a);
4153 aRet.push_back(a[1]);
4154 aRet.push_back(a[0]);
4155 }
4156
4157 return aRet;
4158}
4159
4160Word2CHPX ReadWord2Chpx(SvStream &rSt, std::size_t nOffset, sal_uInt8 nSize)
4161{
4162 Word2CHPX aChpx;
4163
4164 if (!nSize || !checkSeek(rSt, nOffset))
4165 return aChpx;
4166
4167 const size_t nMaxByteCount = rSt.remainingSize();
4168 if (!nMaxByteCount)
4169 return aChpx;
4170
4171 if (nSize > nMaxByteCount)
4172 {
4173 SAL_WARN("sw.ww8", "ReadWord2Chpx: truncating out of range "
4174 << nSize << " to " << nMaxByteCount);
4175 nSize = nMaxByteCount;
4176 }
4177
4178 sal_uInt8 nCount=0;
4179
4180 while (true)
4181 {
4182 sal_uInt8 nFlags8;
4183 rSt.ReadUChar( nFlags8 );
4184 nCount++;
4185
4186 if (!rSt.good())
4187 break;
4188
4189 aChpx.fBold = nFlags8 & 0x01;
4190 aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4191 aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4192 aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4193 aChpx.fFieldVanish = (nFlags8 & 0x10) >> 4;
4194 aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4195 aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4196 aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4197
4198 if (nCount >= nSize) break;
4199 rSt.ReadUChar( nFlags8 );
4200 nCount++;
4201
4202 if (!rSt.good())
4203 break;
4204
4205 aChpx.fRMark = nFlags8 & 0x01;
4206 aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4207 aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4208 aChpx.fObj = (nFlags8 & 0x08) >> 3;
4209 aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4210 aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4211 aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4212 aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4213
4214 if (nCount >= nSize) break;
4215 rSt.ReadUChar( nFlags8 );
4216 nCount++;
4217
4218 if (!rSt.good())
4219 break;
4220
4221 aChpx.fsIco = nFlags8 & 0x01;
4222 aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4223 aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4224 aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4225 aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4226 aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4227 aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4228 aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4229
4230 if (nCount >= nSize) break;
4231 rSt.ReadUChar( nFlags8 );
4232 nCount++;
4233
4234 if (!rSt.good())
4235 break;
4236
4237 aChpx.fsFtcBi = nFlags8 & 0x01;
4238 aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4239 aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4240
4241 if (nCount >= nSize) break;
4242 rSt.ReadUInt16( aChpx.ftc );
4243 nCount+=2;
4244
4245 if (nCount >= nSize) break;
4246 rSt.ReadUInt16( aChpx.hps );
4247 nCount+=2;
4248
4249 if (nCount >= nSize) break;
4250 rSt.ReadUChar( nFlags8 );
4251 nCount++;
4252
4253 if (!rSt.good())
4254 break;
4255
4256 aChpx.qpsSpace = nFlags8 & 0x3F;
4257 aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4258 aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4259
4260 if (nCount >= nSize) break;
4261 rSt.ReadUChar( nFlags8 );
4262 nCount++;
4263
4264 if (!rSt.good())
4265 break;
4266
4267 aChpx.ico = nFlags8 & 0x1F;
4268 aChpx.kul = (nFlags8 & 0xE0) >> 5;
4269
4270 if (nCount >= nSize) break;
4271 rSt.ReadUChar( aChpx.hpsPos );
4272 nCount++;
4273
4274 if (nCount >= nSize) break;
4275 rSt.ReadUChar( aChpx.icoBi );
4276 nCount++;
4277
4278 if (nCount >= nSize) break;
4279 rSt.ReadUInt16( aChpx.lid );
4280 nCount+=2;
4281
4282 if (nCount >= nSize) break;
4283 rSt.ReadUInt16( aChpx.ftcBi );
4284 nCount+=2;
4285
4286 if (nCount >= nSize) break;
4287 rSt.ReadUInt16( aChpx.hpsBi );
4288 nCount+=2;
4289
4290 if (nCount >= nSize) break;
4291 rSt.ReadUInt16( aChpx.lidBi );
4292 nCount+=2;
4293
4294 if (nCount >= nSize) break;
4295 rSt.ReadUInt32( aChpx.fcPic );
4296 nCount+=4;
4297
4298 break;
4299 }
4300
4301 rSt.SeekRel(nSize-nCount);
4302 return aChpx;
4303}
4304
4305namespace
4306{
4307 struct pxoffset { std::size_t mnOffset; sal_uInt8 mnSize; };
4308}
4309
4311{
4312 for (sal_uInt16 i=0; i < m_cstd; ++i)
4313 {
4314 mpIo->m_vColl[i].m_bColl = true;
4315 //every chain must end eventually at the null style (style code 222)
4316 mpIo->m_vColl[i].m_nBase = 222;
4317 }
4318
4319 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4320 mpIo->m_xWwFib->m_chseTables, mpIo->m_xWwFib->m_lid);
4321
4322 sal_uInt16 cstcStd(0);
4323 m_rStream.ReadUInt16( cstcStd );
4324
4325 size_t nMaxByteCount = m_rStream.remainingSize();
4326 sal_uInt16 cbName(0);
4327 m_rStream.ReadUInt16(cbName);
4328 if (cbName > nMaxByteCount)
4329 {
4330 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4331 << cbName << " to " << nMaxByteCount);
4332 cbName = nMaxByteCount;
4333 }
4334 sal_uInt16 nByteCount = 2;
4335 sal_uInt16 stcp=0;
4336 while (nByteCount < cbName)
4337 {
4338 sal_uInt8 nCount(0);
4340 nByteCount++;
4341
4342 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4343 if (stc >=mpIo->m_vColl.size())
4344 continue;
4345
4346 SwWW8StyInf &rSI = mpIo->m_vColl[stc];
4347 OUString sName;
4348
4349 if (nCount != 0xFF) // undefined style
4350 {
4351 if (nCount != 0) // user style
4352 {
4353 OString aTmp = read_uInt8s_ToOString(m_rStream, nCount);
4354 nByteCount += aTmp.getLength();
4355 sName = OStringToOUString(aTmp, eStructChrSet);
4356 }
4357 rSI.m_bImported = true;
4358 }
4359
4360 if (sName.isEmpty())
4361 {
4363 if (const char *pStr = GetEnglishNameFromSti(eSti))
4364 sName = OUString(pStr, strlen(pStr), RTL_TEXTENCODING_ASCII_US);
4365 }
4366
4367 if (sName.isEmpty())
4368 sName = "Unknown Style: " + OUString::number(stc);
4369
4370 rSI.SetOrgWWIdent(sName, stc);
4371 stcp++;
4372 }
4373
4374 sal_uInt16 nStyles=stcp;
4375
4376 std::vector<pxoffset> aCHPXOffsets(stcp);
4377 nMaxByteCount = m_rStream.remainingSize();
4378 sal_uInt16 cbChpx(0);
4379 m_rStream.ReadUInt16(cbChpx);
4380 if (cbChpx > nMaxByteCount)
4381 {
4382 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4383 << cbChpx << " to " << nMaxByteCount);
4384 cbChpx = nMaxByteCount;
4385 }
4386 nByteCount = 2;
4387 stcp=0;
4388 std::vector< std::vector<sal_uInt8> > aConvertedChpx;
4389 while (nByteCount < cbChpx)
4390 {
4391 if (stcp == aCHPXOffsets.size())
4392 {
4393 //more data than style slots, skip remainder
4394 m_rStream.SeekRel(cbChpx-nByteCount);
4395 break;
4396 }
4397
4398 sal_uInt8 cb(0);
4399 m_rStream.ReadUChar( cb );
4400 nByteCount++;
4401
4402 aCHPXOffsets[stcp].mnSize = 0;
4403
4404 if (cb != 0xFF)
4405 {
4406 sal_uInt8 nRemainder = cb;
4407
4408 aCHPXOffsets[stcp].mnOffset = m_rStream.Tell();
4409 aCHPXOffsets[stcp].mnSize = nRemainder;
4410
4411 Word2CHPX aChpx = ReadWord2Chpx(m_rStream, aCHPXOffsets[stcp].mnOffset,
4412 aCHPXOffsets[stcp].mnSize);
4413 aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4414
4415 nByteCount += nRemainder;
4416 }
4417 else
4418 aConvertedChpx.emplace_back( );
4419
4420 ++stcp;
4421 }
4422
4423 std::vector<pxoffset> aPAPXOffsets(stcp);
4424 nMaxByteCount = m_rStream.remainingSize();
4425 sal_uInt16 cbPapx(0);
4426 m_rStream.ReadUInt16(cbPapx);
4427 if (cbPapx > nMaxByteCount)
4428 {
4429 SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4430 << cbPapx << " to " << nMaxByteCount);
4431 cbPapx = nMaxByteCount;
4432 }
4433 nByteCount = 2;
4434 stcp=0;
4435 while (nByteCount < cbPapx)
4436 {
4437 if (stcp == aPAPXOffsets.size())
4438 {
4439 m_rStream.SeekRel(cbPapx-nByteCount);
4440 break;
4441 }
4442
4443 sal_uInt8 cb(0);
4444 m_rStream.ReadUChar( cb );
4445 nByteCount++;
4446
4447 aPAPXOffsets[stcp].mnSize = 0;
4448
4449 if (cb != 0xFF)
4450 {
4451 sal_uInt8 stc2(0);
4452 m_rStream.ReadUChar( stc2 );
4453 m_rStream.SeekRel(6);
4454 nByteCount+=7;
4455 sal_uInt8 nRemainder = cb-7;
4456
4457 aPAPXOffsets[stcp].mnOffset = m_rStream.Tell();
4458 aPAPXOffsets[stcp].mnSize = nRemainder;
4459
4460 m_rStream.SeekRel(nRemainder);
4461 nByteCount += nRemainder;
4462 }
4463
4464 ++stcp;
4465 }
4466
4467 sal_uInt16 iMac(0);
4468 m_rStream.ReadUInt16( iMac );
4469
4470 if (iMac > nStyles) iMac = nStyles;
4471
4472 std::map<OUString, sal_Int32> aParaCollisions;
4473 std::map<OUString, sal_Int32> aCharCollisions;
4474
4475 for (stcp = 0; stcp < iMac; ++stcp)
4476 {
4477 sal_uInt8 stcNext(0), stcBase(0);
4478 m_rStream.ReadUChar( stcNext );
4479 m_rStream.ReadUChar( stcBase );
4480
4481 sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4482
4483 /*
4484 #i64557# style based on itself
4485 every chain must end eventually at the null style (style code 222)
4486 */
4487 if (stc == stcBase)
4488 stcBase = 222;
4489
4490 SwWW8StyInf &rSI = mpIo->m_vColl[stc];
4491 rSI.m_nBase = stcBase;
4492
4494
4495 if (eSti == ww::stiNil)
4496 continue;
4497
4498 if (stcp >= aPAPXOffsets.size())
4499 continue;
4500
4501 rSI.m_bValid = true;
4502
4503 if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4504 mpIo->m_vColl[stc].m_bColl = false;
4505
4506 bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext,
4507 aParaCollisions,
4508 aCharCollisions);
4509
4510 ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4511 true);
4512
4513 if (!aConvertedChpx[stcp].empty())
4514 ImportSprms(aConvertedChpx[stcp].data(),
4515 static_cast< short >(aConvertedChpx[stcp].size()),
4516 false);
4517
4518 PostStyle(rSI, bOldNoImp);
4519 }
4520}
4521
4523{
4524 ScanStyles(); // Scan Based On
4525
4526 std::map<OUString, sal_Int32> aParaCollisions;
4527 std::map<OUString, sal_Int32> aCharCollisions;
4528
4529 for (sal_uInt16 i = 0; i < m_cstd; ++i) // import Styles
4530 if (mpIo->m_vColl[i].m_bValid)
4531 Import1Style(i, aParaCollisions, aCharCollisions);
4532}
4533
4535{
4539
4541 return;
4542
4543 if (mpIo->m_xWwFib->GetFIBVersion() <= ww::eWW2)
4545 else
4547
4548 for (sal_uInt16 i = 0; i < m_cstd; ++i)
4549 {
4550 // Follow chain
4551 SwWW8StyInf* pi = &mpIo->m_vColl[i];
4552 sal_uInt16 j = pi->m_nFollow;
4553 if( j < m_cstd )
4554 {
4555 SwWW8StyInf* pj = &mpIo->m_vColl[j];
4556 if ( j != i // rational Index ?
4557 && pi->m_pFormat // Format ok ?
4558 && pj->m_pFormat // Derived-Format ok ?
4559 && pi->m_bColl // only possible for paragraph templates (WW)
4560 && pj->m_bColl ){ // identical Type ?
4561 static_cast<SwTextFormatColl*>(pi->m_pFormat)->SetNextTextFormatColl(
4562 *static_cast<SwTextFormatColl*>(pj->m_pFormat) ); // ok, register
4563 }
4564 }
4565 }
4566
4567 // Missing special handling for default character template
4568 // "Absatz-Standardschriftart" ( Style-ID 65 ).
4569 // That is empty by default ( WW6 dt and US ) and not changeable
4570 // via WW-UI so this does not matter.
4571 // This could be done by:
4572 // if( bNew ) rDoc.SetDefault( pDefCharFormat->GetAttrSet() );
4573
4574 // for e.g. tables an always valid Std-Style is necessary
4575
4576 if( mpIo->StyleExists(0) && !mpIo->m_vColl.empty() &&
4577 mpIo->m_vColl[0].m_pFormat && mpIo->m_vColl[0].m_bColl && mpIo->m_vColl[0].m_bValid )
4578 mpIo->m_pDfltTextFormatColl = static_cast<SwTextFormatColl*>(mpIo->m_vColl[0].m_pFormat);
4579 else
4581
4582 // set Hyphenation flag on BASIC para-style
4584 {
4585 if (mpIo->m_xWDop->fAutoHyphen
4586 && SfxItemState::SET != mpIo->m_pStandardFormatColl->GetItemState(
4587 RES_PARATR_HYPHENZONE, false) )
4588 {
4590 aAttr.GetMinLead() = 2;
4591 aAttr.GetMinTrail() = 2;
4592 aAttr.GetMaxHyphens() = 0;
4593
4595 }
4596 }
4597
4598 // we do not read styles anymore:
4599 mpIo->m_pCurrentColl = nullptr;
4600}
4601
4602rtl_TextEncoding SwWW8StyInf::GetCharSet() const
4603{
4604 if (m_pFormat && (m_pFormat->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4605 return m_eRTLFontSrcCharSet;
4606 return m_eLTRFontSrcCharSet;
4607}
4608
4609rtl_TextEncoding SwWW8StyInf::GetCJKCharSet() const
4610{
4611 if (m_pFormat && (m_pFormat->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4612 return m_eRTLFontSrcCharSet;
4613 return m_eCJKFontSrcCharSet;
4614}
4615
4616/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const OUString & GetValue() const
ManTypes meType
Definition: ww8par.hxx:999
virtual void DeleteRange(SwPaM &)=0
Delete a range SwFlyFrameFormat.
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_uInt64 Tell() const
bool good() const
SvStream & ReadInt16(sal_Int16 &rInt16)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
sal_uInt64 SeekRel(sal_Int64 nPos)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
sal_uInt64 remainingSize()
SvStream & ReadUChar(unsigned char &rChar)
bool WasDeleted() const
void SetDistance(sal_Int16 nNew, SvxBoxItemLine nLine)
SvxBreak GetBreak() const
sal_uInt8 & GetMinLead()
sal_uInt8 & GetMaxHyphens()
sal_uInt8 & GetMinTrail()
short GetTextFirstLineOffset() const
void SetLeft(const tools::Long nL, const sal_uInt16 nProp=100)
void SetStart(sal_uInt16 nSet)
void SetAbsLSpace(sal_Int32 nSet)
sal_uInt8 GetIncludeUpperLevels() const
void SetBulletFont(const vcl::Font *pFont)
void SetCharTextDistance(short nSet)
void SetListFormat(const OUString &rPrefix, const OUString &rSuffix, int nLevel)
void SetNumAdjust(SvxAdjust eSet)
void SetIncludeUpperLevels(sal_uInt8 nSet)
void SetFirstLineOffset(sal_Int32 nSet)
void SetBulletChar(sal_UCS4 cSet)
const OUString & GetSuffix() const
void SetNumberingType(SvxNumType nSet)
SvxNumType GetNumberingType() const
void SetHeight(tools::Long n)
void SetWidth(tools::Long n)
bool WasDeleted() const
Definition: doc.hxx:192
SwFlyFrameFormat * MakeFlySection(RndStdIds eAnchorType, const SwPosition *pAnchorPos, const SfxItemSet *pSet=nullptr, SwFrameFormat *pParent=nullptr, bool bCalledFromShell=false)
Definition: doclay.cxx:288
OUString GetUniqueNumRuleName(const OUString *pChkStr=nullptr, bool bAutoNum=true) const
Definition: docnum.cxx:2533
SwNumRule * FindNumRulePtr(const OUString &rName) const
Definition: docnum.cxx:2455
const SwTable * InsertTable(const SwInsertTableOptions &rInsTableOpts, const SwPosition &rPos, sal_uInt16 nRows, sal_uInt16 nCols, sal_Int16 eAdjust, const SwTableAutoFormat *pTAFormat=nullptr, const std::vector< sal_uInt16 > *pColArr=nullptr, bool bCalledFromShell=false, bool bNewModel=true)
Insert new table at position.
Definition: ndtbl.cxx:341
const SwNumRuleTable & GetNumRuleTable() const
Definition: doc.hxx:1070
SwNumRule * GetOutlineNumRule() const
Definition: doc.hxx:1028
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:316
SwNodes & GetNodes()
Definition: doc.hxx:413
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:638
void InsertRow(const SwCursor &rCursor, sal_uInt16 nCnt=1, bool bBehind=true)
Definition: ndtbl.cxx:1748
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:427
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:780
std::shared_ptr< SwUnoCursor > CreateUnoCursor(const SwPosition &rPos, bool bTableCursor=false)
Definition: doc.cxx:1774
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1322
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter <bResetListAttrs>.
Definition: docfmt.cxx:1082
sal_uInt16 MakeNumRule(const OUString &rName, const SwNumRule *pCpy=nullptr, bool bBroadcast=false, const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode=SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
Definition: docnum.cxx:2489
void SetOutlineNumRule(const SwNumRule &rRule)
Definition: docnum.cxx:112
FlyAnchors.
Definition: fmtanchr.hxx:37
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1586
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:69
void SetWidthPercent(sal_uInt8 n)
Definition: fmtfsize.hxx:95
void SetHeightSizeType(SwFrameSize eSize)
Definition: fmtfsize.hxx:81
void SetPos(SwTwips nNew)
Definition: fmtornt.hxx:93
void SetHoriOrient(sal_Int16 eNew)
Definition: fmtornt.hxx:89
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
void SetAnchorOnly(bool bNew)
Definition: fmtsrnd.hxx:56
Base class for various Writer styles.
Definition: format.hxx:47
const SvxFrameDirectionItem & GetFrameDir(bool=true) const
Definition: frmatr.hxx:94
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
void SetAuto(bool bNew)
Definition: format.hxx:179
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:387
const SwNumRuleItem & GetNumRule(bool=true) const
Definition: paratr.hxx:232
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:83
const SvxFormatBreakItem & GetBreak(bool=true) const
Definition: frmatr.hxx:90
bool SetDerivedFrom(SwFormat *pDerivedFrom=nullptr)
0 is Default.
Definition: format.cxx:320
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
const SfxPoolItem & GetFormatAttr(sal_uInt16 nWhich, bool bInParents=true) const
If bInParents is FALSE, search only in this format for attribute.
Definition: format.cxx:368
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:449
virtual sal_uInt16 ResetAllFormatAttr()
Takes all hints from Delta-Array,.
Definition: format.cxx:648
Style of a layout element.
Definition: frmfmt.hxx:62
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:171
Base class of the Writer document model elements.
Definition: node.hxx:84
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:876
SwNodeOffset EndOfSectionIndex() const
Definition: node.hxx:705
SwNodeType GetNodeType() const
Definition: node.hxx:150
SwNode & GetEndOfExtras() const
This is the last EndNode of a special section.
Definition: ndarr.hxx:163
bool InsBoxen(SwTableNode *, SwTableLine *, SwTableBoxFormat *, SwTextFormatColl *, const SfxItemSet *pAutoAttr, sal_uInt16 nInsPos, sal_uInt16 nCnt=1)
Insert a new box in the line before InsPos.
Definition: ndtbl.cxx:236
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx:97
void Set(sal_uInt16 i, const SwNumFormat *)
Definition: number.cxx:618
const OUString & GetName() const
Definition: numrule.hxx:224
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:187
SwNode & GetPointNode() const
Definition: pam.hxx:283
const SwPosition * GetPoint() const
Definition: pam.hxx:261
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:419
SwNodeOffset GetSttIdx() const
Definition: swtable.cxx:2049
void setRowSpan(sal_Int32 nNewRowSpan)
Definition: swtable.cxx:77
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:457
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:471
void ChgFrameFormat(SwTableBoxFormat *pNewFormat, bool bNeedToReregister=true)
Definition: swtable.cxx:1937
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1901
SwTableLine is one table row in the document model.
Definition: swtable.hxx:358
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:380
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1478
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:368
size_type size() const
Definition: swtable.hxx:76
const SwTable & GetTable() const
Definition: node.hxx:521
SwTableNode * GetTableNode() const
Definition: swtable.cxx:2111
void SetRowsToRepeat(sal_uInt16 nNumOfRows)
Definition: swtable.hxx:197
SwTableLines & GetTabLines()
Definition: swtable.hxx:201
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:204
static SwSelBoxes & SelLineFromBox(const SwTableBox *pBox, SwSelBoxes &rBoxes, bool bToTop=true)
Definition: tblcpy.cxx:1028
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:167
void SetSeqNo(sal_uInt16 n)
Definition: txtftn.hxx:63
void SetNumber(sal_uInt16 nNumber, sal_uInt16 nNumberRLHidden, const OUString &sNumStr)
Definition: atrftn.cxx:357
const SwNodeIndex * GetStartNode() const
Definition: txtftn.hxx:41
Represents the style of a paragraph.
Definition: fmtcol.hxx:59
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:86
void SetAttrListLevel(int nLevel)
Sets the list level of this text node.
Definition: ndtxt.cxx:4156
SwTextAttr * InsertItem(SfxPoolItem &rAttr, const sal_Int32 nStart, const sal_Int32 nEnd, const SetAttrMode nMode=SetAttrMode::DEFAULT)
create new text attribute from rAttr and insert it
Definition: thints.cxx:1305
const SfxPoolItem & GetAttr(sal_uInt16 nWhich, bool bInParent=true) const
End: Data collected during idle time.
Definition: node.hxx:749
void SetCountedInList(bool bCounted)
Definition: ndtxt.cxx:4316
const OUString & GetText() const
Definition: ndtxt.hxx:222
std::optional< SwPosition > m_oLastAnchorPos
Definition: ww8par.hxx:1407
SwPaM * m_pPaM
Definition: ww8par.hxx:1129
sal_uInt16 m_nLFOPosition
Definition: ww8par.hxx:1325
bool InLocalApo() const
Definition: ww8par.hxx:1587
SwDocShell * m_pDocShell
Definition: ww8par.hxx:1106
sal_uInt16 End_Footnote()
Definition: ww8par2.cxx:170
const WW8Fib & GetFib() const
Definition: ww8par.hxx:1919
friend struct WW8SwFlyPara
Definition: ww8par.hxx:1112
std::vector< SwWW8StyInf > m_vColl
Definition: ww8par.hxx:1269
void PopTableDesc()
Definition: ww8par2.cxx:3526
sal_Int32 m_nIniFlyDx
Definition: ww8par.hxx:1316
bool m_bCurrentAND_fNumberAcross
Definition: ww8par.hxx:1382
const SwTextFormatColl * m_pDfltTextFormatColl
Definition: ww8par.hxx:1270
SwNumRule * GetStyRule()
Definition: ww8par2.cxx:737
void Read_TabRowEnd(sal_uInt16, const sal_uInt8 *pData, short nLen)
Definition: ww8par2.cxx:3520
void Read_ANLevelNo(sal_uInt16, const sal_uInt8 *pData, short nLen)
Definition: ww8par2.cxx:756
static Color ExtractColour(const sal_uInt8 *&rpData, bool bVer67)
Definition: ww8par6.cxx:5024
bool m_bWasTabCellEnd
Definition: ww8par.hxx:1353
bool SetUpperSpacing(SwPaM &pMyPam, int nSpace)
Definition: ww8par.cxx:2543
std::unique_ptr< SwWW8FltControlStack > m_xCtrlStck
Definition: ww8par.hxx:1131
SwDoc & m_rDoc
Definition: ww8par.hxx:1127
std::unique_ptr< WW8SwFlyPara > m_xSFlyPara
Definition: ww8par.hxx:1276
void Read_TabCellEnd(sal_uInt16, const sal_uInt8 *pData, short nLen)
Definition: ww8par2.cxx:3514
bool m_bWasTabRowEnd
Definition: ww8par.hxx:1352
bool ParseTabPos(WW8_TablePos *aTabPos, WW8PLCFx_Cp_FKP *pPap)
Definition: ww8par6.cxx:5309
SwTwips MoveOutsideFly(SwFrameFormat *pFlyFormat, const SwPosition &rPos, bool bTableJoin=true)
Definition: ww8par6.cxx:2332
std::shared_ptr< WW8Fib > m_xWwFib
Definition: ww8par.hxx:1253
wwSectionManager m_aSectionManager
Definition: ww8par.hxx:1184
sal_Int32 m_nIniFlyDy
Definition: ww8par.hxx:1317
void StopAnlToRestart(sal_uInt8 nType, bool bGoBack=true)
Definition: ww8par2.cxx:1064
bool SetNewFontAttr(sal_uInt16 nFCode, bool bSetEnums, sal_uInt16 nWhich)
Definition: ww8par6.cxx:3774
sal_uInt16 m_nCurrentColl
Definition: ww8par.hxx:1323
sw::util::InsertedTablesManager m_aInsertedTables
Definition: ww8par.hxx:1197
void SetNCurrentColl(sal_uInt16 nColl)
Definition: ww8par.hxx:1922
sw::util::CharStyleMapper m_aCharStyleMapper
Definition: ww8par.hxx:1218
std::unique_ptr< WW8Dop > m_xWDop
Definition: ww8par.hxx:1255