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