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