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 += OUStringChar(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 = reinterpret_cast<WW8_TCell *>(new char[nWwCols * sizeof (WW8_TCell)]);
1084  // create uninitialized
1085  memcpy( pTCs, rBand.pTCs, nWwCols * sizeof( WW8_TCell ) );
1086  }
1087  if( rBand.pSHDs )
1088  {
1089  pSHDs = new WW8_SHD[nWwCols];
1090  memcpy( pSHDs, rBand.pSHDs, nWwCols * sizeof( WW8_SHD ) );
1091  }
1092  if( rBand.pNewSHDs )
1093  {
1094  pNewSHDs = new Color[nWwCols];
1095  memcpy(pNewSHDs, rBand.pNewSHDs, nWwCols * sizeof(Color));
1096  }
1097  memcpy(aDefBrcs, rBand.aDefBrcs, sizeof(aDefBrcs));
1098 }
1099 
1100 // ReadDef reads the cell position and the borders of a band
1101 void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS, short nLen)
1102 {
1103  if (!bVer67)
1104  {
1105  //the ww8 version of this is unusual in masquerading as a srpm with a
1106  //single byte len arg while it really has a word len arg, after this
1107  //increment nLen is correct to describe the remaining amount of data
1108  pS++;
1109  }
1110 
1111  --nLen; //reduce len by expected nCols arg
1112  if (nLen < 0)
1113  return;
1114  sal_uInt8 nCols = *pS; // number of cells
1115 
1116  if (nCols > MAX_COL)
1117  return;
1118 
1119  nLen -= 2 * (nCols + 1); //reduce len by claimed amount of next x-borders arguments
1120  if (nLen < 0)
1121  return;
1122 
1123  short nOldCols = nWwCols;
1124  nWwCols = nCols;
1125 
1126  const sal_uInt8* pT = &pS[1];
1127  for (int i = 0; i <= nCols; i++, pT+=2)
1128  nCenter[i] = static_cast<sal_Int16>(SVBT16ToUInt16( pT )); // X-borders
1129 
1130  if( nCols != nOldCols ) // different column count
1131  {
1132  delete[] pTCs;
1133  pTCs = nullptr;
1134  delete[] pSHDs;
1135  pSHDs = nullptr;
1136  delete[] pNewSHDs;
1137  pNewSHDs = nullptr;
1138  }
1139 
1140  short nFileCols = nLen / ( bVer67 ? 10 : 20 ); // really saved
1141 
1142  if (!pTCs && nCols)
1143  {
1144  // create empty TCs
1145  pTCs = new WW8_TCell[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 
1402  if (pTCs)
1403  {
1404  memcpy( pTC2s, pTCs, nWwCols * sizeof( WW8_TCell ) );
1405  delete[] pTCs;
1406  }
1407  pTCs = pTC2s;
1408 
1409  //If we have to move some cells
1410  if (nitcInsert <= nWwCols)
1411  {
1412  // adjust the left x-position of the dummy at the very end
1413  nCenter[nWwCols + nctc] = nCenter[nWwCols]+nctc*ndxaCol;
1414  for( int i = nWwCols-1; i >= nitcInsert; i--)
1415  {
1416  // adjust the left x-position
1417  nCenter[i + nctc] = nCenter[i]+nctc*ndxaCol;
1418 
1419  // adjust the cell's borders
1420  pTCs[i + nctc] = pTCs[i];
1421  }
1422  }
1423 
1424  //if itcMac is larger than full size, fill in missing ones first
1425  for( int i = nWwCols; i > nitcInsert+nWwCols; i--)
1426  nCenter[i] = i ? (nCenter[i - 1]+ndxaCol) : 0;
1427 
1428  //now add in our new cells
1429  for( int j = 0;j < nctc; j++)
1430  nCenter[j + nitcInsert] = (j + nitcInsert) ? (nCenter[j + nitcInsert -1]+ndxaCol) : 0;
1431 
1432  nWwCols = nNewWwCols;
1433 
1434 }
1435 
1437 {
1438  sal_uInt8 nStartCell = *pParams++;
1439  sal_uInt8 nEndCell = *pParams++;
1440  sal_uInt16 nCode = SVBT16ToUInt16(pParams);
1441 
1442  OSL_ENSURE(nStartCell < nEndCell, "not as I thought");
1443  OSL_ENSURE(nEndCell < MAX_COL + 1, "not as I thought");
1444  if (nStartCell > MAX_COL)
1445  return;
1446  if (nEndCell > MAX_COL + 1)
1447  nEndCell = MAX_COL + 1;
1448 
1449  for (;nStartCell < nEndCell; ++nStartCell)
1450  maDirections[nStartCell] = nCode;
1451 }
1452 
1454 {
1455  sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1456  OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1457  if (nLen != 6)
1458  return;
1459  mbHasSpacing=true;
1460 #if OSL_DEBUG_LEVEL > 0
1461  sal_uInt8 nWhichCell = *pParams;
1462  OSL_ENSURE(nWhichCell == 0, "Expected cell to be 0!");
1463 #endif
1464  ++pParams; //Skip which cell
1465  ++pParams; //unknown byte
1466 
1467  sal_uInt8 nSideBits = *pParams++;
1468  OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1469  ++pParams; //unknown byte
1470  sal_uInt16 nValue = SVBT16ToUInt16( pParams );
1471  for (int i = wwTOP; i <= wwRIGHT; i++)
1472  {
1473  switch (nSideBits & (1 << i))
1474  {
1475  case 1 << wwTOP:
1476  mnDefaultTop = nValue;
1477  break;
1478  case 1 << wwLEFT:
1479  mnDefaultLeft = nValue;
1480  break;
1481  case 1 << wwBOTTOM:
1482  mnDefaultBottom = nValue;
1483  break;
1484  case 1 << wwRIGHT:
1485  mnDefaultRight = nValue;
1486  break;
1487  case 0:
1488  break;
1489  default:
1490  OSL_ENSURE(false, "Impossible");
1491  break;
1492  }
1493  }
1494 }
1495 
1497 {
1498  sal_uInt8 nLen = pParams ? *(pParams - 1) : 0;
1499  OSL_ENSURE(nLen == 6, "Unexpected spacing len");
1500  if (nLen != 6)
1501  return;
1502  sal_uInt8 nWhichCell = *pParams++;
1503  OSL_ENSURE(nWhichCell < MAX_COL + 1, "Cell out of range in spacings");
1504  if (nWhichCell >= MAX_COL + 1)
1505  return;
1506 
1507  ++pParams; //unknown byte
1508  sal_uInt8 nSideBits = *pParams++;
1509  OSL_ENSURE(nSideBits < 0x10, "Unexpected value for nSideBits");
1510  nOverrideSpacing[nWhichCell] |= nSideBits;
1511 
1512  OSL_ENSURE(nOverrideSpacing[nWhichCell] < 0x10,
1513  "Unexpected value for nSideBits");
1514 #if OSL_DEBUG_LEVEL > 0
1515  sal_uInt8 nUnknown2 = *pParams;
1516  OSL_ENSURE(nUnknown2 == 0x3, "Unexpected value for spacing2");
1517 #endif
1518  ++pParams;
1519  sal_uInt16 nValue = SVBT16ToUInt16( pParams );
1520 
1521  for (int i=0; i < 4; i++)
1522  {
1523  if (nSideBits & (1 << i))
1524  nOverrideValues[nWhichCell][i] = nValue;
1525  }
1526 }
1527 
1529 {
1530  if( nWwCols && pParamsTDelete ) // set one or more cell length(s)
1531  {
1532  sal_uInt8 nitcFirst= pParamsTDelete[0]; // first col to be deleted
1533  if (nitcFirst >= nWwCols) // first index to delete from doesn't exist
1534  return;
1535  sal_uInt8 nitcLim = pParamsTDelete[1]; // (last col to be deleted)+1
1536  if (nitcLim <= nitcFirst) // second index to delete to is not greater than first index
1537  return;
1538 
1539  /*
1540  * sprmTDelete causes any rgdxaCenter and rgtc entries whose index is
1541  * greater than or equal to itcLim to be moved
1542  */
1543  int nShlCnt = nWwCols - nitcLim; // count of cells to be shifted
1544 
1545  if (nShlCnt >= 0) //There exist entries whose index is greater than or equal to itcLim
1546  {
1547  WW8_TCell* pCurrentTC = pTCs + nitcFirst;
1548  int i = 0;
1549  while( i < nShlCnt )
1550  {
1551  // adjust the left x-position
1552  nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1553 
1554  // adjust the cell's borders
1555  *pCurrentTC = pTCs[ nitcLim + i];
1556 
1557  ++i;
1558  ++pCurrentTC;
1559  }
1560  // adjust the left x-position of the dummy at the very end
1561  nCenter[nitcFirst + i] = nCenter[nitcLim + i];
1562  }
1563 
1564  short nCellsDeleted = nitcLim - nitcFirst;
1565  //clip delete request to available number of cells
1566  if (nCellsDeleted > nWwCols)
1567  nCellsDeleted = nWwCols;
1568  nWwCols -= nCellsDeleted;
1569  }
1570 }
1571 
1572 // ReadShd reads the background color of a cell
1573 // ReadDef must be called before
1575 {
1576  sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1577  if( !nLen )
1578  return;
1579 
1580  if( !pSHDs )
1581  {
1582  pSHDs = new WW8_SHD[nWwCols];
1583  }
1584 
1585  short nCount = nLen >> 1;
1586  if (nCount > nWwCols)
1587  nCount = nWwCols;
1588 
1589  SVBT16 const * pShd;
1590  int i;
1591  for(i=0, pShd = reinterpret_cast<SVBT16 const *>(pS); i<nCount; i++, pShd++ )
1592  pSHDs[i].SetWWValue( *pShd );
1593 }
1594 
1595 void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67)
1596 {
1597  sal_uInt8 nLen = pS ? *(pS - 1) : 0;
1598  if (!nLen)
1599  return;
1600 
1601  if (!pNewSHDs)
1602  pNewSHDs = new Color[nWwCols];
1603 
1604  short nCount = nLen / 10; //10 bytes each
1605  if (nCount > nWwCols)
1606  nCount = nWwCols;
1607 
1608  int i=0;
1609  while (i < nCount)
1610  pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);
1611 
1612  while (i < nWwCols)
1613  pNewSHDs[i++] = COL_AUTO;
1614 }
1615 
1616 namespace
1617 {
1618  SprmResult HasTabCellSprm(WW8PLCFx_Cp_FKP* pPap, bool bVer67)
1619  {
1620  if (bVer67)
1621  return pPap->HasSprm(24);
1622  SprmResult aRes = pPap->HasSprm(0x244B);
1623  if (aRes.pSprm == nullptr)
1624  aRes = pPap->HasSprm(0x2416);
1625  return aRes;
1626  }
1627 }
1628 
1629 namespace {
1630 
1632 {
1633  sprmNil,
1634 
1637  sprmTSetBrc, sprmTSetBrc90, sprmTDxaCol, sprmTInsert, sprmTDelete,
1638  sprmTTableHeader, sprmTDxaGapHalf, sprmTTableBorders, sprmTTableBorders90,
1639  sprmTDefTableNewShd, sprmTCellPadding, sprmTCellPaddingDefault
1640 };
1641 
1642 }
1643 
1644 static wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
1645 {
1646  switch (eVer)
1647  {
1648  case ww::eWW8:
1649  switch (nId)
1650  {
1652  return sprmTTableWidth;
1654  return sprmTTextFlow;
1656  return sprmTTableHeader;
1658  return sprmTFCantSplit;
1659  case NS_sprm::sprmTJc90:
1660  return sprmTJc;
1661  case NS_sprm::sprmTFBiDi:
1662  return sprmTFBiDi;
1663  case NS_sprm::sprmTDelete:
1664  return sprmTDelete;
1665  case NS_sprm::sprmTInsert:
1666  return sprmTInsert;
1667  case NS_sprm::sprmTDxaCol:
1668  return sprmTDxaCol;
1670  return sprmTDyaRowHeight;
1671  case NS_sprm::sprmTDxaLeft:
1672  return sprmTDxaLeft;
1674  return sprmTDxaGapHalf;
1676  return sprmTTableBorders;
1678  return sprmTDefTable;
1680  return sprmTDefTableShd;
1682  return sprmTDefTableNewShd;
1684  return sprmTTableBorders90;
1686  return sprmTSetBrc;
1687  case NS_sprm::sprmTSetBrc:
1688  return sprmTSetBrc90;
1690  return sprmTCellPadding;
1692  return sprmTCellPaddingDefault;
1693  }
1694  break;
1695  case ww::eWW7:
1696  case ww::eWW6:
1697  switch (nId)
1698  {
1699  case 182:
1700  return sprmTJc;
1701  case 183:
1702  return sprmTDxaLeft;
1703  case 184:
1704  return sprmTDxaGapHalf;
1705  case 186:
1706  return sprmTTableHeader;
1707  case 187:
1708  return sprmTTableBorders;
1709  case 189:
1710  return sprmTDyaRowHeight;
1711  case 190:
1712  return sprmTDefTable;
1713  case 191:
1714  return sprmTDefTableShd;
1715  case 193:
1716  return sprmTSetBrc;
1717  case 194:
1718  return sprmTInsert;
1719  case 195:
1720  return sprmTDelete;
1721  case 196:
1722  return sprmTDxaCol;
1723  }
1724  break;
1725  case ww::eWW1:
1726  case ww::eWW2:
1727  switch (nId)
1728  {
1729  case 146:
1730  return sprmTJc;
1731  case 147:
1732  return sprmTDxaLeft;
1733  case 148:
1734  return sprmTDxaGapHalf;
1735  case 153:
1736  return sprmTDyaRowHeight;
1737  case 154:
1738  return sprmTDefTable;
1739  case 155:
1740  return sprmTDefTableShd;
1741  case 157:
1742  return sprmTSetBrc;
1743  case 158:
1744  return sprmTInsert;
1745  case 159:
1746  return sprmTDelete;
1747  case 160:
1748  return sprmTDxaCol;
1749  }
1750  break;
1751  }
1752  return sprmNil;
1753 }
1754 
1756  m_pIo(pIoClass),
1757  m_pFirstBand(nullptr),
1758  m_pActBand(nullptr),
1759  m_pTableNd(nullptr),
1760  m_pTabLines(nullptr),
1761  m_pTabLine(nullptr),
1762  m_pTabBoxes(nullptr),
1763  m_pTabBox(nullptr),
1764  m_pCurrentWWCell(nullptr),
1765  m_nRows(0),
1766  m_nDefaultSwCols(0),
1767  m_nBands(0),
1768  m_nMinLeft(0),
1769  m_nConvertedLeft(0),
1770  m_nMaxRight(0),
1771  m_nSwWidth(0),
1772  m_nPreferredWidth(0),
1773  m_nPercentWidth(0),
1774  m_bOk(true),
1775  m_bClaimLineFormat(false),
1776  m_eOri(text::HoriOrientation::NONE),
1777  m_bIsBiDi(false),
1778  m_nCurrentRow(0),
1779  m_nCurrentBandRow(0),
1780  m_nCurrentCol(0),
1781  m_nRowsToRepeat(0),
1782  m_pTable(nullptr),
1783  m_pParentPos(nullptr),
1784  m_pFlyFormat(nullptr),
1785  m_aItemSet(m_pIo->m_rDoc.GetAttrPool(),svl::Items<RES_FRMATR_BEGIN,RES_FRMATR_END-1>{})
1786 {
1787  m_pIo->m_bCurrentAND_fNumberAcross = false;
1788 
1789  static const sal_Int16 aOriArr[] =
1790  {
1791  text::HoriOrientation::LEFT, text::HoriOrientation::CENTER, text::HoriOrientation::RIGHT, text::HoriOrientation::CENTER
1792  };
1793 
1794  bool bOldVer = ww::IsSevenMinus(m_pIo->GetFib().GetFIBVersion());
1795  WW8_TablePos aTabPos;
1796 
1797  WW8PLCFxSave1 aSave;
1798  m_pIo->m_xPlcxMan->GetPap()->Save( aSave );
1799 
1800  WW8PLCFx_Cp_FKP* pPap = m_pIo->m_xPlcxMan->GetPapPLCF();
1801 
1802  m_eOri = text::HoriOrientation::LEFT;
1803 
1804  WW8TabBandDesc* pNewBand = new WW8TabBandDesc;
1805 
1806  wwSprmParser aSprmParser(m_pIo->GetFib());
1807 
1808  // process pPap until end of table found
1809  do
1810  {
1811  short nTabeDxaNew = SHRT_MAX;
1812  bool bTabRowJustRead = false;
1813  const sal_uInt8* pShadeSprm = nullptr;
1814  const sal_uInt8* pNewShadeSprm = nullptr;
1815  const sal_uInt8* pTableBorders = nullptr;
1816  sal_uInt16 nTableBordersLen = 0;
1817  const sal_uInt8* pTableBorders90 = nullptr;
1818  sal_uInt16 nTableBorders90Len = 0;
1819  // params, len
1820  std::vector<std::pair<const sal_uInt8*, sal_uInt16>> aTSetBrcs, aTSetBrc90s;
1821  WW8_TablePos *pTabPos = nullptr;
1822 
1823  // search end of a tab row
1824  if(!(m_pIo->SearchRowEnd(pPap, nStartCp, m_pIo->m_nInTable)))
1825  {
1826  m_bOk = false;
1827  break;
1828  }
1829 
1830  // Get the SPRM chains:
1831  // first from PAP and then from PCD (of the Piece Table)
1832  WW8PLCFxDesc aDesc;
1833  pPap->GetSprms( &aDesc );
1834  WW8SprmIter aSprmIter(aDesc.pMemPos, aDesc.nSprmsLen, aSprmParser);
1835 
1836  for (int nLoop = 0; nLoop < 2; ++nLoop)
1837  {
1838  const sal_uInt8* pParams;
1839  while (aSprmIter.GetSprms() && nullptr != (pParams = aSprmIter.GetCurrentParams()))
1840  {
1841  sal_uInt16 nId = aSprmIter.GetCurrentId();
1842  sal_uInt16 nFixedLen = aSprmParser.DistanceToData(nId);
1843  sal_uInt16 nL = aSprmParser.GetSprmSize(nId, aSprmIter.GetSprms(), aSprmIter.GetRemLen());
1844  sal_uInt16 nLen = nL - nFixedLen;
1845  wwTableSprm eSprm = GetTableSprm(nId, m_pIo->GetFib().GetFIBVersion());
1846  switch (eSprm)
1847  {
1848  case sprmTTableWidth:
1849  {
1850  const sal_uInt8 b0 = pParams[0];
1851  const sal_uInt8 b1 = pParams[1];
1852  const sal_uInt8 b2 = pParams[2];
1853  if (b0 == 3) // Twips
1854  m_nPreferredWidth = b2 * 0x100 + b1;
1855  else if (b0 == 2) // percent in fiftieths of a percent
1856  {
1857  m_nPercentWidth = (b2 * 0x100 + b1);
1858  // MS documentation: non-negative, and 600% max
1859  if ( m_nPercentWidth >= 0 && m_nPercentWidth <= 30000 )
1860  m_nPercentWidth *= .02;
1861  else
1862  m_nPercentWidth = 100;
1863  }
1864  }
1865  break;
1866  case sprmTTextFlow:
1867  pNewBand->ProcessDirection(pParams);
1868  break;
1869  case sprmTFCantSplit:
1870  pNewBand->bCantSplit = *pParams;
1871  m_bClaimLineFormat = true;
1872  break;
1873  case sprmTTableBorders:
1874  pTableBorders = pParams; // process at end
1875  nTableBordersLen = nLen;
1876  break;
1877  case sprmTTableBorders90:
1878  pTableBorders90 = pParams; // process at end
1879  nTableBorders90Len = nLen;
1880  break;
1881  case sprmTTableHeader:
1882  // tdf#105570
1883  if ( m_nRowsToRepeat == m_nRows )
1884  m_nRowsToRepeat = (m_nRows + 1);
1885  break;
1886  case sprmTJc:
1887  // sprmTJc - Justification Code
1888  if (m_nRows == 0)
1889  m_eOri = aOriArr[*pParams & 0x3];
1890  break;
1891  case sprmTFBiDi:
1892  m_bIsBiDi = SVBT16ToUInt16(pParams) != 0;
1893  break;
1894  case sprmTDxaGapHalf:
1895  pNewBand->nGapHalf = static_cast<sal_Int16>(SVBT16ToUInt16( pParams ));
1896  break;
1897  case sprmTDyaRowHeight:
1898  pNewBand->nLineHeight = static_cast<sal_Int16>(SVBT16ToUInt16( pParams ));
1899  m_bClaimLineFormat = true;
1900  break;
1901  case sprmTDefTable:
1902  pNewBand->ReadDef(bOldVer, pParams, nLen);
1903  bTabRowJustRead = true;
1904  break;
1905  case sprmTDefTableShd:
1906  pShadeSprm = pParams;
1907  break;
1908  case sprmTDefTableNewShd:
1909  pNewShadeSprm = pParams;
1910  break;
1911  case sprmTDxaLeft:
1912  // our Writer cannot shift single table lines
1913  // horizontally so we have to find the smallest
1914  // parameter (meaning the left-most position) and then
1915  // shift the whole table to that margin (see below)
1916  {
1917  short nDxaNew = static_cast<sal_Int16>(SVBT16ToUInt16( pParams ));
1918  if( nDxaNew < nTabeDxaNew )
1919  nTabeDxaNew = nDxaNew;
1920  }
1921  break;
1922  case sprmTSetBrc:
1923  aTSetBrcs.emplace_back(pParams, nLen); // process at end
1924  break;
1925  case sprmTSetBrc90:
1926  aTSetBrc90s.emplace_back(pParams, nLen); // process at end
1927  break;
1928  case sprmTDxaCol:
1929  pNewBand->ProcessSprmTDxaCol(pParams);
1930  break;
1931  case sprmTInsert:
1932  pNewBand->ProcessSprmTInsert(pParams);
1933  break;
1934  case sprmTDelete:
1935  pNewBand->ProcessSprmTDelete(pParams);
1936  break;
1938  pNewBand->ProcessSpacing(pParams);
1939  break;
1940  case sprmTCellPadding:
1941  pNewBand->ProcessSpecificSpacing(pParams);
1942  break;
1943  default:
1944  ;
1945  }
1946  aSprmIter.advance();
1947  }
1948 
1949  if( !nLoop )
1950  {
1951  pPap->GetPCDSprms( aDesc );
1952  aSprmIter.SetSprms( aDesc.pMemPos, aDesc.nSprmsLen );
1953  }
1954  }
1955 
1956  // WW-Tables can contain Fly-changes. For this abort tables here
1957  // and start again. *pPap is still before TabRowEnd, so TestApo()
1958  // can be called with the last parameter set to false and therefore
1959  // take effect.
1960 
1961  if (bTabRowJustRead)
1962  {
1963  // Some SPRMs need to be processed *after* ReadDef is called
1964  // so they were saved up until here
1965  if (pShadeSprm)
1966  pNewBand->ReadShd(pShadeSprm);
1967  if (pNewShadeSprm)
1968  pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
1969  if (pTableBorders90)
1970  pNewBand->ProcessSprmTTableBorders(9, pTableBorders90, nTableBorders90Len);
1971  else if (pTableBorders)
1972  pNewBand->ProcessSprmTTableBorders(bOldVer ? 6 : 8,
1973  pTableBorders, nTableBordersLen);
1974  for (const auto& a : aTSetBrcs)
1975  pNewBand->ProcessSprmTSetBRC(bOldVer ? 6 : 8, a.first, a.second);
1976  for (const auto& a : aTSetBrc90s)
1977  pNewBand->ProcessSprmTSetBRC(9, a.first, a.second);
1978  }
1979 
1980  if( nTabeDxaNew < SHRT_MAX )
1981  {
1982  short* pCenter = pNewBand->nCenter;
1983  short firstDxaCenter = *pCenter;
1984  for( int i = 0; i < pNewBand->nWwCols; i++, ++pCenter )
1985  {
1986  // #i30298# Use sprmTDxaLeft to adjust the left indent
1987  // #i40461# Use dxaGapHalf during calculation
1988  *pCenter +=
1989  (nTabeDxaNew - (firstDxaCenter + pNewBand->nGapHalf));
1990  }
1991  }
1992 
1993  if (!m_pActBand)
1994  m_pActBand = m_pFirstBand = pNewBand;
1995  else
1996  {
1997  m_pActBand->pNextBand = pNewBand;
1998  m_pActBand = pNewBand;
1999  }
2000  m_nBands++;
2001 
2002  pNewBand = new WW8TabBandDesc;
2003 
2004  m_nRows++;
2005  m_pActBand->nRows++;
2006 
2007  //Seek our pap to its next block of properties
2008  WW8PLCFxDesc aRes;
2009  aRes.pMemPos = nullptr;
2010  aRes.nStartPos = nStartCp;
2011 
2012  if (!(pPap->SeekPos(aRes.nStartPos)))
2013  {
2014  aRes.nEndPos = WW8_CP_MAX;
2015  pPap->SetDirty(true);
2016  }
2017  pPap->GetSprms(&aRes);
2018  pPap->SetDirty(false);
2019 
2020  //Are we at the end of available properties
2021  if (
2022  !pPap->HasFkp() || pPap->Where() == WW8_CP_MAX ||
2023  aRes.nStartPos == WW8_CP_MAX
2024  )
2025  {
2026  m_bOk = false;
2027  break;
2028  }
2029 
2030  //Are we still in a table cell
2031  SprmResult aParamsRes = HasTabCellSprm(pPap, bOldVer);
2032  const sal_uInt8* pParams = aParamsRes.pSprm;
2033  SprmResult aLevelRes = pPap->HasSprm(0x6649);
2034  const sal_uInt8 *pLevel = aLevelRes.pSprm;
2035  // InTable
2036  if (!pParams || aParamsRes.nRemainingData < 1 || (1 != *pParams) ||
2037  (pLevel && aLevelRes.nRemainingData >= 1 && (*pLevel <= m_pIo->m_nInTable)))
2038  {
2039  break;
2040  }
2041 
2042  //Get the end of row new table positioning data
2043  WW8_CP nMyStartCp=nStartCp;
2044  if (m_pIo->SearchRowEnd(pPap, nMyStartCp, m_pIo->m_nInTable))
2045  if (m_pIo->ParseTabPos(&aTabPos, pPap))
2046  pTabPos = &aTabPos;
2047 
2048  //Move back to this cell
2049  aRes.pMemPos = nullptr;
2050  aRes.nStartPos = nStartCp;
2051 
2052  // PlcxMan currently points too far ahead so we need to bring
2053  // it back to where we are trying to make a table
2054  m_pIo->m_xPlcxMan->GetPap()->nOrigStartPos = aRes.nStartPos;
2055  m_pIo->m_xPlcxMan->GetPap()->nCpOfs = aRes.nCpOfs;
2056  if (!(pPap->SeekPos(aRes.nStartPos)))
2057  {
2058  aRes.nEndPos = WW8_CP_MAX;
2059  pPap->SetDirty(true);
2060  }
2061  pPap->GetSprms(&aRes);
2062  pPap->SetDirty(false);
2063 
2064  //Does this row match up with the last row closely enough to be
2065  //considered part of the same table
2066  ApoTestResults aApo = m_pIo->TestApo(m_pIo->m_nInTable + 1, false, pTabPos);
2067 
2068  /*
2069  ##513##, #79474# If this is not sufficient, then we should look at
2070  sprmPD{y|x}aAbs as our indicator that the following set of rows is not
2071  part of this table, but instead is an absolutely positioned table
2072  outside of this one
2073  */
2074  if (aApo.mbStopApo)
2075  break;
2076  if (aApo.mbStartApo)
2077  {
2078  //if there really is a fly here, and not a "null" fly then break.
2079  if (m_pIo->ConstructApo(aApo, pTabPos))
2080  break;
2081  }
2082 
2083  if (nStartCp == aRes.nEndPos)
2084  {
2085  SAL_WARN("sw.ww8", "WW8TabDesc End same as Start, abandoning to avoid looping");
2086  break;
2087  }
2088  nStartCp = aRes.nEndPos;
2089  }
2090  while(true);
2091 
2092  if( m_bOk )
2093  {
2094  if( m_pActBand->nRows > 1 )
2095  {
2096  // last band has more than 1 cell
2097  delete pNewBand;
2098  pNewBand = new WW8TabBandDesc( *m_pActBand ); // create new
2099  m_pActBand->nRows--; // because of special treatment of border defaults
2100  pNewBand->nRows = 1;
2101  m_pActBand->pNextBand = pNewBand; // append at the end
2102  m_nBands++;
2103  pNewBand = nullptr; // do not delete
2104  }
2105  CalcDefaults();
2106  }
2107  delete pNewBand;
2108 
2109  m_pIo->m_xPlcxMan->GetPap()->Restore( aSave );
2110 }
2111 
2113 {
2115  while(pR)
2116  {
2117  WW8TabBandDesc* pR2 = pR->pNextBand;
2118  delete pR;
2119  pR = pR2;
2120  }
2121 
2122  delete m_pParentPos;
2123 }
2124 
2126 {
2127  short nMinCols = SHRT_MAX;
2128  WW8TabBandDesc* pR;
2129 
2130  m_nMinLeft = SHRT_MAX;
2131  m_nMaxRight = SHRT_MIN;
2132 
2133  /*
2134  If we are an honestly inline centered table, then the normal rules of
2135  engagement for left and right margins do not apply. The multiple rows are
2136  centered regardless of the actual placement of rows, so we cannot have
2137  mismatched rows as is possible in other configurations.
2138 
2139  e.g. change the example bugdoc in word from text wrapping of none (inline)
2140  to around (in frame (bApo)) and the table splits into two very disjoint
2141  rows as the beginning point of each row are very different
2142  */
2143  if ((!m_pIo->InLocalApo()) && (m_eOri == text::HoriOrientation::CENTER))
2144  {
2145  for (pR = m_pFirstBand; pR; pR = pR->pNextBand)
2146  for( short i = pR->nWwCols; i >= 0; --i)
2147  pR->nCenter[i] = pR->nCenter[i] - pR->nCenter[0];
2148  }
2149 
2150  // First loop: find outermost L and R borders
2151  for( pR = m_pFirstBand; pR; pR = pR->pNextBand )
2152  {
2153  if( pR->nCenter[0] < m_nMinLeft )
2154  m_nMinLeft = pR->nCenter[0];
2155 
2156  // Following adjustment moves a border and then uses it to find width
2157  // of next cell, so collect current widths, to avoid situation when width
2158  // adjustment to too narrow cell makes next cell have negative width
2159  short nOrigWidth[MAX_COL + 1];
2160  for( short i = 0; i < pR->nWwCols; i++ )
2161  {
2162  nOrigWidth[i] = pR->nCenter[i+1] - pR->nCenter[i];
2163  }
2164 
2165  for( short i = 0; i < pR->nWwCols; i++ )
2166  {
2167  /*
2168  If the margins are so large as to make the displayable
2169  area inside them smaller than the minimum allowed then adjust the
2170  width to fit. But only do it if the two cells are not the exact
2171  same value, if they are then the cell does not really exist and will
2172  be blended together into the same cell through the use of the
2173  nTrans(late) array.
2174  #i28333# If the nGapHalf is greater than the cell width best to ignore it
2175  */
2176  int nCellWidth = pR->nCenter[i+1] - pR->nCenter[i];
2177  if (nCellWidth != nOrigWidth[i])
2178  {
2179  if (nOrigWidth[i] == 0)
2180  nCellWidth = 0; // restore zero-width "cell"
2181  else if ((pR->nGapHalf >= nCellWidth) && (pR->nGapHalf < nOrigWidth[i]))
2182  nCellWidth = pR->nGapHalf + 1; // avoid false ignore
2183  else if ((nCellWidth <= 0) && (nOrigWidth[i] > 0))
2184  nCellWidth = 1; // minimal non-zero width to minimize distortion
2185  }
2186  if (nCellWidth && ((nCellWidth - pR->nGapHalf*2) < MINLAY) && pR->nGapHalf < nCellWidth)
2187  {
2188  nCellWidth = MINLAY + pR->nGapHalf * 2;
2189  }
2190  pR->nCenter[i + 1] = pR->nCenter[i] + nCellWidth;
2191  }
2192 
2193  if( pR->nCenter[pR->nWwCols] > m_nMaxRight )
2194  m_nMaxRight = pR->nCenter[pR->nWwCols];
2195  }
2197 
2198  // If the table is right aligned we need to align all rows to the
2199  // row that has the furthest right point
2200 
2201  if(m_eOri == text::HoriOrientation::RIGHT)
2202  {
2203  for( pR = m_pFirstBand; pR; pR = pR->pNextBand )
2204  {
2205  int adjust = m_nMaxRight - pR->nCenter[pR->nWwCols];
2206  for( short i = 0; i < pR->nWwCols + 1; i++ )
2207  {
2208  pR->nCenter[i] = static_cast< short >(pR->nCenter[i] + adjust);
2209  }
2210 
2211  }
2212  }
2213 
2214  // 2. pass: Detect number of writer columns. This can exceed the count
2215  // of columns in WW by 2, because SW in contrast to WW does not provide
2216  // fringed left and right borders and has to fill with empty boxes.
2217  // Non existent cells can reduce the number of columns.
2218 
2219  // 3. pass: Replace border with defaults if needed
2221 
2222  short nLeftMaxThickness = 0, nRightMaxThickness=0;
2223  for( pR = m_pFirstBand ; pR; pR = pR->pNextBand )
2224  {
2225  if( !pR->pTCs )
2226  {
2227  pR->pTCs = new WW8_TCell[ pR->nWwCols ];
2228  }
2229  for (int k = 0; k < pR->nWwCols; ++k)
2230  {
2231  WW8_TCell& rT = pR->pTCs[k];
2232  for (int i = 0; i < 4; ++i)
2233  {
2234  if (rT.rgbrc[i].brcType()==0)
2235  {
2236  // if shadow is set, its invalid
2237  int j = i;
2238  switch( i )
2239  {
2240  case 0:
2241  // outer top / horizontally inside
2242  j = (pR == m_pFirstBand) ? 0 : 4;
2243  break;
2244  case 1:
2245  // outer left / vertically inside
2246  j = k ? 5 : 1;
2247  break;
2248  case 2:
2249  // outer bottom / horizontally inside
2250  j = pR->pNextBand ? 4 : 2;
2251  break;
2252  case 3:
2253  // outer right / vertically inside
2254  j = (k == pR->nWwCols - 1) ? 3 : 5;
2255  break;
2256  }
2257  // merge with above defaults
2258  rT.rgbrc[i] = pR->aDefBrcs[j];
2259  }
2260  }
2261  }
2262  if (pR->nWwCols)
2263  {
2264  /*
2265  Similar to graphics and other elements word does not totally
2266  factor the width of the border into its calculations of size, we
2267  do so we must adjust out widths and other dimensions to fit. It
2268  appears that what occurs is that the last cell's right margin if
2269  the margin width that is not calculated into winwords table
2270  dimensions, so in that case increase the table to include the
2271  extra width of the right margin.
2272  */
2273  if ( ! pR->pTCs[pR->nWwCols-1].rgbrc[3].fShadow() )
2274  {
2275  short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
2276  DetermineBorderProperties();
2277  pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
2278  if (nThickness > nRightMaxThickness)
2279  nRightMaxThickness = nThickness;
2280  }
2281 
2282  /*
2283  The left space of the table is in nMinLeft, but again this
2284  does not consider the margin thickness to its left in the
2285  placement value, so get the thickness of the left border,
2286  half is placed to the left of the nominal left side, and
2287  half to the right.
2288  */
2289  if ( ! pR->pTCs[0].rgbrc[1].fShadow() )
2290  {
2291  short nThickness = pR->pTCs[0].rgbrc[1].
2292  DetermineBorderProperties();
2293  if (nThickness > nLeftMaxThickness)
2294  nLeftMaxThickness = nThickness;
2295  }
2296  }
2297  }
2298  m_nSwWidth = m_nSwWidth + nRightMaxThickness;
2299  m_nMaxRight = m_nMaxRight + nRightMaxThickness;
2300  m_nConvertedLeft = m_nMinLeft-(nLeftMaxThickness/2);
2301 
2302  for( pR = m_pFirstBand; pR; pR = pR->pNextBand )
2303  {
2304  pR->nSwCols = pR->nWwCols;
2305  pR->bLEmptyCol = pR->nCenter[0] - m_nMinLeft >= MINLAY;
2306  pR->bREmptyCol = (m_nMaxRight - pR->nCenter[pR->nWwCols] - nRightMaxThickness) >= MINLAY;
2307 
2308  short nAddCols = short(pR->bLEmptyCol) + short(pR->bREmptyCol);
2309  sal_uInt16 i;
2310  sal_uInt16 j = ( pR->bLEmptyCol ) ? 1 : 0;
2311  for (i = 0; i < pR->nWwCols; ++i)
2312  {
2313  pR->nTransCell[i] = static_cast<sal_Int8>(j);
2314  if ( pR->nCenter[i] < pR->nCenter[i+1] )
2315  {
2316  pR->bExist[i] = true;
2317  j++;
2318  }
2319  else
2320  {
2321  pR->bExist[i] = false;
2322  nAddCols--;
2323  }
2324  }
2325 
2326  OSL_ENSURE(i,"no columns in row ?");
2327 
2328  /*
2329  If the last cell was "false" then there is no valid cell following it,
2330  so the default mapping forward won't work. So map it (and
2331  contiguous invalid cells backwards to the last valid cell instead.)
2332  */
2333  if (i && !pR->bExist[i-1])
2334  {
2335  sal_uInt16 k=i-1;
2336  while (k && !pR->bExist[k])
2337  k--;
2338  for (sal_uInt16 n=k+1;n<i;n++)
2339  pR->nTransCell[n] = pR->nTransCell[k];
2340  }
2341 
2342  pR->nTransCell[i++] = static_cast<sal_Int8>(j++); // Can exceed by 2 among other
2343  pR->nTransCell[i] = static_cast<sal_Int8>(j); // things because of bREmptyCol
2344 
2345  pR->nSwCols = pR->nSwCols + nAddCols;
2346  if( pR->nSwCols < nMinCols )
2347  nMinCols = pR->nSwCols;
2348  }
2349 
2350  if ((m_nMinLeft && !m_bIsBiDi && text::HoriOrientation::LEFT == m_eOri) ||
2351  (m_nMinLeft != -108 && m_bIsBiDi && text::HoriOrientation::RIGHT == m_eOri)) // Word sets the first nCenter value to -108 when no indent is used
2352  m_eOri = text::HoriOrientation::LEFT_AND_WIDTH; // absolutely positioned
2353 
2354  m_nDefaultSwCols = nMinCols; // because inserting cells is cheaper than merging
2355  if( m_nDefaultSwCols == 0 )
2356  m_bOk = false;
2358  m_nCurrentBandRow = 0;
2359  OSL_ENSURE( m_pActBand, "pActBand is 0" );
2360 }
2361 
2363 {
2364  SwFrameFormat* pApply = pFrameFormat;
2365  if (!pApply )
2366  pApply = m_pTable->GetFrameFormat();
2367  OSL_ENSURE(pApply,"No frame");
2368  pApply->SetFormatAttr(m_aItemSet);
2369  if (pFrameFormat)
2370  {
2371  SwFormatFrameSize aSize = pFrameFormat->GetFrameSize();
2373  aSize.SetHeight(MINLAY);
2374  pFrameFormat->SetFormatAttr(aSize);
2375  m_pTable->GetFrameFormat()->SetFormatAttr(SwFormatHoriOrient(0,text::HoriOrientation::FULL));
2376  }
2377 }
2378 
2380  const SwNode &rNode)
2381 {
2382  OSL_ENSURE(!maSegments.empty(),
2383  "should not be possible, must be at least one segment");
2384  if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2385  maSegments.back().maStart.Assign(rNode);
2386 }
2387 
2389 {
2391 
2392  // if there is already some content on the Node append new node to ensure
2393  // that this content remains ABOVE the table
2394  SwPosition* pPoint = m_pIo->m_pPaM->GetPoint();
2395  bool bInsNode = pPoint->nContent.GetIndex() != 0;
2396  bool bSetMinHeight = false;
2397 
2398  /*
2399  #i8062#
2400  Set fly anchor to its anchor pos, so that if a table starts immediately
2401  at this position a new node will be inserted before inserting the table.
2402  */
2403  if (!bInsNode && m_pIo->m_pFormatOfJustInsertedApo)
2404  {
2405  const SwPosition* pAPos =
2407  if (pAPos && &pAPos->nNode.GetNode() == &pPoint->nNode.GetNode())
2408  {
2409  bInsNode = true;
2410  bSetMinHeight = true;
2411 
2413  aSur.SetAnchorOnly(true);
2415  }
2416  }
2417 
2418  if (bSetMinHeight)
2419  {
2420  // minimize Fontsize to minimize height growth of the header/footer
2421  // set font size to 1 point to minimize y-growth of Hd/Ft
2422  SvxFontHeightItem aSz(20, 100, RES_CHRATR_FONTSIZE);
2423  m_pIo->NewAttr( aSz );
2424  m_pIo->m_xCtrlStck->SetAttr(*pPoint, RES_CHRATR_FONTSIZE);
2425  }
2426 
2427  if (bInsNode)
2428  m_pIo->AppendTextNode(*pPoint);
2429 
2430  m_xTmpPos.reset(new SwPosition(*m_pIo->m_pPaM->GetPoint()));
2431 
2432  // The table is small: The number of columns is the lowest count of
2433  // columns of the origin, because inserting is faster than deleting.
2434  // The number of rows is the count of bands because (identically)
2435  // rows of a band can be duplicated easy.
2439 
2440  OSL_ENSURE(m_pTable && m_pTable->GetFrameFormat(), "insert table failed");
2441  if (!m_pTable || !m_pTable->GetFrameFormat())
2442  return;
2443 
2444  SwTableNode* pTableNode = m_pTable->GetTableNode();
2445  OSL_ENSURE(pTableNode, "no table node!");
2446  if (pTableNode)
2447  {
2449  *pTableNode);
2450  }
2451 
2452  // Check if the node into which the table should be inserted already
2453  // contains a Pagedesc. If so that Pagedesc would be moved to the
2454  // row after the table, that would be wrong. So delete and
2455  // set later to the table format.
2456  if (SwTextNode *const pNd = m_xTmpPos->nNode.GetNode().GetTextNode())
2457  {
2458  if (const SfxItemSet* pSet = pNd->GetpSwAttrSet())
2459  {
2460  SfxPoolItem *pSetAttr = nullptr;
2461  const SfxPoolItem* pItem;
2462  if (SfxItemState::SET == pSet->GetItemState(RES_BREAK, false, &pItem))
2463  {
2464  pSetAttr = new SvxFormatBreakItem( *static_cast<const SvxFormatBreakItem*>(pItem) );
2465  pNd->ResetAttr( RES_BREAK );
2466  }
2467 
2468  // eventually set the PageDesc/Break now to the table
2469  if (pSetAttr)
2470  {
2471  m_aItemSet.Put(*pSetAttr);
2472  delete pSetAttr;
2473  }
2474  }
2475  }
2476 
2477  // total width of table
2479  {
2481  // Don't set relative width if the table has been converted into a floating frame
2482  if ( m_nPercentWidth && (!m_pIo->m_xSFlyPara || !m_pIo->m_xSFlyPara->pFlyFormat) )
2483  aFrameSize.SetWidthPercent(m_nPercentWidth);
2484  m_pTable->GetFrameFormat()->SetFormatAttr(aFrameSize);
2485  m_aItemSet.Put(aFrameSize);
2486  }
2487 
2488  SvxFrameDirectionItem aDirection(
2489  m_bIsBiDi ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR );
2490  m_pTable->GetFrameFormat()->SetFormatAttr(aDirection);
2491 
2492  if (text::HoriOrientation::LEFT_AND_WIDTH == m_eOri)
2493  {
2494  if (!m_pIo->m_nInTable && m_pIo->InLocalApo() && m_pIo->m_xSFlyPara &&
2495  m_pIo->m_xSFlyPara->pFlyFormat && GetMinLeft())
2496  {
2497  //If we are inside a frame and we have a border, the frames
2498  //placement does not consider the tables border, which word
2499  //displays outside the frame, so adjust here.
2500  SwFormatHoriOrient aHori(m_pIo->m_xSFlyPara->pFlyFormat->GetHoriOrient());
2501  sal_Int16 eHori = aHori.GetHoriOrient();
2502  if ((eHori == text::HoriOrientation::NONE) || (eHori == text::HoriOrientation::LEFT) ||
2503  (eHori == text::HoriOrientation::LEFT_AND_WIDTH))
2504  {
2505  //With multiple table, use last table settings. Perhaps
2506  //the maximum is what word does ?
2507  aHori.SetPos(m_pIo->m_xSFlyPara->nXPos + GetMinLeft());
2508  aHori.SetHoriOrient(text::HoriOrientation::NONE);
2509  m_pIo->m_xSFlyPara->pFlyFormat->SetFormatAttr(aHori);
2510  }
2511  }
2512  else
2513  {
2514  //If bApo is set, then this table is being placed in a floating
2515  //frame, and the frame matches the left and right *lines* of the
2516  //table, so the space to the left of the table isn't to be used
2517  //inside the frame, in word the dialog involved greys out the
2518  //ability to set the margin.
2520 
2521  long nLeft = 0;
2522  if (!m_bIsBiDi)
2523  nLeft = GetMinLeft();
2524  else
2525  {
2526  const short nTableWidth = m_nPreferredWidth ? m_nPreferredWidth : m_nSwWidth;
2528  nLeft = nLeft - nTableWidth - GetMinLeft();
2529  }
2530  aL.SetLeft(nLeft);
2531 
2532  m_aItemSet.Put(aL);
2533  }
2534  }
2535 
2536  mxOldRedlineStack = std::move(m_pIo->m_xRedlineStack);
2538 }
2539 
2541 {
2542  // init global Vars
2545 
2546  m_pTableNd = const_cast<SwTableNode*>((*m_pTabLines)[0]->GetTabBoxes()[0]->
2547  GetSttNd()->FindTableNode());
2548  OSL_ENSURE( m_pTableNd, "Where is my table node" );
2549 
2550  // #i69519# - Restrict rows to repeat to a decent value
2551  if ( m_nRowsToRepeat == static_cast<sal_uInt16>(m_nRows) )
2552  m_nRowsToRepeat = 1;
2553 
2555  // insert extra cells if needed and something like this
2556  AdjustNewBand();
2557 
2559  m_pIo->m_xCtrlStck->SetAttr(*m_pIo->m_pPaM->GetPoint(), 0, false);
2560 
2561  // now set the correct PaM and prepare first merger group if any
2562  SetPamInCell(m_nCurrentCol, true);
2563  aDup.Insert(*m_pIo->m_pPaM->GetPoint());
2564 
2565  m_pIo->m_bWasTabRowEnd = false;
2566  m_pIo->m_bWasTabCellEnd = false;
2567 }
2568 
2570 {
2571  short nRow;
2572 
2574  {
2575  // insert current box into merge group if appropriate.
2576  // The algorithm must ensure proper row and column order in WW8SelBoxInfo!
2577  if( m_pActBand->pTCs )
2578  {
2579  for( short j = 0; j < m_pActBand->nRows; j++, nRow++ )
2580  for( short i = 0; i < m_pActBand->nWwCols; i++ )
2581  {
2582  WW8SelBoxInfo* pActMGroup = nullptr;
2583 
2584  // start a new merge group if appropriate
2585 
2586  OSL_ENSURE(nRow < static_cast<sal_uInt16>(m_pTabLines->size()),
2587  "Too few lines, table ended early");
2588  if (nRow >= static_cast<sal_uInt16>(m_pTabLines->size()))
2589  return;
2590  m_pTabLine = (*m_pTabLines)[ nRow ];
2592 
2593  sal_uInt16 nCol = m_pActBand->nTransCell[ i ];
2594  if (!m_pActBand->bExist[i])
2595  continue;
2596  OSL_ENSURE(nCol < m_pTabBoxes->size(),
2597  "Too few columns, table ended early");
2598  if (nCol >= m_pTabBoxes->size())
2599  return;
2600  m_pTabBox = (*m_pTabBoxes)[nCol];
2601  WW8_TCell& rCell = m_pActBand->pTCs[ i ];
2602  // is this the left upper cell of a merge group ?
2603 
2604  bool bMerge = false;
2605  if ( rCell.bVertRestart && !rCell.bMerged )
2606  bMerge = true;
2607  else if (rCell.bFirstMerged && m_pActBand->bExist[i])
2608  {
2609  // Some tests to avoid merging cells which previously were
2610  // declared invalid because of sharing the exact same dimensions
2611  // as their previous cell
2612 
2613  //If there's anything underneath/above we're ok.
2614  if (rCell.bVertMerge || rCell.bVertRestart)
2615  bMerge = true;
2616  else
2617  {
2618  //If it's a hori merge only, and the only things in
2619  //it are invalid cells then it's already taken care
2620  //of, so don't merge.
2621  for (sal_uInt16 i2 = i+1; i2 < m_pActBand->nWwCols; i2++ )
2622  if (m_pActBand->pTCs[ i2 ].bMerged &&
2623  !m_pActBand->pTCs[ i2 ].bFirstMerged )
2624  {
2625  if (m_pActBand->bExist[i2])
2626  {
2627  bMerge = true;
2628  break;
2629  }
2630  }
2631  else
2632  break;
2633  }
2634  }
2635 
2636  // remove numbering from cells that will be disabled in the merge
2637  if( rCell.bVertMerge && !rCell.bVertRestart )
2638  {
2639  SwPaM aPam( *m_pTabBox->GetSttNd(), 0 );
2640  aPam.GetPoint()->nNode++;
2641  SwTextNode* pNd = aPam.GetNode().GetTextNode();
2642  while( pNd )
2643  {
2644  pNd->SetCountedInList( false );
2645 
2646  aPam.GetPoint()->nNode++;
2647  pNd = aPam.GetNode().GetTextNode();
2648  }
2649  }
2650 
2651  if (bMerge)
2652  {
2653  short nX1 = m_pActBand->nCenter[ i ];
2654  short nWidth = m_pActBand->nWidth[ i ];
2655 
2656  // 2. create current merge group
2657  pActMGroup = new WW8SelBoxInfo( nX1, nWidth );
2658 
2659  // determine size of new merge group
2660  // before inserted the new merge group.
2661  // Needed to correctly locked previously created merge groups.
2662  // Calculate total width and set
2663  short nSizCell = m_pActBand->nWidth[ i ];
2664  for (sal_uInt16 i2 = i+1; i2 < m_pActBand->nWwCols; i2++ )
2665  if (m_pActBand->pTCs[ i2 ].bMerged &&
2666  !m_pActBand->pTCs[ i2 ].bFirstMerged )
2667  {
2668  nSizCell = nSizCell + m_pActBand->nWidth[ i2 ];
2669  }
2670  else
2671  break;
2672  pActMGroup->nGroupWidth = nSizCell;
2673 
2674  // locked previously created merge groups,
2675  // after determining the size for the new merge group.
2676  // 1. If necessary close old merge group(s) that overlap
2677  // the X-area of the new group
2678  for (;;)
2679  {
2681  nX1, pActMGroup->nGroupWidth, false );
2682  if (p == nullptr)
2683  {
2684  break;
2685  }
2686  p->bGroupLocked = true;
2687  }
2688 
2689  // 3. push to group array
2690  m_MergeGroups.push_back(std::unique_ptr<WW8SelBoxInfo>(pActMGroup));
2691  }
2692 
2693  // if necessary add the current box to a merge group
2694  // (that can be a newly created or another group)
2695  UpdateTableMergeGroup( rCell, pActMGroup, m_pTabBox, i );
2696  }
2697  }
2698  }
2699 }
2700 
2701 //There is a limbo area in word at the end of the row marker
2702 //where properties can live in word, there is no location in
2703 //writer equivalent, so try and park the cursor in the best
2704 //match, see #i23022#/#i18644#
2706 {
2707  SwTableBox *pTabBox2 = nullptr;
2708  short nRow = m_nCurrentRow + 1;
2709  if (nRow < static_cast<sal_uInt16>(m_pTabLines->size()))
2710  {
2711  if (SwTableLine *pLine = (*m_pTabLines)[nRow])
2712  {
2713  SwTableBoxes &rBoxes = pLine->GetTabBoxes();
2714  pTabBox2 = rBoxes.empty() ? nullptr : rBoxes.front();
2715  }
2716  }
2717 
2718  if (!pTabBox2 || !pTabBox2->GetSttNd())
2719  {
2720  MoveOutsideTable();
2721  return;
2722  }
2723 
2724  sal_uLong nSttNd = pTabBox2->GetSttIdx() + 1,
2725  nEndNd = pTabBox2->GetSttNd()->EndOfSectionIndex();
2726 
2727  if (m_pIo->m_pPaM->GetPoint()->nNode != nSttNd)
2728  {
2729  do
2730  {
2731  m_pIo->m_pPaM->GetPoint()->nNode = nSttNd;
2732  }
2733  while (m_pIo->m_pPaM->GetNode().GetNodeType() != SwNodeType::Text && ++nSttNd < nEndNd);
2734 
2736  m_pIo->m_rDoc.SetTextFormatColl(*m_pIo->m_pPaM, const_cast<SwTextFormatColl*>(m_pIo->m_pDfltTextFormatColl));
2737  }
2738 }
2739 
2741 {
2742  OSL_ENSURE(m_xTmpPos.get() && m_pIo, "I've forgotten where the table is anchored");
2743  if (m_xTmpPos && m_pIo)
2744  *m_pIo->m_pPaM->GetPoint() = *m_xTmpPos;
2745 }
2746 
2748 {
2749  m_pIo->m_xRedlineStack->closeall(*m_pIo->m_pPaM->GetPoint());
2750  m_pIo->m_aFrameRedlines.emplace(std::move(m_pIo->m_xRedlineStack));
2751  m_pIo->m_xRedlineStack = std::move(mxOldRedlineStack);
2752 
2754  m_pIo->m_xCtrlStck->SetAttr( *m_pIo->m_pPaM->GetPoint(), 0, false);
2755 
2756  MoveOutsideTable();
2757  m_xTmpPos.reset();
2758 
2759  aDup.Insert(*m_pIo->m_pPaM->GetPoint());
2760 
2761  m_pIo->m_bWasTabRowEnd = false;
2762  m_pIo->m_bWasTabCellEnd = false;
2763 
2765 
2766  MergeCells();
2767 
2768  // if needed group cells together that should be merged
2769  if (!m_MergeGroups.empty())
2770  {
2771  // process all merge groups one by one
2772  for (auto const& groupIt : m_MergeGroups)
2773  {
2774  if((1 < groupIt->size()) && groupIt->row(0)[0])
2775  {
2776  SwFrameFormat* pNewFormat = groupIt->row(0)[0]->ClaimFrameFormat();
2777  pNewFormat->SetFormatAttr(SwFormatFrameSize(ATT_VAR_SIZE, groupIt->nGroupWidth, 0));
2778  const sal_uInt16 nRowSpan = groupIt->rowsCount();
2779  for (sal_uInt16 n = 0; n < nRowSpan; ++n)
2780  {
2781  auto& rRow = groupIt->row(n);
2782  for (size_t i = 0; i<rRow.size(); ++i)
2783  {
2784  const long nRowSpanSet = (n == 0) && (i == 0) ?
2785  nRowSpan :
2786  (-1 * (nRowSpan - n));
2787  SwTableBox* pCurrentBox = rRow[i];
2788  pCurrentBox->setRowSpan(nRowSpanSet);
2789 
2790  if (i == 0)
2791  pCurrentBox->ChgFrameFormat(static_cast<SwTableBoxFormat*>(pNewFormat));
2792  else
2793  {
2794  SwFrameFormat* pFormat = pCurrentBox->ClaimFrameFormat();
2795  pFormat->SetFormatAttr(SwFormatFrameSize(ATT_VAR_SIZE, 0, 0));
2796  }
2797  }
2798  }
2799  }
2800  }
2801  m_pIo->m_pFormatOfJustInsertedApo = nullptr;
2802  m_MergeGroups.clear();
2803  }
2804 }
2805 
2806 // browse m_MergeGroups, detect the index of the first fitting group or -1 otherwise
2807 
2808 // Parameter: nXcenter = center position of asking box
2809 // nWidth = width of asking box
2810 // bExact = flag, if box has to fit into group
2811 // or only has to touch
2812 
2813 WW8SelBoxInfo* WW8TabDesc::FindMergeGroup(short nX1, short nWidth, bool bExact)
2814 {
2815  if (!m_MergeGroups.empty())
2816  {
2817  // still valid area near the boundary
2818  const short nTolerance = 4;
2819  // box boundary
2820  short nX2 = nX1 + nWidth;
2821  // approximate group boundary
2822  short nGrX1;
2823  short nGrX2;
2824 
2825  // improvement: search backwards
2826  for (short iGr = m_MergeGroups.size() - 1; iGr >= 0; --iGr)
2827  {
2828  // the currently inspected group
2829  WW8SelBoxInfo& rActGroup = *m_MergeGroups[ iGr ];
2830  if (!rActGroup.bGroupLocked)
2831  {
2832  // approximate group boundary with room (tolerance) to the *outside*
2833  nGrX1 = rActGroup.nGroupXStart - nTolerance;
2834  nGrX2 = rActGroup.nGroupXStart
2835  + rActGroup.nGroupWidth + nTolerance;
2836 
2837  // If box fits report success
2838 
2839  if( ( nX1 > nGrX1 ) && ( nX2 < nGrX2 ) )
2840  {
2841  return &rActGroup;
2842  }
2843 
2844  // does the box share areas with the group?
2845 
2846  if( !bExact )
2847  {
2848  // successful if nX1 *or* nX2 are inside the group
2849  if( ( ( nX1 > nGrX1 )
2850  && ( nX1 < nGrX2 - 2*nTolerance ) )
2851  || ( ( nX2 > nGrX1 + 2*nTolerance )
2852  && ( nX2 < nGrX2 ) )
2853  // or nX1 and nX2 surround the group
2854  || ( ( nX1 <=nGrX1 )
2855  && ( nX2 >=nGrX2 ) ) )
2856  {
2857  return &rActGroup;
2858  }
2859  }
2860  }
2861  }
2862  }
2863  return nullptr;
2864 }
2865 
2866 bool WW8TabDesc::IsValidCell(short nCol) const
2867 {
2868  return (static_cast<size_t>(nCol) < SAL_N_ELEMENTS(m_pActBand->bExist)) &&
2869  m_pActBand->bExist[nCol] &&
2870  static_cast<sal_uInt16>(m_nCurrentRow) < m_pTabLines->size();
2871 }
2872 
2874 {
2875  //e.g. #i19718#
2876  if (!m_pTabBox || !m_pTabBox->GetSttNd())
2877  {
2878  OSL_FAIL("Problem with table");
2879  return false;
2880  }
2881 
2882  if (!IsValidCell(GetCurrentCol()))
2883  return false;
2884 
2885  return m_pIo->m_pPaM->GetPoint()->nNode == m_pTabBox->GetSttIdx() + 1;
2886 }
2887 
2888 void WW8TabDesc::SetPamInCell(short nWwCol, bool bPam)
2889 {
2890  OSL_ENSURE( m_pActBand, "pActBand is 0" );
2891  if (!m_pActBand)
2892  return;
2893 
2894  sal_uInt16 nCol = m_pActBand->transCell(nWwCol);
2895 
2896  if (static_cast<sal_uInt16>(m_nCurrentRow) >= m_pTabLines->size())
2897  {
2898  OSL_ENSURE(false, "Actual row bigger than expected." );
2899  if (bPam)
2900  MoveOutsideTable();
2901  return;
2902  }
2903 
2904  m_pTabLine = (*m_pTabLines)[m_nCurrentRow];
2906 
2907  if (nCol >= m_pTabBoxes->size())
2908  {
2909  if (bPam)
2910  {
2911  // The first paragraph in a cell with upper autospacing has upper
2912  // spacing set to 0
2913  if (
2915  !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing
2916  )
2917  {
2919  }
2920 
2921  // The last paragraph in a cell with lower autospacing has lower
2922  // spacing set to 0
2923  if (m_pIo->m_bParaAutoAfter && !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing)
2925 
2926  ParkPaM();
2927  }
2928  return;
2929  }
2930  m_pTabBox = (*m_pTabBoxes)[nCol];
2931  if( !m_pTabBox->GetSttNd() )
2932  {
2933  OSL_ENSURE(m_pTabBox->GetSttNd(), "Problems building the table");
2934  if (bPam)
2935  MoveOutsideTable();
2936  return;
2937  }
2938  if (bPam)
2939  {
2940  m_pCurrentWWCell = &m_pActBand->pTCs[ nWwCol ];
2941 
2942  // The first paragraph in a cell with upper autospacing has upper spacing set to 0
2943  if(m_pIo->m_bParaAutoBefore && m_pIo->m_bFirstPara && !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing)
2945 
2946  // The last paragraph in a cell with lower autospacing has lower spacing set to 0
2947  if(m_pIo->m_bParaAutoAfter && !m_pIo->m_xWDop->fDontUseHTMLAutoSpacing)
2949 
2950  //We need to set the pPaM on the first cell, invalid
2951  //or not so that we can collect paragraph properties over
2952  //all the cells, but in that case on the valid cell we do not
2953  //want to reset the fmt properties
2954  sal_uLong nSttNd = m_pTabBox->GetSttIdx() + 1,
2955  nEndNd = m_pTabBox->GetSttNd()->EndOfSectionIndex();
2956  if (m_pIo->m_pPaM->GetPoint()->nNode != nSttNd)
2957  {
2958  do
2959  {
2960  m_pIo->m_pPaM->GetPoint()->nNode = nSttNd;
2961  }
2962  while (m_pIo->m_pPaM->GetNode().GetNodeType() != SwNodeType::Text && ++nSttNd < nEndNd);
2964  // Precautionally set now, otherwise the style is not set for cells
2965  // that are inserted for margin balancing.
2966  m_pIo->m_rDoc.SetTextFormatColl(*m_pIo->m_pPaM, const_cast<SwTextFormatColl*>(m_pIo->m_pDfltTextFormatColl));
2967  // because this cells are invisible helper constructions only to simulate
2968  // the frayed view of WW-tables we do NOT need SetTextFormatCollAndListLevel()
2969  }
2970 
2971  // Better to turn Snap to Grid off for all paragraphs in tables
2972  if(SwTextNode *pNd = m_pIo->m_pPaM->GetNode().GetTextNode())
2973  {
2974  const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_PARATR_SNAPTOGRID);
2975  const SvxParaGridItem &rSnapToGrid = static_cast<const SvxParaGridItem&>(rItm);
2976 
2977  if(rSnapToGrid.GetValue())
2978  {
2979  SvxParaGridItem aGridItem( rSnapToGrid );
2980  aGridItem.SetValue(false);
2981 
2982  SwPosition* pGridPos = m_pIo->m_pPaM->GetPoint();
2983 
2984  const sal_Int32 nEnd = pGridPos->nContent.GetIndex();
2985  pGridPos->nContent.Assign(m_pIo->m_pPaM->GetContentNode(), 0);
2986  m_pIo->m_xCtrlStck->NewAttr(*pGridPos, aGridItem);
2987  pGridPos->nContent.Assign(m_pIo->m_pPaM->GetContentNode(), nEnd);
2988  m_pIo->m_xCtrlStck->SetAttr(*pGridPos, RES_PARATR_SNAPTOGRID);
2989  }
2990  }
2991  }
2992 }
2993 
2994 void WW8TabDesc::InsertCells( short nIns )
2995 {
2996  m_pTabLine = (*m_pTabLines)[m_nCurrentRow];
2998  m_pTabBox = (*m_pTabBoxes)[0];
2999 
3000  m_pIo->m_rDoc.GetNodes().InsBoxen( m_pTableNd, m_pTabLine, static_cast<SwTableBoxFormat*>(m_pTabBox->GetFrameFormat()),
3001  const_cast<SwTextFormatColl*>(m_pIo->m_pDfltTextFormatColl), nullptr, m_pTabBoxes->size(), nIns );
3002  // The third parameter contains the FrameFormat of the boxes.
3003  // Here it is possible to optimize to save (reduce) FrameFormats.
3004 }
3005 
3006 void WW8TabDesc::SetTabBorders(SwTableBox* pBox, short nWwIdx)
3007 {
3008  if( nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols )
3009  return; // faked cells -> no border
3010 
3011  SvxBoxItem aFormatBox( RES_BOX );
3012  if (m_pActBand->pTCs) // neither Cell Border nor Default Border defined ?
3013  {
3014  WW8_TCell* pT = &m_pActBand->pTCs[nWwIdx];
3016  SwWW8ImplReader::SetBorder(aFormatBox, pT->rgbrc);
3017  }
3018 
3019  if (m_pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwTOP))
3020  {
3021  aFormatBox.SetDistance(
3023  SvxBoxItemLine::TOP);
3024  }
3025  else
3026  aFormatBox.SetDistance(m_pActBand->mnDefaultTop, SvxBoxItemLine::TOP);
3028  {
3029  aFormatBox.SetDistance(
3031  SvxBoxItemLine::BOTTOM);
3032  }
3033  else
3034  aFormatBox.SetDistance(m_pActBand->mnDefaultBottom,SvxBoxItemLine::BOTTOM);
3035 
3036  // nGapHalf for WW is a *horizontal* gap between table cell and content.
3037  short nLeftDist =
3039  short nRightDist =
3041  if (m_pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwLEFT))
3042  {
3043  aFormatBox.SetDistance(
3045  SvxBoxItemLine::LEFT);
3046  }
3047  else
3048  aFormatBox.SetDistance(nLeftDist, SvxBoxItemLine::LEFT);
3049  if (m_pActBand->nOverrideSpacing[nWwIdx] & (1 << WW8TabBandDesc::wwRIGHT))
3050  {
3051  aFormatBox.SetDistance(
3053  SvxBoxItemLine::RIGHT);
3054  }
3055  else
3056  aFormatBox.SetDistance(nRightDist,SvxBoxItemLine::RIGHT);
3057 
3058  pBox->GetFrameFormat()->SetFormatAttr(aFormatBox);
3059 }
3060 
3061 void WW8TabDesc::SetTabShades( SwTableBox* pBox, short nWwIdx )
3062 {
3063  if( nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols )
3064  return; // faked cells -> no color
3065 
3066  bool bFound=false;
3067  if (m_pActBand->pNewSHDs && m_pActBand->pNewSHDs[nWwIdx] != COL_AUTO)
3068  {
3069  Color aColor(m_pActBand->pNewSHDs[nWwIdx]);
3071  bFound = true;
3072  }
3073 
3074  //If there was no new shades, or no new shade setting
3075  if (m_pActBand->pSHDs && !bFound)
3076  {
3077  WW8_SHD& rSHD = m_pActBand->pSHDs[nWwIdx];
3078  if (!rSHD.GetValue()) // auto
3079  return;
3080 
3081  SwWW8Shade aSh( m_pIo->m_bVer67, rSHD );
3083  }
3084 }
3085 
3086 static SvxFrameDirection MakeDirection(sal_uInt16 nCode, bool bIsBiDi)
3087 {
3088  SvxFrameDirection eDir = SvxFrameDirection::Environment;
3089  // 1: Asian layout with rotated CJK characters
3090  // 5: Asian layout
3091  // 3: Western layout rotated by 90 degrees
3092  // 4: Western layout
3093  switch (nCode)
3094  {
3095  default:
3096  OSL_ENSURE(eDir == SvxFrameDirection::Environment, "unknown direction code, maybe it's a bitfield");
3097  [[fallthrough]];
3098  case 3:
3099  eDir = SvxFrameDirection::Vertical_LR_BT;
3100  break;
3101  case 5:
3102  eDir = SvxFrameDirection::Vertical_RL_TB;
3103  break;
3104  case 1:
3105  eDir = SvxFrameDirection::Vertical_RL_TB;
3106  break;
3107  case 4:
3108  eDir = bIsBiDi ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB; // #i38158# - Consider RTL tables
3109  break;
3110  }
3111  return eDir;
3112 }
3113 
3114 void WW8TabDesc::SetTabDirection(SwTableBox* pBox, short nWwIdx)
3115 {
3116  if (nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols)
3117  return;
3119  pBox->GetFrameFormat()->SetFormatAttr(aItem);
3120 }
3121 
3122 void WW8TabDesc::SetTabVertAlign( SwTableBox* pBox, short nWwIdx )
3123 {
3124  if( nWwIdx < 0 || nWwIdx >= m_pActBand->nWwCols )
3125  return;
3126 
3127  sal_Int16 eVertOri=text::VertOrientation::TOP;
3128 
3129  if( m_pActBand->pTCs )
3130  {
3131  WW8_TCell* pT = &m_pActBand->pTCs[nWwIdx];
3132  switch (pT->nVertAlign)
3133  {
3134  case 0:
3135  default:
3136  eVertOri = text::VertOrientation::TOP;
3137  break;
3138  case 1:
3139  eVertOri = text::VertOrientation::CENTER;
3140  break;
3141  case 2:
3142  eVertOri = text::VertOrientation::BOTTOM;
3143  break;
3144  }
3145  }
3146 
3147  pBox->GetFrameFormat()->SetFormatAttr( SwFormatVertOrient(0,eVertOri) );
3148 }
3149 
3151 {
3152  if( m_pActBand->nSwCols > m_nDefaultSwCols ) // split cells
3154 
3155  SetPamInCell( 0, false);
3156  OSL_ENSURE( m_pTabBoxes && m_pTabBoxes->size() == static_cast<sal_uInt16>(m_pActBand->nSwCols),
3157  "Wrong column count in table" );
3158 
3159  if( m_bClaimLineFormat )
3160  {
3161  m_pTabLine->ClaimFrameFormat(); // necessary because of cell height
3162  SwFormatFrameSize aF( ATT_MIN_SIZE, 0, 0 ); // default
3163 
3164  if (m_pActBand->nLineHeight == 0) // 0 = Auto
3166  else
3167  {
3168  if (m_pActBand->nLineHeight < 0) // positive = min, negative = exact
3169  {
3172  }
3173  if (m_pActBand->nLineHeight < MINLAY) // invalid cell height
3175 
3176  aF.SetHeight(m_pActBand->nLineHeight);// set min/exact height
3177  }
3179  }
3180 
3181  //Word stores 1 for bCantSplit if the row cannot be split, we set true if
3182  //we can split the row
3183  bool bSetCantSplit = m_pActBand->bCantSplit;
3185 
3186  // if table is only a single row, and row is set as don't split, set the same value for the whole table.
3187  if (bSetCantSplit && m_pTabLines->size() == 1)
3189 
3190  short i; // SW-Index
3191  short j; // WW-Index
3192  short nW; // Width
3194  j = m_pActBand->bLEmptyCol ? -1 : 0;
3195 
3196  for( i = 0; i < m_pActBand->nSwCols; i++ )
3197  {
3198  // set cell width
3199  if( j < 0 )
3200  nW = m_pActBand->nCenter[0] - m_nMinLeft;
3201  else
3202  {
3203  //Set j to first non invalid cell
3204  while ((j < m_pActBand->nWwCols) && (!m_pActBand->bExist[j]))
3205  j++;
3206 
3207  if( j < m_pActBand->nWwCols )
3208  nW = m_pActBand->nCenter[j+1] - m_pActBand->nCenter[j];
3209  else
3210  nW = m_nMaxRight - m_pActBand->nCenter[j];
3211  m_pActBand->nWidth[ j ] = nW;
3212  }
3213 
3214  SwTableBox* pBox = (*m_pTabBoxes)[i];
3215  // could be reduced further by intelligent moving of FrameFormats
3216  pBox->ClaimFrameFormat();
3217 
3218  SetTabBorders(pBox, j);
3219 
3220  // #i18128# word has only one line between adjoining vertical cells
3221  // we have to mimic this in the filter by picking the larger of the
3222  // sides and using that one on one side of the line (right)
3223  SvxBoxItem aCurrentBox(sw::util::ItemGet<SvxBoxItem>(*(pBox->GetFrameFormat()), RES_BOX));
3224  if (i != 0)
3225  {
3226  SwTableBox* pBox2 = (*m_pTabBoxes)[i-1];
3227  SvxBoxItem aOldBox(sw::util::ItemGet<SvxBoxItem>(*(pBox2->GetFrameFormat()), RES_BOX));
3228  if( aOldBox.CalcLineWidth(SvxBoxItemLine::RIGHT) > aCurrentBox.CalcLineWidth(SvxBoxItemLine::LEFT) )
3229  aCurrentBox.SetLine(aOldBox.GetLine(SvxBoxItemLine::RIGHT), SvxBoxItemLine::LEFT);
3230 
3231  aOldBox.SetLine(nullptr, SvxBoxItemLine::RIGHT);
3232  pBox2->GetFrameFormat()->SetFormatAttr(aOldBox);
3233  }
3234 
3235  pBox->GetFrameFormat()->SetFormatAttr(aCurrentBox);
3236 
3237  SetTabVertAlign(pBox, j);
3238  SetTabDirection(pBox, j);
3240  SetTabShades(pBox, j);
3241  j++;
3242 
3243  aFS.SetWidth( nW );
3244  pBox->GetFrameFormat()->SetFormatAttr( aFS );
3245 
3246  // skip non existing cells
3247  while( ( j < m_pActBand->nWwCols ) && !m_pActBand->bExist[j] )
3248  {
3250  j++;
3251  }
3252  }
3253 }
3254 
3256 {
3258 
3259  // new line/row
3260  if( m_pIo->m_bWasTabRowEnd )
3261  {
3262  // bWasTabRowEnd will be deactivated in
3263  // SwWW8ImplReader::ProcessSpecial()
3264 
3265  sal_uInt16 iCol = GetLogicalWWCol();
3266  if (iCol < m_aNumRuleNames.size())
3267  {
3268  m_aNumRuleNames.erase(m_aNumRuleNames.begin() + iCol,
3269  m_aNumRuleNames.end());
3270  }
3271 
3272  m_nCurrentCol = 0;
3273  m_nCurrentRow++;
3275  OSL_ENSURE( m_pActBand , "pActBand is 0" );
3276  if( m_pActBand )
3277  {
3278  if( m_nCurrentRow >= m_nRows ) // nothing to at end of table
3279  return;
3280 
3281  bool bNewBand = m_nCurrentBandRow >= m_pActBand->nRows;
3282  if( bNewBand )
3283  { // new band needed ?
3285  m_nCurrentBandRow = 0;
3286  OSL_ENSURE( m_pActBand, "pActBand is 0" );
3287  AdjustNewBand();
3288  }
3289  else
3290  {
3291  SwTableBox* pBox = (*m_pTabBoxes)[0];
3292  SwSelBoxes aBoxes;
3293  m_pIo->m_rDoc.InsertRow( SwTable::SelLineFromBox( pBox, aBoxes ) );
3294  }
3295  }
3296  }
3297  else
3298  { // new column ( cell )
3299  m_nCurrentCol++;
3300  }
3301  SetPamInCell(m_nCurrentCol, true);
3302 
3303  // finish Annotated Level Numbering ?
3306 }
3307 
3308 // if necessary register the box for the merge group for this column
3310  WW8SelBoxInfo* pActGroup,
3311  SwTableBox* pActBox,
3312  sal_uInt16 nCol )
3313 {
3314  // check if the box has to be merged
3315  // If cell is the first one to be merged, a new merge group has to be provided.
3316  // E.g., it could be that a cell is the first one to be merged, but no
3317  // new merge group is provided, because the potential other cell to be merged
3318  // doesn't exist - see method <WW8TabDesc::MergeCells>.
3319  if ( m_pActBand->bExist[ nCol ] &&
3320  ( ( rCell.bFirstMerged && pActGroup ) ||
3321  rCell.bMerged ||
3322  rCell.bVertMerge ||
3323  rCell.bVertRestart ) )
3324  {
3325  // detect appropriate merge group
3326  WW8SelBoxInfo* pTheMergeGroup = nullptr;
3327  if( pActGroup )
3328  // assign group
3329  pTheMergeGroup = pActGroup;
3330  else
3331  {
3332  // find group
3333  pTheMergeGroup = FindMergeGroup(
3334  m_pActBand->nCenter[ nCol ], m_pActBand->nWidth[ nCol ], true );
3335  }
3336  if( pTheMergeGroup )
3337  {
3338  // add current box to merge group
3339  pTheMergeGroup->push_back(pActBox);
3340  }
3341  }
3342 }
3343 
3344 sal_uInt16 WW8TabDesc::GetLogicalWWCol() const // returns number of col as INDICATED within WW6 UI status line -1
3345 {
3346  sal_uInt16 nCol = 0;
3347  if( m_pActBand && m_pActBand->pTCs)
3348  {
3349  for( sal_uInt16 iCol = 1; iCol <= m_nCurrentCol && iCol <= m_pActBand->nWwCols; ++iCol )
3350  {
3351  if( !m_pActBand->pTCs[ iCol-1 ].bMerged )
3352  ++nCol;
3353  }
3354  }
3355  return nCol;
3356 }
3357 
3358 // find name of numrule valid for current WW-COL
3360 {
3361  sal_uInt16 nCol = GetLogicalWWCol();
3362  if (nCol < m_aNumRuleNames.size())
3363  return m_aNumRuleNames[nCol];
3364  return OUString();
3365 }
3366 
3367 void WW8TabDesc::SetNumRuleName( const OUString& rName )
3368 {
3369  sal_uInt16 nCol = GetLogicalWWCol();
3370  for (sal_uInt16 nSize = static_cast< sal_uInt16 >(m_aNumRuleNames.size()); nSize <= nCol; ++nSize)
3371  m_aNumRuleNames.emplace_back();
3372  m_aNumRuleNames[nCol] = rName;
3373 }
3374 
3376 {
3377  // Entering a table so make sure the FirstPara flag gets set
3378  m_bFirstPara = true;
3379  // no recursive table, not with InsertFile in table or foot note
3380  if (m_bReadNoTable)
3381  return false;
3382 
3383  if (m_xTableDesc)
3384  m_aTableStack.push(std::move(m_xTableDesc));
3385 
3386  // #i33818# - determine absolute position object attributes,
3387  // if possible. It's needed for nested tables.
3388  std::unique_ptr<WW8FlyPara> pTableWFlyPara;
3389  WW8SwFlyPara* pTableSFlyPara( nullptr );
3390  // #i45301# - anchor nested table inside Writer fly frame
3391  // only at-character, if absolute position object attributes are available.
3392  // Thus, default anchor type is as-character anchored.
3393  RndStdIds eAnchor( RndStdIds::FLY_AS_CHAR );
3394  if ( m_nInTable )
3395  {
3396  WW8_TablePos* pNestedTabPos( nullptr );
3397  WW8_TablePos aNestedTabPos;
3398  WW8PLCFxSave1 aSave;
3399  m_xPlcxMan->GetPap()->Save( aSave );
3400  WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
3401  WW8_CP nMyStartCp = nStartCp;
3402  if ( SearchRowEnd( pPap, nMyStartCp, m_nInTable ) &&
3403  ParseTabPos( &aNestedTabPos, pPap ) )
3404  {
3405  pNestedTabPos = &aNestedTabPos;
3406  }
3407  m_xPlcxMan->GetPap()->Restore( aSave );
3408  if ( pNestedTabPos )
3409  {
3410  ApoTestResults aApo = TestApo( m_nInTable + 1, false, pNestedTabPos );
3411  pTableWFlyPara = ConstructApo( aApo, pNestedTabPos );
3412  if ( pTableWFlyPara )
3413  {
3414  // <WW8SwFlyPara> constructor has changed - new 4th parameter
3415  // containing WW8 page top margin.
3416  pTableSFlyPara = new WW8SwFlyPara(*m_pPaM, *this, *pTableWFlyPara,
3420 
3421  // #i45301# - anchor nested table Writer fly frame at-character
3422  eAnchor = RndStdIds::FLY_AT_CHAR;
3423  }
3424  }
3425  }
3426  // if first paragraph in table has break-before-page, transfer that setting to the table itself.
3427  else if( StyleExists(m_nCurrentColl) )
3428  {
3429  const SwFormat* pStyleFormat = m_vColl[m_nCurrentColl].m_pFormat;
3430  if( pStyleFormat && pStyleFormat->GetBreak().GetBreak() == SvxBreak::PageBefore )
3431  NewAttr( pStyleFormat->GetBreak() );
3432  }
3433 
3434  m_xTableDesc.reset(new WW8TabDesc(this, nStartCp));
3435 
3436  if( m_xTableDesc->Ok() )
3437  {
3438  int nNewInTable = m_nInTable + 1;
3439 
3440  if ((eAnchor == RndStdIds::FLY_AT_CHAR)
3441  && !m_aTableStack.empty() && !InEqualApo(nNewInTable) )
3442  {
3443  m_xTableDesc->m_pParentPos = new SwPosition(*m_pPaM->GetPoint());
3444  SfxItemSet aItemSet(m_rDoc.GetAttrPool(),
3446  // #i33818# - anchor the Writer fly frame for the nested table at-character.
3447  // #i45301#
3448  SwFormatAnchor aAnchor( eAnchor );
3449  aAnchor.SetAnchor( m_xTableDesc->m_pParentPos );
3450  aItemSet.Put( aAnchor );
3451  m_xTableDesc->m_pFlyFormat = m_rDoc.MakeFlySection( eAnchor,
3452  m_xTableDesc->m_pParentPos, &aItemSet);
3453  OSL_ENSURE( m_xTableDesc->m_pFlyFormat->GetAnchor().GetAnchorId() == eAnchor,
3454  "Not the anchor type requested!" );
3455  MoveInsideFly(m_xTableDesc->m_pFlyFormat);
3456  }
3457  m_xTableDesc->CreateSwTable();
3458  if (m_xTableDesc->m_pFlyFormat)
3459  {
3460  m_xTableDesc->SetSizePosition(m_xTableDesc->m_pFlyFormat);
3461  // #i33818# - Use absolute position object attributes,
3462  // if existing, and apply them to the created Writer fly frame.
3463  if ( pTableWFlyPara && pTableSFlyPara )
3464  {
3465  WW8FlySet aFlySet( *this, pTableWFlyPara.get(), pTableSFlyPara, false );
3466  SwFormatAnchor aAnchor( RndStdIds::FLY_AT_CHAR );
3467  aAnchor.SetAnchor( m_xTableDesc->m_pParentPos );
3468  aFlySet.Put( aAnchor );
3469  m_xTableDesc->m_pFlyFormat->SetFormatAttr( aFlySet );
3470  }
3471  else
3472  {
3473  SwFormatHoriOrient aHori =
3474  m_xTableDesc->m_pTable->GetFrameFormat()->GetHoriOrient();
3475  m_xTableDesc->m_pFlyFormat->SetFormatAttr(aHori);
3476  m_xTableDesc->m_pFlyFormat->SetFormatAttr( SwFormatSurround( css::text::WrapTextMode_NONE ) );
3477  }
3478  // #i33818# - The nested table doesn't have to leave
3479  // the table cell. Thus, the Writer fly frame has to follow the text flow.
3480  m_xTableDesc->m_pFlyFormat->SetFormatAttr( SwFormatFollowTextFlow( true ) );
3481  }
3482  else
3483  m_xTableDesc->SetSizePosition(nullptr);
3484  m_xTableDesc->UseSwTable();
3485  }
3486  else
3487  PopTableDesc();
3488 
3489  // #i33818#
3490  delete pTableSFlyPara;
3491 
3492  return m_xTableDesc != nullptr;
3493 }
3494 
3496 {
3497  if (m_nInTable && m_xTableDesc)
3498  m_xTableDesc->TableCellEnd();
3499 
3500  m_bFirstPara = true; // We have come to the end of a cell so FirstPara flag
3501  m_bReadTable = false;
3502 }
3503 
3504 void SwWW8ImplReader::Read_TabCellEnd( sal_uInt16, const sal_uInt8* pData, short nLen)
3505 {
3506  if( ( nLen > 0 ) && ( *pData == 1 ) )
3507  m_bWasTabCellEnd = true;
3508 }
3509 
3510 void SwWW8ImplReader::Read_TabRowEnd( sal_uInt16, const sal_uInt8* pData, short nLen ) // Sprm25
3511 {
3512  if( ( nLen > 0 ) && ( *pData == 1 ) )
3513  m_bWasTabRowEnd = true;
3514 }
3515 
3517 {
3518  if (m_xTableDesc && m_xTableDesc->m_pFlyFormat)
3519  {
3520  MoveOutsideFly(m_xTableDesc->m_pFlyFormat, *m_xTableDesc->m_pParentPos);
3521  }
3522 
3523  m_xTableDesc.reset();
3524  if (!m_aTableStack.empty())
3525  {
3526  m_xTableDesc = std::move(m_aTableStack.top());
3527  m_aTableStack.pop();
3528  }
3529 }
3530 
3532 {
3533  OSL_ENSURE(m_xTableDesc, "Panic, stop table with no table!");
3534  if (!m_xTableDesc)
3535  return;
3536 
3537  // We are leaving a table so make sure the next paragraph doesn't think
3538  // it's the first paragraph
3539  m_bFirstPara = false;
3540 
3541  m_xTableDesc->FinishSwTable();
3542  PopTableDesc();
3543 
3544  m_bReadTable = true;
3545 }
3546 
3548 {
3549  if( !m_xTableDesc )
3550  return false;
3551 
3552  const WW8_TCell* pCell = m_xTableDesc->GetCurrentWWCell();
3553 
3554  return !m_xTableDesc->IsValidCell( m_xTableDesc->GetCurrentCol() )
3555  || ( pCell
3556  && ( !pCell->bFirstMerged
3557  && ( pCell->bMerged
3558  || ( pCell->bVertMerge
3559  && !pCell->bVertRestart
3560  )
3561  )
3562  )
3563  );
3564 }
3565 
3566 sal_uInt16 SwWW8ImplReader::StyleUsingLFO( sal_uInt16 nLFOIndex ) const
3567 {
3568  sal_uInt16 nRes = USHRT_MAX;
3569  if( !m_vColl.empty() )
3570  {
3571  for(sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); nI++ )
3572  if( m_vColl[ nI ].m_bValid
3573  && (nLFOIndex == m_vColl[ nI ].m_nLFOIndex) )
3574  nRes = nI;
3575  }
3576  return nRes;
3577 }
3578 
3579 const SwFormat* SwWW8ImplReader::GetStyleWithOrgWWName( OUString const & rName ) const
3580 {
3581  SwFormat* pRet = nullptr;
3582  if( !m_vColl.empty() )
3583  {
3584  for(sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); nI++ )
3585  if( m_vColl[ nI ].m_bValid
3586  && (rName == m_vColl[ nI ].GetOrgWWName()) )
3587  {
3588  pRet = m_vColl[ nI ].m_pFormat;
3589  break;
3590  }
3591  }
3592  return pRet;
3593 }
3594 
3595 // class WW8RStyle
3596 
3597 SprmResult WW8RStyle::HasParaSprm(sal_uInt16 nId) const
3598 {
3599  if( !mpParaSprms || !mnSprmsLen )
3600  return SprmResult();
3601 
3603 }
3604 
3605 void WW8RStyle::ImportSprms(sal_uInt8 *pSprms, short nLen, bool bPap)
3606 {
3607  if (!nLen)
3608  return;
3609 
3610  if( bPap )
3611  {
3612  mpParaSprms = pSprms; // for HasParaSprms()
3613  mnSprmsLen = nLen;
3614  }
3615 
3616  WW8SprmIter aSprmIter(pSprms, nLen, maSprmParser);
3617  while (const sal_uInt8* pSprm = aSprmIter.GetSprms())
3618  {
3619 #ifdef DEBUGSPRMREADER
3620  fprintf(stderr, "id is %x\n", aIter.GetCurrentId());
3621 #endif
3622  mpIo->ImportSprm(pSprm, aSprmIter.GetRemLen(), aSprmIter.GetCurrentId());
3623  aSprmIter.advance();
3624  }
3625 
3626  mpParaSprms = nullptr;
3627  mnSprmsLen = 0;
3628 }
3629 
3630 void WW8RStyle::ImportSprms(std::size_t nPosFc, short nLen, bool bPap)
3631 {
3632  if (!nLen)
3633  return;
3634 
3635  if (checkSeek(*mpStStrm, nPosFc))
3636  {
3637  std::unique_ptr<sal_uInt8[]> pSprms( new sal_uInt8[nLen] );
3638  nLen = mpStStrm->ReadBytes(pSprms.get(), nLen);
3639  ImportSprms(pSprms.get(), nLen, bPap);
3640  }
3641 }
3642 
3643 static short WW8SkipOdd(SvStream* pSt )
3644 {
3645  if ( pSt->Tell() & 0x1 )
3646  {
3647  sal_uInt8 c;
3648  return pSt->ReadBytes( &c, 1 );
3649  }
3650  return 0;
3651 }
3652 
3653 static short WW8SkipEven(SvStream* pSt )
3654 {
3655  if (!(pSt->Tell() & 0x1))
3656  {
3657  sal_uInt8 c;
3658  return pSt->ReadBytes( &c, 1 );
3659  }
3660  return 0;
3661 }
3662 
3663 short WW8RStyle::ImportUPX(short nLen, bool bPAP, bool bOdd)
3664 {
3665  if( 0 < nLen ) // Empty ?
3666  {
3667  if (bOdd)
3668  nLen = nLen - WW8SkipEven( mpStStrm );
3669  else
3670  nLen = nLen - WW8SkipOdd( mpStStrm );
3671 
3672  sal_Int16 cbUPX(0);
3673  mpStStrm->ReadInt16( cbUPX );
3674 
3675  nLen-=2;
3676 
3677  if ( cbUPX > nLen )
3678  cbUPX = nLen; // shrink cbUPX to nLen
3679 
3680  if( (1 < cbUPX) || ( (0 < cbUPX) && !bPAP ) )
3681  {
3682  if( bPAP )
3683  {
3684  sal_uInt16 id;
3685  mpStStrm->ReadUInt16( id );
3686 
3687  cbUPX-= 2;
3688  nLen-= 2;
3689  }
3690 
3691  if( 0 < cbUPX )
3692  {
3693  sal_uInt64 const nPos = mpStStrm->Tell(); // if something is interpreted wrong,
3694  // this should make it work again
3695  ImportSprms( nPos, cbUPX, bPAP );
3696 
3697  if ( mpStStrm->Tell() != nPos + cbUPX )
3698  mpStStrm->Seek( nPos+cbUPX );
3699 
3700  nLen = nLen - cbUPX;
3701  }
3702  }
3703  }
3704  return nLen;
3705 }
3706 
3707 void WW8RStyle::ImportGrupx(short nLen, bool bPara, bool bOdd)
3708 {
3709  if( nLen <= 0 )
3710  return;
3711  if (bOdd)
3712  nLen = nLen - WW8SkipEven( mpStStrm );
3713  else
3714  nLen = nLen - WW8SkipOdd( mpStStrm );
3715 
3716  if( bPara ) // Grupx.Papx
3717  nLen = ImportUPX(nLen, true, bOdd);
3718  ImportUPX(nLen, false, bOdd); // Grupx.Chpx
3719 }
3720 
3722  : WW8Style(*pI->m_pTableStream, _rFib)
3723  , maSprmParser(_rFib)
3724  , mpIo(pI)
3725  , mpStStrm(pI->m_pTableStream)
3726  , mpStyRule(nullptr)
3727  , mpParaSprms(nullptr)
3728  , mnSprmsLen(0)
3729  , mnWwNumLevel(0)
3730  , mbTextColChanged(false)
3731  , mbFontChanged(false)
3732  , mbCJKFontChanged(false)
3733  , mbCTLFontChanged(false)
3734  , mbFSizeChanged(false)
3735  , mbFCTLSizeChanged(false)
3736  , mbWidowsChanged(false)
3737 {
3738  mpIo->m_vColl.resize(m_cstd);
3739 }
3740 
3742 {
3743  // see #i25247#, #i25561#, #i48064#, #i92341# for default font
3744  if (!mbCJKFontChanged) // Style no CJK Font? set the default
3746 
3747  if (!mbCTLFontChanged) // Style no CTL Font? set the default
3749 
3750  // western 2nd to make western charset conversion the default
3751  if (!mbFontChanged) // Style has no Font? set the default,
3753 
3754  if( !mpIo->m_bNoAttrImport )
3755  {
3756  // Style has no text color set, winword default is auto
3757  if ( !mbTextColChanged )
3759 
3760  // Style has no FontSize ? WinWord Default is 10pt for western and asian
3761  if( !mbFSizeChanged )
3762  {
3763  SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3765  aAttr.SetWhich(RES_CHRATR_CJK_FONTSIZE);
3767  }
3768 
3769  // Style has no FontSize ? WinWord Default is 10pt for western and asian
3770  if( !mbFCTLSizeChanged )
3771  {
3772  SvxFontHeightItem aAttr(200, 100, RES_CHRATR_FONTSIZE);
3773  aAttr.SetWhich(RES_CHRATR_CTL_FONTSIZE);
3775  }
3776 
3777  if( !mbWidowsChanged ) // Widows ?
3778  {
3781  }
3782  }
3783 }
3784 
3785 bool WW8RStyle::PrepareStyle(SwWW8StyInf &rSI, ww::sti eSti, sal_uInt16 nThisStyle, sal_uInt16 nNextStyle)
3786 {
3787  SwFormat* pColl;
3788  bool bStyExist;
3789 
3790  if (rSI.m_bColl)
3791  {
3792  // Para-Style
3795  pColl = aResult.first;
3796  bStyExist = aResult.second;
3797  }
3798  else
3799  {
3800  // Char-Style
3803  pColl = aResult.first;
3804  bStyExist = aResult.second;
3805  }
3806 
3807  bool bImport = !bStyExist || mpIo->m_bNewDoc; // import content ?
3808 
3809  // Do not override character styles the list import code created earlier.
3810  if (bImport && bStyExist && rSI.GetOrgWWName().startsWith("WW8Num"))
3811  bImport = false;
3812 
3813  bool bOldNoImp = mpIo->m_bNoAttrImport;
3814  rSI.m_bImportSkipped = !bImport;
3815 
3816  if( !bImport )
3817  mpIo->m_bNoAttrImport = true;
3818  else
3819  {
3820  if (bStyExist)
3821  {
3822  pColl->ResetAllFormatAttr(); // #i73790# - method renamed
3823  }
3824  pColl->SetAuto(false); // suggested by JP
3825  } // but changes the UI
3826  mpIo->m_pCurrentColl = pColl;
3827  rSI.m_pFormat = pColl; // remember translation WW->SW
3828  rSI.m_bImportSkipped = !bImport;
3829 
3830  // Set Based on style
3831  sal_uInt16 j = rSI.m_nBase;
3832  if (j != nThisStyle && j < m_cstd )
3833  {
3834  SwWW8StyInf* pj = &mpIo->m_vColl[j];
3835  if (rSI.m_pFormat && pj->m_pFormat && rSI.m_bColl == pj->m_bColl)
3836  {
3837  rSI.m_pFormat->SetDerivedFrom( pj->m_pFormat ); // ok, set Based on
3841  rSI.m_n81Flags = pj->m_n81Flags;
3842  rSI.m_n81BiDiFlags = pj->m_n81BiDiFlags;
3843  if (!rSI.IsWW8BuiltInHeadingStyle())
3844  {
3846  }
3849 
3850  if (pj->m_xWWFly)
3851  rSI.m_xWWFly.reset(new WW8FlyPara(mpIo->m_bVer67, pj->m_xWWFly.get()));
3852  }
3853  }
3854  else if( mpIo->m_bNewDoc && bStyExist )
3855  rSI.m_pFormat->SetDerivedFrom();
3856 
3857  rSI.m_nFollow = nNextStyle; // remember Follow
3858 
3859  mpStyRule = nullptr; // recreate if necessary
3862  mpIo->SetNCurrentColl( nThisStyle );
3863  mpIo->m_bStyNormal = nThisStyle == 0;
3864  return bOldNoImp;
3865 }
3866 
3867 void WW8RStyle::PostStyle(SwWW8StyInf const &rSI, bool bOldNoImp)
3868 {
3869  // Reset attribute flags, because there are no style-ends.
3870 
3871  mpIo->m_bHasBorder = mpIo->m_bSpec = mpIo->m_bObj = mpIo->m_bSymbol = false;
3872  mpIo->m_nCharFormat = -1;
3873 
3874  // if style is based on nothing or base ignored
3875  if ((rSI.m_nBase >= m_cstd || mpIo->m_vColl[rSI.m_nBase].m_bImportSkipped) && rSI.m_bColl)
3876  {
3877  // If Char-Styles does not work
3878  // -> set hard WW-Defaults
3880  }
3881 
3882  mpStyRule = nullptr; // to be on the safe side
3883  mpIo->m_bStyNormal = false;
3884  mpIo->SetNCurrentColl( 0 );
3885  mpIo->m_bNoAttrImport = bOldNoImp;
3886  // reset the list-remember-fields, if used when reading styles
3889 }
3890 
3891 void WW8RStyle::Import1Style( sal_uInt16 nNr )
3892 {
3893  if (nNr >= mpIo->m_vColl.size())
3894  return;
3895 
3896  SwWW8StyInf &rSI = mpIo->m_vColl[nNr];
3897 
3898  if( rSI.m_bImported || !rSI.m_bValid )
3899  return;
3900 
3901  rSI.m_bImported = true; // set flag now to avoid endless loops
3902 
3903  // valid and not NUL and not yet imported
3904 
3905  if( rSI.m_nBase < m_cstd && !mpIo->m_vColl[rSI.m_nBase].m_bImported )
3906  Import1Style( rSI.m_nBase );
3907 
3908  mpStStrm->Seek( rSI.m_nFilePos );
3909 
3910  sal_uInt16 nSkip;
3911  OUString sName;
3912 
3913  std::unique_ptr<WW8_STD> xStd(Read1Style(nSkip, &sName));// read Style
3914 
3915  if (xStd)
3916  rSI.SetOrgWWIdent( sName, xStd->sti );
3917 
3918  // either no Name or unused Slot or unknown Style
3919 
3920  if ( !xStd || sName.isEmpty() || ((1 != xStd->sgc) && (2 != xStd->sgc)) )
3921  {
3922  nSkip = std::min<sal_uInt64>(nSkip, mpStStrm->remainingSize());
3923  mpStStrm->Seek(mpStStrm->Tell() + nSkip);
3924  return;
3925  }
3926 
3927  bool bOldNoImp = PrepareStyle(rSI, static_cast<ww::sti>(xStd->sti), nNr, xStd->istdNext);
3928 
3929  // if something is interpreted wrong, this should make it work again
3930  long nPos = mpStStrm->Tell();
3931 
3932  //Variable parts of the STD start at even byte offsets, but "inside
3933  //the STD", which I take to meaning even in relation to the starting
3934  //position of the STD, which matches findings in #89439#, generally it
3935  //doesn't matter as the STSHI starts off nearly always on an even
3936  //offset
3937 
3938  //Import of the Style Contents
3939  ImportGrupx(nSkip, xStd->sgc == 1, rSI.m_nFilePos & 1);
3940 
3941  PostStyle(rSI, bOldNoImp);
3942 
3943  mpStStrm->Seek( nPos+nSkip );
3944 }
3945 
3946 void WW8RStyle::RecursiveReg(sal_uInt16 nNr)
3947 {
3948  if (nNr >= mpIo->m_vColl.size())
3949  return;
3950 
3951  SwWW8StyInf &rSI = mpIo->m_vColl[nNr];
3952  if( rSI.m_bImported || !rSI.m_bValid )
3953  return;
3954 
3955  rSI.m_bImported = true;
3956 
3957  if( rSI.m_nBase < m_cstd && !mpIo->m_vColl[rSI.m_nBase].m_bImported )
3958  RecursiveReg(rSI.m_nBase);
3959 
3961 
3962 }
3963 
3964 /*
3965  After all styles are imported then we can recursively apply numbering
3966  styles to them, and change their tab stop settings if they turned out
3967  to have special first line indentation.
3968 */
3970 {
3971  sal_uInt16 i;
3972  /*
3973  Clear all imported flags so that we can recursively apply numbering
3974  formats and use it to mark handled ones
3975  */
3976  for (i=0; i < m_cstd; ++i)
3977  mpIo->m_vColl[i].m_bImported = false;
3978 
3979  /*
3980  Register the num formats and tabstop changes on the styles recursively.
3981  */
3982 
3983  /*
3984  In the same loop apply the tabstop changes required because we need to
3985  change their location if there's a special indentation for the first line,
3986  By avoiding making use of each styles margins during reading of their
3987  tabstops we don't get problems with doubly adjusting tabstops that
3988  are inheritied.
3989  */
3990  for (i=0; i < m_cstd; ++i)
3991  {
3992  if (mpIo->m_vColl[i].m_bValid)
3993  {
3994  RecursiveReg(i);
3995  }
3996  }
3997 }
3998 
3999 void WW8RStyle::ScanStyles() // investigate style dependencies
4000 { // and detect Filepos for each Style
4001  for (sal_uInt16 i = 0; i < m_cstd; ++i)
4002  {
4003  SwWW8StyInf &rSI = mpIo->m_vColl[i];
4004 
4005  rSI.m_nFilePos = mpStStrm->Tell(); // remember FilePos
4006  sal_uInt16 nSkip;
4007  std::unique_ptr<WW8_STD> xStd(Read1Style(nSkip, nullptr)); // read STD
4008  rSI.m_bValid = xStd != nullptr;
4009  if (rSI.m_bValid)
4010  {
4011  rSI.m_nBase = xStd->istdBase; // remember Basis
4012  rSI.m_bColl = xStd->sgc == 1; // Para-Style
4013  }
4014  else
4015  rSI = SwWW8StyInf();
4016 
4017  xStd.reset();
4018  nSkip = std::min<sal_uInt64>(nSkip, mpStStrm->remainingSize());
4019  mpStStrm->Seek(mpStStrm->Tell() + nSkip); // skip Names and Sprms
4020  }
4021 }
4022 
4023 std::vector<sal_uInt8> ChpxToSprms(const Word2CHPX &rChpx)
4024 {
4025  std::vector<sal_uInt8> aRet;
4026 
4027  aRet.push_back(60);
4028  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBold) );
4029 
4030  aRet.push_back(61);
4031  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalic) );
4032 
4033  aRet.push_back(62);
4034  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fStrike) );
4035 
4036  aRet.push_back(63);
4037  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fOutline) );
4038 
4039  aRet.push_back(65);
4040  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fSmallCaps) );
4041 
4042  aRet.push_back(66);
4043  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fCaps) );
4044 
4045  aRet.push_back(67);
4046  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fVanish) );
4047 
4048  if (rChpx.fsFtc)
4049  {
4050  aRet.push_back(68);
4051  SVBT16 a;
4052  ShortToSVBT16(rChpx.ftc, a);
4053  aRet.push_back(a[1]);
4054  aRet.push_back(a[0]);
4055  }
4056 
4057  if (rChpx.fsKul)
4058  {
4059  aRet.push_back(69);
4060  aRet.push_back(rChpx.kul);
4061  }
4062 
4063  if (rChpx.fsLid)
4064  {
4065  aRet.push_back(72);
4066  SVBT16 a;
4067  ShortToSVBT16(rChpx.lid, a);
4068  aRet.push_back(a[1]);
4069  aRet.push_back(a[0]);
4070  }
4071 
4072  if (rChpx.fsIco)
4073  {
4074  aRet.push_back(73);
4075  aRet.push_back(rChpx.ico);
4076  }
4077 
4078  if (rChpx.fsHps)
4079  {
4080  aRet.push_back(74);
4081 
4082  SVBT16 a;
4083  ShortToSVBT16(rChpx.hps, a);
4084  aRet.push_back(a[0]);
4085  }
4086 
4087  if (rChpx.fsPos)
4088  {
4089  aRet.push_back(76);
4090  aRet.push_back(rChpx.hpsPos);
4091  }
4092 
4093  aRet.push_back(80);
4094  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fBoldBi) );
4095 
4096  aRet.push_back(81);
4097  aRet.push_back( static_cast< sal_uInt8 >(128 + rChpx.fItalicBi) );
4098 
4099  if (rChpx.fsFtcBi)
4100  {
4101  aRet.push_back(82);
4102  SVBT16 a;
4103  ShortToSVBT16(rChpx.fsFtcBi, a);
4104  aRet.push_back(a[1]);
4105  aRet.push_back(a[0]);
4106  }
4107 
4108  if (rChpx.fsLidBi)
4109  {
4110  aRet.push_back(83);
4111  SVBT16 a;
4112  ShortToSVBT16(rChpx.lidBi, a);
4113  aRet.push_back(a[1]);
4114  aRet.push_back(a[0]);
4115  }
4116 
4117  if (rChpx.fsIcoBi)
4118  {
4119  aRet.push_back(84);
4120  aRet.push_back(rChpx.icoBi);
4121  }
4122 
4123  if (rChpx.fsHpsBi)
4124  {
4125  aRet.push_back(85);
4126  SVBT16 a;
4127  ShortToSVBT16(rChpx.hpsBi, a);
4128  aRet.push_back(a[1]);
4129  aRet.push_back(a[0]);
4130  }
4131 
4132  return aRet;
4133 }
4134 
4135 Word2CHPX ReadWord2Chpx(SvStream &rSt, std::size_t nOffset, sal_uInt8 nSize)
4136 {
4137  Word2CHPX aChpx;
4138 
4139  if (!nSize)
4140  return aChpx;
4141 
4142  rSt.Seek(nOffset);
4143 
4144  sal_uInt8 nCount=0;
4145 
4146  while (true)
4147  {
4148  sal_uInt8 nFlags8;
4149  rSt.ReadUChar( nFlags8 );
4150  nCount++;
4151 
4152  aChpx.fBold = nFlags8 & 0x01;
4153  aChpx.fItalic = (nFlags8 & 0x02) >> 1;
4154  aChpx.fRMarkDel = (nFlags8 & 0x04) >> 2;
4155  aChpx.fOutline = (nFlags8 & 0x08) >> 3;
4156  aChpx.fFieldVanish = (nFlags8 & 0x10) >> 4;
4157  aChpx.fSmallCaps = (nFlags8 & 0x20) >> 5;
4158  aChpx.fCaps = (nFlags8 & 0x40) >> 6;
4159  aChpx.fVanish = (nFlags8 & 0x80) >> 7;
4160 
4161  if (nCount >= nSize) break;
4162  rSt.ReadUChar( nFlags8 );
4163  nCount++;
4164 
4165  aChpx.fRMark = nFlags8 & 0x01;
4166  aChpx.fSpec = (nFlags8 & 0x02) >> 1;
4167  aChpx.fStrike = (nFlags8 & 0x04) >> 2;
4168  aChpx.fObj = (nFlags8 & 0x08) >> 3;
4169  aChpx.fBoldBi = (nFlags8 & 0x10) >> 4;
4170  aChpx.fItalicBi = (nFlags8 & 0x20) >> 5;
4171  aChpx.fBiDi = (nFlags8 & 0x40) >> 6;
4172  aChpx.fDiacUSico = (nFlags8 & 0x80) >> 7;
4173 
4174  if (nCount >= nSize) break;
4175  rSt.ReadUChar( nFlags8 );
4176  nCount++;
4177 
4178  aChpx.fsIco = nFlags8 & 0x01;
4179  aChpx.fsFtc = (nFlags8 & 0x02) >> 1;
4180  aChpx.fsHps = (nFlags8 & 0x04) >> 2;
4181  aChpx.fsKul = (nFlags8 & 0x08) >> 3;
4182  aChpx.fsPos = (nFlags8 & 0x10) >> 4;
4183  aChpx.fsSpace = (nFlags8 & 0x20) >> 5;
4184  aChpx.fsLid = (nFlags8 & 0x40) >> 6;
4185  aChpx.fsIcoBi = (nFlags8 & 0x80) >> 7;
4186 
4187  if (nCount >= nSize) break;
4188  rSt.ReadUChar( nFlags8 );
4189  nCount++;
4190 
4191  aChpx.fsFtcBi = nFlags8 & 0x01;
4192  aChpx.fsHpsBi = (nFlags8 & 0x02) >> 1;
4193  aChpx.fsLidBi = (nFlags8 & 0x04) >> 2;
4194 
4195  if (nCount >= nSize) break;
4196  rSt.ReadUInt16( aChpx.ftc );
4197  nCount+=2;
4198 
4199  if (nCount >= nSize) break;
4200  rSt.ReadUInt16( aChpx.hps );
4201  nCount+=2;
4202 
4203  if (nCount >= nSize) break;
4204  rSt.ReadUChar( nFlags8 );
4205  nCount++;
4206 
4207  aChpx.qpsSpace = nFlags8 & 0x3F;
4208  aChpx.fSysVanish = (nFlags8 & 0x40) >> 6;
4209  aChpx.fNumRun = (nFlags8 & 0x80) >> 7;
4210 
4211  if (nCount >= nSize) break;
4212  rSt.ReadUChar( nFlags8 );
4213  nCount++;
4214 
4215  aChpx.ico = nFlags8 & 0x1F;
4216  aChpx.kul = (nFlags8 & 0xE0) >> 5;
4217 
4218  if (nCount >= nSize) break;
4219  rSt.ReadUChar( aChpx.hpsPos );
4220  nCount++;
4221 
4222  if (nCount >= nSize) break;
4223  rSt.ReadUChar( aChpx.icoBi );
4224  nCount++;
4225 
4226  if (nCount >= nSize) break;
4227  rSt.ReadUInt16( aChpx.lid );
4228  nCount+=2;
4229 
4230  if (nCount >= nSize) break;
4231  rSt.ReadUInt16( aChpx.ftcBi );
4232  nCount+=2;
4233 
4234  if (nCount >= nSize) break;
4235  rSt.ReadUInt16( aChpx.hpsBi );
4236  nCount+=2;
4237 
4238  if (nCount >= nSize) break;
4239  rSt.ReadUInt16( aChpx.lidBi );
4240  nCount+=2;
4241 
4242  if (nCount >= nSize) break;
4243  rSt.ReadUInt32( aChpx.fcPic );
4244  nCount+=4;
4245 
4246  break;
4247  }
4248 
4249  rSt.SeekRel(nSize-nCount);
4250  return aChpx;
4251 }
4252 
4253 namespace
4254 {
4255  struct pxoffset { std::size_t mnOffset; sal_uInt8 mnSize; };
4256 }
4257 
4259 {
4260  for (sal_uInt16 i=0; i < m_cstd; ++i)
4261  {
4262  mpIo->m_vColl[i].m_bColl = true;
4263  //every chain must end eventually at the null style (style code 222)
4264  mpIo->m_vColl[i].m_nBase = 222;
4265  }
4266 
4267  rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(
4268  mpIo->m_xWwFib->m_chseTables, mpIo->m_xWwFib->m_lid);
4269 
4270  sal_uInt16 cstcStd(0);
4271  m_rStream.ReadUInt16( cstcStd );
4272 
4273  size_t nMaxByteCount = m_rStream.remainingSize();
4274  sal_uInt16 cbName(0);
4275  m_rStream.ReadUInt16(cbName);
4276  if (cbName > nMaxByteCount)
4277  {
4278  SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4279  << cbName << " to " << nMaxByteCount);
4280  cbName = nMaxByteCount;
4281  }
4282  sal_uInt16 nByteCount = 2;
4283  sal_uInt16 stcp=0;
4284  while (nByteCount < cbName)
4285  {
4286  sal_uInt8 nCount(0);
4287  m_rStream.ReadUChar( nCount );
4288  nByteCount++;
4289 
4290  sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4291  if (stc >=mpIo->m_vColl.size())
4292  continue;
4293 
4294  SwWW8StyInf &rSI = mpIo->m_vColl[stc];
4295  OUString sName;
4296 
4297  if (nCount != 0xFF) // undefined style
4298  {
4299  if (nCount != 0) // user style
4300  {
4301  OString aTmp = read_uInt8s_ToOString(m_rStream, nCount);
4302  nByteCount += aTmp.getLength();
4303  sName = OStringToOUString(aTmp, eStructChrSet);
4304  }
4305  rSI.m_bImported = true;
4306  }
4307 
4308  if (sName.isEmpty())
4309  {
4310  ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4311  if (const sal_Char *pStr = GetEnglishNameFromSti(eSti))
4312  sName = OUString(pStr, strlen(pStr), RTL_TEXTENCODING_ASCII_US);
4313  }
4314 
4315  if (sName.isEmpty())
4316  sName = "Unknown Style: " + OUString::number(stc);
4317 
4318  rSI.SetOrgWWIdent(sName, stc);
4319  stcp++;
4320  }
4321 
4322  sal_uInt16 nStyles=stcp;
4323 
4324  std::vector<pxoffset> aCHPXOffsets(stcp);
4325  nMaxByteCount = m_rStream.remainingSize();
4326  sal_uInt16 cbChpx(0);
4327  m_rStream.ReadUInt16(cbChpx);
4328  if (cbChpx > nMaxByteCount)
4329  {
4330  SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4331  << cbChpx << " to " << nMaxByteCount);
4332  cbChpx = nMaxByteCount;
4333  }
4334  nByteCount = 2;
4335  stcp=0;
4336  std::vector< std::vector<sal_uInt8> > aConvertedChpx;
4337  while (nByteCount < cbChpx)
4338  {
4339  if (stcp == aCHPXOffsets.size())
4340  {
4341  //more data than style slots, skip remainder
4342  m_rStream.SeekRel(cbChpx-nByteCount);
4343  break;
4344  }
4345 
4346  sal_uInt8 cb(0);
4347  m_rStream.ReadUChar( cb );
4348  nByteCount++;
4349 
4350  aCHPXOffsets[stcp].mnSize = 0;
4351 
4352  if (cb != 0xFF)
4353  {
4354  sal_uInt8 nRemainder = cb;
4355 
4356  aCHPXOffsets[stcp].mnOffset = m_rStream.Tell();
4357  aCHPXOffsets[stcp].mnSize = nRemainder;
4358 
4359  Word2CHPX aChpx = ReadWord2Chpx(m_rStream, aCHPXOffsets[stcp].mnOffset,
4360  aCHPXOffsets[stcp].mnSize);
4361  aConvertedChpx.push_back( ChpxToSprms(aChpx) );
4362 
4363  nByteCount += nRemainder;
4364  }
4365  else
4366  aConvertedChpx.emplace_back( );
4367 
4368  ++stcp;
4369  }
4370 
4371  std::vector<pxoffset> aPAPXOffsets(stcp);
4372  nMaxByteCount = m_rStream.remainingSize();
4373  sal_uInt16 cbPapx(0);
4374  m_rStream.ReadUInt16(cbPapx);
4375  if (cbPapx > nMaxByteCount)
4376  {
4377  SAL_WARN("sw.ww8", "WW8RStyle::ImportOldFormatStyles: truncating out of range "
4378  << cbPapx << " to " << nMaxByteCount);
4379  cbPapx = nMaxByteCount;
4380  }
4381  nByteCount = 2;
4382  stcp=0;
4383  while (nByteCount < cbPapx)
4384  {
4385  if (stcp == aPAPXOffsets.size())
4386  {
4387  m_rStream.SeekRel(cbPapx-nByteCount);
4388  break;
4389  }
4390 
4391  sal_uInt8 cb(0);
4392  m_rStream.ReadUChar( cb );
4393  nByteCount++;
4394 
4395  aPAPXOffsets[stcp].mnSize = 0;
4396 
4397  if (cb != 0xFF)
4398  {
4399  sal_uInt8 stc2(0);
4400  m_rStream.ReadUChar( stc2 );
4401  m_rStream.SeekRel(6);
4402  nByteCount+=7;
4403  sal_uInt8 nRemainder = cb-7;
4404 
4405  aPAPXOffsets[stcp].mnOffset = m_rStream.Tell();
4406  aPAPXOffsets[stcp].mnSize = nRemainder;
4407 
4408  m_rStream.SeekRel(nRemainder);
4409  nByteCount += nRemainder;
4410  }
4411 
4412  ++stcp;
4413  }
4414 
4415  sal_uInt16 iMac(0);
4416  m_rStream.ReadUInt16( iMac );
4417 
4418  if (iMac > nStyles) iMac = nStyles;
4419 
4420  for (stcp = 0; stcp < iMac; ++stcp)
4421  {
4422  sal_uInt8 stcNext(0), stcBase(0);
4423  m_rStream.ReadUChar( stcNext );
4424  m_rStream.ReadUChar( stcBase );
4425 
4426  sal_uInt8 stc = static_cast< sal_uInt8 >((stcp - cstcStd) & 255);
4427 
4428  /*
4429  #i64557# style based on itself
4430  every chain must end eventually at the null style (style code 222)
4431  */
4432  if (stc == stcBase)
4433  stcBase = 222;
4434 
4435  SwWW8StyInf &rSI = mpIo->m_vColl[stc];
4436  rSI.m_nBase = stcBase;
4437 
4438  ww::sti eSti = ww::GetCanonicalStiFromStc(stc);
4439 
4440  if (eSti == ww::stiNil)
4441  continue;
4442 
4443  if (stcp >= aPAPXOffsets.size())
4444  continue;
4445 
4446  rSI.m_bValid = true;
4447 
4448  if (ww::StandardStiIsCharStyle(eSti) && !aPAPXOffsets[stcp].mnSize)
4449  mpIo->m_vColl[stc].m_bColl = false;
4450 
4451  bool bOldNoImp = PrepareStyle(rSI, eSti, stc, stcNext);
4452 
4453  ImportSprms(aPAPXOffsets[stcp].mnOffset, aPAPXOffsets[stcp].mnSize,
4454  true);
4455 
4456  if (!aConvertedChpx[stcp].empty())
4457  ImportSprms(aConvertedChpx[stcp].data(),
4458  static_cast< short >(aConvertedChpx[stcp].size()),
4459  false);
4460 
4461  PostStyle(rSI, bOldNoImp);
4462  }
4463 }
4464 
4466 {
4467  ScanStyles(); // Scan Based On
4468 
4469  for (sal_uInt16 i = 0; i < m_cstd; ++i) // import Styles
4470  if (mpIo->m_vColl[i].m_bValid)
4471  Import1Style( i );
4472 }
4473 
4475 {
4479 
4481  return;
4482 
4483  if (mpIo->m_xWwFib->GetFIBVersion() <= ww::eWW2)
4485  else
4487 
4488  for (sal_uInt16 i = 0; i < m_cstd; ++i)
4489  {
4490  // Follow chain
4491  SwWW8StyInf* pi = &mpIo->m_vColl[i];
4492  sal_uInt16 j = pi->m_nFollow;
4493  if( j < m_cstd )
4494  {
4495  SwWW8StyInf* pj = &mpIo->m_vColl[j];
4496  if ( j != i // rational Index ?
4497  && pi->m_pFormat // Format ok ?
4498  && pj->m_pFormat // Derived-Format ok ?
4499  && pi->m_bColl // only possible for paragraph templates (WW)
4500  && pj->m_bColl ){ // identical Type ?
4501  static_cast<SwTextFormatColl*>(pi->m_pFormat)->SetNextTextFormatColl(
4502  *static_cast<SwTextFormatColl*>(pj->m_pFormat) ); // ok, register
4503  }
4504  }
4505  }
4506 
4507  // Missing special handling for default character template
4508  // "Absatz-Standardschriftart" ( Style-ID 65 ).
4509  // That is empty by default ( WW6 dt and US ) and not changeable
4510  // via WW-UI so this does not matter.
4511  // This could be done by:
4512  // if( bNew ) rDoc.SetDefault( pDefCharFormat->GetAttrSet() );
4513 
4514  // for e.g. tables an always valid Std-Style is necessary
4515 
4516  if( mpIo->StyleExists(0) && !mpIo->m_vColl.empty() &&
4517  mpIo->m_vColl[0].m_pFormat && mpIo->m_vColl[0].m_bColl && mpIo->m_vColl[0].m_bValid )
4518  mpIo->m_pDfltTextFormatColl = static_cast<SwTextFormatColl*>(mpIo->m_vColl[0].m_pFormat);
4519  else
4521 
4522  // set Hyphenation flag on BASIC para-style
4524  {
4525  if (mpIo->m_xWDop->fAutoHyphen
4526  && SfxItemState::SET != mpIo->m_pStandardFormatColl->GetItemState(
4527  RES_PARATR_HYPHENZONE, false) )
4528  {
4530  aAttr.GetMinLead() = 2;
4531  aAttr.GetMinTrail() = 2;
4532  aAttr.GetMaxHyphens() = 0;
4533 
4535  }
4536 
4537  /*
4538  Word defaults to ltr not from environment like writer. Regardless of
4539  the page/sections rtl setting the standard style lack of rtl still
4540  means ltr
4541  */
4542  if (SfxItemState::SET != mpIo->m_pStandardFormatColl->GetItemState(RES_FRAMEDIR,
4543  false))
4544  {
4546  SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
4547  }
4548  }
4549 
4550  // we do not read styles anymore:
4551  mpIo->m_pCurrentColl = nullptr;
4552 }
4553 
4554 rtl_TextEncoding SwWW8StyInf::GetCharSet() const
4555 {
4556  if (m_pFormat && (m_pFormat->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4557  return m_eRTLFontSrcCharSet;
4558  return m_eLTRFontSrcCharSet;
4559 }
4560 
4561 rtl_TextEncoding SwWW8StyInf::GetCJKCharSet() const
4562 {
4563  if (m_pFormat && (m_pFormat->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4564  return m_eRTLFontSrcCharSet;
4565  return m_eCJKFontSrcCharSet;
4566 }
4567 
4568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetFamily(FontFamily)
bool HasFrame() const
Definition: ww8par.hxx:983
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:1034
SvStream & ReadInt16(sal_Int16 &rInt16)
sal_uInt8 & GetMaxHyphens()
short nLineHeight
Definition: ww8par.hxx:1018
sal_uInt8 fSysVanish
Definition: ww8struc.hxx:92
short nCenter[MAX_COL+1]
Definition: ww8par.hxx:1021
const sal_uInt16 sprmTJc90
Definition: sprmids.hxx:449
std::unique_ptr< SwWW8FltControlStack > m_xCtrlStck
Definition: ww8par.hxx:1098
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:905
sw::util::CharStyleMapper m_aCharStyleMapper
Definition: ww8par.hxx:1184
sal_uInt8 brcType() const
Definition: ww8struc.hxx:325
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:1230
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:4935
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:77
std::stack< std::unique_ptr< sw::util::RedlineStack > > m_aFrameRedlines
Definition: ww8par.hxx:1104
void ReadDef(bool bVer67, const sal_uInt8 *pS, short nLen)
Definition: ww8par2.cxx:1101
void SetTabBorders(SwTableBox *pBox, short nIdx)
Definition: ww8par2.cxx:3006
sal_uInt32 GetWWPageTopMargin() const
Definition: ww8par2.cxx:169
const OUString & GetText() const
Definition: ndtxt.hxx:210
void CalcDefaults()
Definition: ww8par2.cxx:2125
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:2569
const sal_uInt16 sprmTDelete
Definition: sprmids.hxx:232
short GetTextFirstLineOfst() const
signed char sal_Int8
const sal_uInt16 sprmTDefTable
Definition: sprmids.hxx:227
sal_uInt16 m_nProgress
Definition: ww8par.hxx:1287
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx:87
static bool SetBorder(SvxBoxItem &rBox, const WW8_BRCVer9 *pbrc, short *pSizeArray=nullptr, sal_uInt8 nSetBorders=0xFF)
Definition: ww8par6.cxx:1491
SwNodeIndex nNode
Definition: pam.hxx:37
static wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
Definition: ww8par2.cxx:1644
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:4135
SVX_NUM_NUMBER_NONE
rtl_TextEncoding m_eCJKFontSrcCharSet
Definition: ww8par.hxx:222
rtl_TextEncoding GetCharSet() const
Definition: ww8par2.cxx:4554
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:227
void SetNCurrentColl(sal_uInt16 nColl)
Definition: ww8par.hxx:1892
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:1552
#define RES_FRMATR_END
Definition: hintids.hxx:238
bool const m_bNewDoc
Definition: ww8par.hxx:1305
const sal_uInt16 sprmTDyaRowHeight
Definition: sprmids.hxx:226
sal_uInt8 fNumRun
Definition: ww8struc.hxx:93
const sal_uInt16 sprmTDxaGapHalf
Definition: sprmids.hxx:221
sal_uInt16 mnSprmsLen
Definition: ww8par2.hxx:97
Definition: doc.hxx:185
#define MAX_COL
Definition: ww8par.hxx:1007
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1482
bool m_bWasTabCellEnd
Definition: ww8par.hxx:1317
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:1219
bool StyleExists(unsigned int nColl) const
Definition: ww8par.hxx:1384
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:965
sal_uInt64 Seek(sal_uInt64 nPos)
WW8LvlType GetNumType(sal_uInt8 nWwLevelNo)
Definition: ww8par2.cxx:874
#define RES_CHRATR_FONT
Definition: hintids.hxx:76
void SetTabShades(SwTableBox *pBox, short nWwIdx)
Definition: ww8par2.cxx:3061
SVBT16 ftc
Definition: ww8struc.hxx:636
SwTableLine is one table row in the document model.
Definition: swtable.hxx:344
sal_uInt8 mnWW8OutlineLevel
Definition: ww8par.hxx:238
std::unique_ptr< WW8TabDesc > m_xTableDesc
Definition: ww8par.hxx:1244
SwNode & GetNode() const
Definition: ndindex.hxx:119
WW8LvlType
Definition: ww8par2.hxx:292
const OUString & GetName() const
Definition: numrule.hxx:221
sal_uInt32 m_nIniFlags
Definition: ww8par.hxx:1268
const sal_uInt16 sprmTCellPaddingDefault
Definition: sprmids.hxx:494
SvxFrameDirection
sal_uInt16 fVanish
Definition: ww8struc.hxx:68
rtl_TextEncoding GetCJKCharSet() const
Definition: ww8par2.cxx:4561
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:91
sal_Int32 m_nIniFlyDy
Definition: ww8par.hxx:1282
WW8FlyPara * mpStyleApo
Definition: ww8par.hxx:978
sal_uInt16 m_n81BiDiFlags
Definition: ww8par.hxx:241
void ProcessSprmTDelete(const sal_uInt8 *pParamsTDelete)
Definition: ww8par2.cxx:1528
void MoveInsideFly(const SwFrameFormat *pFlyFormat)
Definition: ww8par6.cxx:2273
#define RES_CHRATR_CJK_FONTSIZE
Definition: hintids.hxx:92
sal_uInt8 rgch[64]
Definition: ww8struc.hxx:661
short mnDefaultBottom
Definition: ww8par.hxx:1016
void SetIncludeUpperLevels(sal_uInt8 nSet)
sal_uInt16 fsSpace
Definition: ww8struc.hxx:82
void SetTabDirection(SwTableBox *pBox, short nWwIdx)
Definition: ww8par2.cxx:3114
SVBT16 dxaIndent
Definition: ww8struc.hxx:639
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:3785
void TabCellEnd()
Definition: ww8par2.cxx:3495
sal_uInt8 cbTextAfter
Definition: ww8struc.hxx:615
void PopTableDesc()
Definition: ww8par2.cxx:3516
void setRowSpan(long nNewRowSpan)
Definition: swtable.cxx:107
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:201
WW8_SHD * pSHDs
Definition: ww8par.hxx:1032
bool StartTable(WW8_CP nStartCp)
Definition: ww8par2.cxx:3375
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:1036
void ReadShd(const sal_uInt8 *pS)
Definition: ww8par2.cxx:1574
sal_uInt16 fItalicBi
Definition: ww8struc.hxx:74
const sal_uInt16 sprmTTableBorders
Definition: sprmids.hxx:467
void ImportOldFormatStyles()
Definition: ww8par2.cxx:4258
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:1553
rtl_TextEncoding m_eRTLFontSrcCharSet
Definition: ww8par.hxx:221
bool m_bHasSprm37
Definition: ww8par.hxx:975
SvxNumType
SVBT16 dxaSpace
Definition: ww8struc.hxx:640
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:1105
bool IsSevenMinus(WordVersion eVer)
Definition: types.hxx:32
const SwTableLines * m_pTabLines
Definition: ww8par2.hxx:209
sal_uInt8 fNumberAcross
Definition: ww8struc.hxx:648
sal_uInt8 & GetMinLead()
sal_uInt16 fsHps
Definition: ww8struc.hxx:79
constexpr::Color COL_AUTO(0xFF, 0xFF, 0xFF, 0xFF)
const SwTable * m_pTable
Definition: ww8par2.hxx:263
short m_nMaxRight
Definition: ww8par2.hxx:223
short GetCurrentCol() const
Definition: ww8par2.hxx:284
WW8TabDesc(WW8TabDesc const &)=delete
bool m_bParaAutoAfter
Definition: ww8par.hxx:255
void SetLeft(const long nL, const sal_uInt16 nProp=100)
SwFlyFrameFormat * MakeFlySection(RndStdIds eAnchorType, const SwPosition *pAnchorPos, const SfxItemSet *pSet=nullptr, SwFrameFormat *pParent=nullptr, bool bCalledFromShell=false)
Definition: doclay.cxx:284
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:2888
std::vector< sal_uInt8 > ChpxToSprms(const Word2CHPX &rChpx)
Definition: ww8par2.cxx:4023
sal_uInt16 hpsBi
Definition: ww8struc.hxx:100
NONE
StyleResult GetStyle(const OUString &rName, ww::sti eSti)
Get the writer style which the word style should map to.
SwNodeType GetNodeType() const
Definition: node.hxx:144
SvStream * mpStStrm
Definition: ww8par2.hxx:92
#define RES_CHRATR_CTL_FONTSIZE
Definition: hintids.hxx:97
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:1235
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter .
Definition: docfmt.cxx:1064
short m_nBands
Definition: ww8par2.hxx:220
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:425
SwFormat * m_pStandardFormatColl
Definition: ww8par.hxx:1237
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:226
bool mbHasSpacing
Definition: ww8par.hxx:1017
bool m_bImportSkipped
Definition: ww8par.hxx:246
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
SwTableBoxes * m_pTabBoxes
Definition: ww8par2.hxx:211
const SwTextFormatColl * m_pDfltTextFormatColl
Definition: ww8par.hxx:1236
SVX_NUM_ARABIC
const sal_uInt16 sprmTTableBorders
Definition: sprmids.hxx:224
const sal_uInt16 sprmTFBiDi
Definition: sprmids.hxx:459
const sal_uInt8 MAXLEVEL
Definition: swtypes.hxx:95
sw::util::ParaStyleMapper m_aParaStyleMapper
Definition: ww8par.hxx:1183
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:1226
std::pair< SwTextFormatColl *, bool > StyleResult
StyleResult StyleResult is a std::pair of a pointer to a style and a flag which is true if the style ...
Definition: msfilter.hxx:158
const SwTable & GetTable() const
Definition: node.hxx:497
sal_uInt8 chs
Definition: ww8struc.hxx:213
bool IsWW8BuiltInHeadingStyle() const
Definition: ww8par.hxx:327
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
SVX_NUM_ROMAN_LOWER
const sal_uInt16 sprmTTableWidth
Definition: sprmids.hxx:468
void Import()
Definition: ww8par2.cxx:4474
virtual WW8_CP Where() override
Definition: ww8scan.cxx:3372
SVX_NUM_IROHA_FULLWIDTH_JA
sal_uInt8 rgchAnld[32]
Definition: ww8struc.hxx:651
SvStream & m_rStream
Definition: ww8scan.hxx:1542
void MoveOutsideTable()
Definition: ww8par2.cxx:2740
sal_uInt32 fcPic
Definition: ww8struc.hxx:102
void SetCountedInList(bool bCounted)
Definition: ndtxt.cxx:4225
void ReadNewShd(const sal_uInt8 *pS, bool bVer67)
Definition: ww8par2.cxx:1595
This is what we use in the Parser (and Dumper)
Definition: ww8struc.hxx:221
std::unique_ptr< WW8_STD > Read1Style(sal_uInt16 &rSkip, OUString *pString)
Definition: ww8scan.cxx:6968
sal_uInt16 fSpec
Definition: ww8struc.hxx:70
const sal_uInt16 sprmTTableHeader
Definition: sprmids.hxx:223
void ProcessSpecificSpacing(const sal_uInt8 *pParamsTInsert)
Definition: ww8par2.cxx:1496
#define RES_PARATR_SNAPTOGRID
Definition: hintids.hxx:176
sal_uInt16 m_n81Flags
Definition: ww8par.hxx:240
sal_uInt64 remainingSize()
bool IsValidCell(short nCol) const
Definition: ww8par2.cxx:2866
void ImportGrupx(short nLen, bool bPara, bool bOdd)
Definition: ww8par2.cxx:3707
WW8_BRCVer9 rgbrc[4]
Definition: ww8struc.hxx:534
SwFrameFormat * m_pFormatOfJustInsertedApo
Definition: ww8par.hxx:1200
sal_uInt8 kul
Definition: ww8struc.hxx:95
const OUString & GetSuffix() const
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:1751
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:1029
friend struct WW8SwFlyPara
Definition: ww8par.hxx:1079
void SetWidth(long n)
bool m_bParaAutoAfter
Definition: ww8par.hxx:1354
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:3380
#define RES_BACKGROUND
Definition: hintids.hxx:212
void SetNumAdjust(SvxAdjust eSet)
bool mbStartApo
Definition: ww8par.hxx:973
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:3358
bool m_bIsBiDi
Definition: ww8par2.hxx:231
#define RES_CHRATR_COLOR
Definition: hintids.hxx:72
sal_uInt8 icoBi
Definition: ww8struc.hxx:97
sal_Int32 m_nIniFlyDx
Definition: ww8par.hxx:1281
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
#define RES_FLTR_NUMRULE
Definition: hintids.hxx:324
void PrependedInlineNode(const SwPosition &rPos, const SwNode &rNode)
Definition: ww8par2.cxx:2379
sal_uInt8 ico
Definition: ww8struc.hxx:94
SVBT16 iStartAt
Definition: ww8struc.hxx:638
SwNumRule * FindNumRulePtr(const OUString &rName) const
Definition: docnum.cxx:2414
sal_uInt16 fsIcoBi
Definition: ww8struc.hxx:84
bool CurrentSectionIsProtected() const
Definition: ww8par2.cxx:140
void AdjustNewBand()
Definition: ww8par2.cxx:3150
static SwNodePtr GetStartNode(SwOutlineNodes const *pOutlNds, int nOutlineLevel, SwOutlineNodes::size_type *nOutl)
Definition: docglbl.cxx:87
short ImportSprm(const sal_uInt8 *pPos, sal_Int32 nMemLen, sal_uInt16 nId=0)
Definition: ww8par6.cxx:6099
ApoTestResults TestApo(int nCellLevel, bool bTableRowEnd, const WW8_TablePos *pTabPos)
Definition: ww8par2.cxx:423
void ImportNewFormatStyles()
Definition: ww8par2.cxx:4465
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
bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
SVX_NUM_NUMBER_UPPER_KO
void UpdateTableMergeGroup(WW8_TCell const &rCell, WW8SelBoxInfo *pActGroup, SwTableBox *pActBox, sal_uInt16 nCol)
Definition: ww8par2.cxx:3309
void SetFamilyName(const OUString &rFamilyName)
sal_uInt16 GetValue() const
Definition: ww8struc.hxx:589
static bool IsBorder(const WW8_BRCVer9 *pbrc, bool bChkBtwn=false)
Definition: ww8par6.cxx:1486
sal_uInt16 m_nCurrentColl
Definition: ww8par.hxx:1288
WW8_ANLV eAnlv
Definition: ww8struc.hxx:646
wwSectionManager m_aSectionManager
Definition: ww8par.hxx:1150
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
#define RES_CHRATR_CTL_FONT
Definition: hintids.hxx:96
WW8_FFN_BASE aFFNBase
Definition: ww8struc.hxx:231
SvxAdjust
short m_nCharFormat
Definition: ww8par.hxx:1292
SwDoc & m_rDoc
Definition: ww8par.hxx:1094
void SetNumRuleName(const OUString &rName)
Definition: ww8par2.cxx:3367
void SetBulletFont(const vcl::Font *pFont)
sal_uInt8 * mpParaSprms
Definition: ww8par2.hxx:96