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