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