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