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