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