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