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