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