LibreOffice Module sw (master)  1
ww8par6.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 <stdlib.h>
21 #include <o3tl/safeint.hxx>
22 #include <o3tl/unit_conversion.hxx>
23 #include <svl/itemiter.hxx>
24 #include <svl/grabbagitem.hxx>
25 #include <rtl/tencinfo.h>
26 #include <sal/log.hxx>
27 
28 #include <hintids.hxx>
29 #include <editeng/lspcitem.hxx>
30 #include <editeng/wrlmitem.hxx>
31 #include <editeng/udlnitem.hxx>
32 #include <editeng/kernitem.hxx>
33 #include <editeng/langitem.hxx>
34 #include <editeng/cmapitem.hxx>
35 #include <editeng/shdditem.hxx>
36 #include <editeng/contouritem.hxx>
38 #include <editeng/postitem.hxx>
39 #include <editeng/wghtitem.hxx>
40 #include <editeng/colritem.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/spltitem.hxx>
43 #include <editeng/keepitem.hxx>
44 #include <editeng/orphitem.hxx>
45 #include <editeng/widwitem.hxx>
46 #include <editeng/adjustitem.hxx>
48 #include <editeng/fhgtitem.hxx>
49 #include <editeng/fontitem.hxx>
50 #include <editeng/shaditem.hxx>
51 #include <editeng/boxitem.hxx>
52 #include <editeng/ulspitem.hxx>
53 #include <editeng/lrspitem.hxx>
54 #include <editeng/tstpitem.hxx>
55 #include <editeng/autokernitem.hxx>
56 #include <editeng/paperinf.hxx>
58 #include <editeng/twolinesitem.hxx>
62 #include <editeng/blinkitem.hxx>
65 #include <editeng/pgrditem.hxx>
66 #include <editeng/frmdiritem.hxx>
68 #include <i18nlangtag/mslangid.hxx>
69 #include <svx/xfillit0.hxx>
70 #include <svx/xflclit.hxx>
71 #include "sortedarray.hxx"
72 #include "sprmids.hxx"
73 #include <node.hxx>
74 #include <ndtxt.hxx>
75 #include <pam.hxx>
76 #include <doc.hxx>
78 #include <pagedesc.hxx>
79 #include <fmtanchr.hxx>
80 #include <fmtcntnt.hxx>
81 #include <fchrfmt.hxx>
82 #include <fmthdft.hxx>
83 #include <fmtclds.hxx>
84 #include <fmtftntx.hxx>
85 #include <frmatr.hxx>
86 #include <section.hxx>
87 #include <lineinfo.hxx>
88 #include <fmtline.hxx>
89 #include <txatbase.hxx>
90 #include <fmtflcnt.hxx>
91 #include <tgrditem.hxx>
92 #include <hfspacingitem.hxx>
93 #include <swtable.hxx>
94 #include <fltini.hxx>
95 #include "writerhelper.hxx"
96 #include "writerwordglue.hxx"
97 #include "ww8scan.hxx"
98 #include "ww8par2.hxx"
99 #include "ww8graf.hxx"
100 
102 
103 using namespace sw::util;
104 using namespace sw::types;
105 using namespace ::com::sun::star;
106 using namespace nsHdFtFlags;
107 
108 // various
109 
110 // WW default for horizontal borders: 2.5 cm
112 // WW default for lower border: 2.0 cm
114 
115 
116 static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
117  const WW8RStyle* pSty = nullptr, const WW8PLCFx_SEPX* pSep = nullptr);
118 
120 {
121  static const Color eSwWW8ColA[] =
122  {
127  };
128  SAL_WARN_IF(
129  nIco >= SAL_N_ELEMENTS(eSwWW8ColA), "sw.ww8",
130  "ico " << sal_uInt32(nIco) << " >= " << SAL_N_ELEMENTS(eSwWW8ColA));
131  return nIco < SAL_N_ELEMENTS(eSwWW8ColA) ? eSwWW8ColA[nIco] : COL_AUTO;
132 }
133 
134 static sal_uInt32 MSRoundTweak(sal_uInt32 x)
135 {
136  return x;
137 }
138 
139 // page attribute which are not handled via the attribute management but
140 // using ...->HasSprm
141 // (except OLST which stays a normal attribute)
142 static short ReadSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
143 {
144  SprmResult aRes = pSep->HasSprm(nId); // sprm here?
145  const sal_uInt8* pS = aRes.pSprm;
146  short nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToInt16(pS) : nDefaultVal;
147  return nVal;
148 }
149 
150 static sal_uInt16 ReadUSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
151 {
152  SprmResult aRes = pSep->HasSprm(nId); // sprm here?
153  const sal_uInt8* pS = aRes.pSprm;
154  sal_uInt16 nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToUInt16(pS) : nDefaultVal;
155  return nVal;
156 }
157 
158 static sal_uInt8 ReadBSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, sal_uInt8 nDefaultVal )
159 {
160  SprmResult aRes = pSep->HasSprm(nId); // sprm here?
161  const sal_uInt8* pS = aRes.pSprm;
162  sal_uInt8 nVal = (pS && aRes.nRemainingData >= 1) ? *pS : nDefaultVal;
163  return nVal;
164 }
165 
167 {
168  //sprmSTextFlow
169  switch (maSep.wTextFlow)
170  {
171  default:
172  OSL_ENSURE(false, "Unknown layout type");
173  [[fallthrough]];
174  case 0:
175  meDir=SvxFrameDirection::Horizontal_LR_TB;
176  break;
177  case 1:
178  meDir=SvxFrameDirection::Vertical_RL_TB;
179  break;
180  case 2:
181  //asian letters are not rotated, western are. We can't import
182  //bottom to top going left to right, we can't do this in
183  //pages, (in drawboxes we could partly hack it with a rotated
184  //drawing box, though not frame)
185  meDir=SvxFrameDirection::Vertical_RL_TB;
186  break;
187  case 3:
188  //asian letters are not rotated, western are. We can't import
189  meDir=SvxFrameDirection::Vertical_RL_TB;
190  break;
191  case 4:
192  //asian letters are rotated, western not. We can't import
193  meDir=SvxFrameDirection::Horizontal_LR_TB;
194  break;
195  }
196 
197  sal_uInt8 bRTLPgn = maSep.fBiDi;
198  if ((meDir == SvxFrameDirection::Horizontal_LR_TB) && bRTLPgn)
199  meDir = SvxFrameDirection::Horizontal_RL_TB;
200 }
201 
203 {
204  return meDir == SvxFrameDirection::Vertical_RL_TB || meDir == SvxFrameDirection::Vertical_LR_TB;
205 }
206 
207 /*
208  This is something of festering mapping, I'm open to better ways of doing it,
209  but primarily the grid in writer is different to that in word. In writer the
210  grid elements are squares with ruby rows inbetween. While in word there is no
211  ruby stuff, and the elements are rectangles. By misusing the ruby row I can
212  handle distortions in one direction, but its all a bit of a mess:
213 */
215 {
216  if (m_bVer67)
217  return;
218 
220 
221  SwTwips nTextareaHeight = rFormat.GetFrameSize().GetHeight();
222  const SvxULSpaceItem &rUL = ItemGet<SvxULSpaceItem>(rFormat, RES_UL_SPACE);
223  nTextareaHeight -= rUL.GetUpper();
224  nTextareaHeight -= rUL.GetLower();
225 
226  SwTwips nTextareaWidth = rFormat.GetFrameSize().GetWidth();
227  const SvxLRSpaceItem &rLR = ItemGet<SvxLRSpaceItem>(rFormat, RES_LR_SPACE);
228  nTextareaWidth -= rLR.GetLeft();
229  nTextareaWidth -= rLR.GetRight();
230 
231  if (rSection.IsVertical())
232  std::swap(nTextareaHeight, nTextareaWidth);
233 
234  SwTextGridItem aGrid;
235  aGrid.SetDisplayGrid(false);
236  aGrid.SetPrintGrid(false);
238 
239  switch (rSection.maSep.clm)
240  {
241  case 0:
242  eType = GRID_NONE;
243  break;
244  default:
245  OSL_ENSURE(false, "Unknown grid type");
246  [[fallthrough]];
247  case 3:
248  eType = GRID_LINES_CHARS;
249  aGrid.SetSnapToChars(true);
250  break;
251  case 1:
252  eType = GRID_LINES_CHARS;
253  aGrid.SetSnapToChars(false);
254  break;
255  case 2:
256  eType = GRID_LINES_ONLY;
257  break;
258  }
259 
260  aGrid.SetGridType(eType);
261 
262  // seem to not add external leading in word, or the character would run across
263  // two line in some cases.
264  if (eType != GRID_NONE)
266 
267  //force to set document as standard page mode
268  bool bSquaredMode = false;
269  m_rDoc.SetDefaultPageMode( bSquaredMode );
270  aGrid.SetSquaredMode( bSquaredMode );
271 
272  //Get the size of word's default styles font
273  sal_uInt32 nCharWidth=240;
274  for (sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); ++nI)
275  {
276  if (m_vColl[nI].m_bValid && m_vColl[nI].m_pFormat &&
277  m_vColl[nI].IsWW8BuiltInDefaultStyle())
278  {
279  nCharWidth = ItemGet<SvxFontHeightItem>(*(m_vColl[nI].m_pFormat),
280  RES_CHRATR_CJK_FONTSIZE).GetHeight();
281  break;
282  }
283  }
284 
285  //dxtCharSpace
286  if (rSection.maSep.dxtCharSpace)
287  {
288  sal_uInt32 nCharSpace = rSection.maSep.dxtCharSpace;
289  //main lives in top 20 bits, and is signed.
290  sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
291  nMain/=0x1000;
292  nCharWidth += nMain*20;
293 
294  int nFraction = (nCharSpace & 0x00000FFF);
295  nFraction = (nFraction*20)/0xFFF;
296  nCharWidth += nFraction;
297  }
298 
299  aGrid.SetBaseWidth( writer_cast<sal_uInt16>(nCharWidth));
300 
301  //sep.dyaLinePitch
302  sal_Int32 nLinePitch = rSection.maSep.dyaLinePitch;
303  if (nLinePitch >= 1 && nLinePitch <= 31680)
304  {
305  aGrid.SetLines(writer_cast<sal_uInt16>(nTextareaHeight/nLinePitch));
306  aGrid.SetBaseHeight(writer_cast<sal_uInt16>(nLinePitch));
307  }
308 
309  aGrid.SetRubyHeight(0);
310 
311  rFormat.SetFormatAttr(aGrid);
312 }
313 
315 {
316  if ( m_pCurrentColl && StyleExists(m_nCurrentColl) ) // importing style
317  m_vColl[m_nCurrentColl].m_nRelativeJustify = bRel ? 1 : 0;
318  else if ( m_xPlcxMan && m_xPlcxMan->GetPap() ) // importing paragraph
319  m_xPlcxMan->GetPap()->nRelativeJustify = bRel ? 1 : 0;
320 }
321 
323 {
324  bool bRet = m_xWwFib->GetFIBVersion() >= ww::eWW8;
325  if ( bRet )
326  {
327  // if relativeJustify is undefined (-1), then check the parent style.
328  if ( m_pCurrentColl && StyleExists(m_nCurrentColl) )
329  {
330  sal_Int16 nRelative = m_vColl[m_nCurrentColl].m_nRelativeJustify;
331  if ( nRelative < 0 && m_nCurrentColl )
332  {
333  o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
334  bRet = IsRelativeJustify(m_vColl[m_nCurrentColl].m_nBase, aVisitedStyles);
335  }
336  else
337  bRet = nRelative > 0;
338  }
339  else if ( m_xPlcxMan && m_xPlcxMan->GetPap() )
340  {
341  sal_Int16 nRelative = m_xPlcxMan->GetPap()->nRelativeJustify;
342  if ( nRelative < 0 )
343  {
344  o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
345  bRet = IsRelativeJustify(m_nCurrentColl, aVisitedStyles);
346  }
347  else
348  bRet = nRelative > 0;
349  }
350  }
351 
352  return bRet;
353 }
354 
356 {
357  assert( m_xWwFib->GetFIBVersion() >= ww::eWW8
358  && "pointless to search styles if relative justify is impossible");
359  bool bRet = true;
360  if ( StyleExists(nColl) )
361  {
362  rVisitedStyles.insert(nColl);
363  // if relativeJustify is undefined (-1), then check the parent style.
364  sal_Int16 nRelative = m_vColl[nColl].m_nRelativeJustify;
365  if ( nColl == 0 || nRelative >= 0 )
366  bRet = nRelative > 0;
367  else if (rVisitedStyles.find(m_vColl[nColl].m_nBase) == rVisitedStyles.end()) // detect loop in chain
368  bRet = IsRelativeJustify(m_vColl[nColl].m_nBase, rVisitedStyles);
369  }
370 
371  return bRet;
372 }
373 
374 void SwWW8ImplReader::Read_ParaBiDi(sal_uInt16, const sal_uInt8* pData, short nLen)
375 {
376  if (nLen < 1)
377  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FRAMEDIR);
378  else
379  {
380  SvxFrameDirection eDir =
381  *pData ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB;
382 
383  // In eWW8+, justify can be absolute, or relative to BiDi
384  bool bBiDiSwap = IsRelativeJustify();
385  if ( bBiDiSwap )
386  {
387  // Only change if ParaBiDi doesn't match previous setting.
388  const bool bParentRTL = IsRightToLeft();
389  bBiDiSwap = (eDir == SvxFrameDirection::Horizontal_RL_TB && !bParentRTL)
390  || (eDir == SvxFrameDirection::Horizontal_LR_TB && bParentRTL);
391  }
392 
393  if ( bBiDiSwap )
394  {
395  const SvxAdjustItem* pItem = static_cast<const SvxAdjustItem*>(GetFormatAttr(RES_PARATR_ADJUST));
396  if ( !pItem )
397  {
398  // no previous adjust: set appropriate default
399  if ( eDir == SvxFrameDirection::Horizontal_LR_TB )
400  NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
401  else
402  NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
403  }
404  else
405  {
406  // previous adjust and bidi has changed: swap Left/Right
407  const SvxAdjust eJustify = pItem->GetAdjust();
408  if ( eJustify == SvxAdjust::Left )
409  NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
410  else if ( eJustify == SvxAdjust::Right )
411  NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
412  }
413  }
414 
415  NewAttr(SvxFrameDirectionItem(eDir, RES_FRAMEDIR));
416 
417  if ( m_pCurrentColl && m_xStyles ) // in style definition
418  m_xStyles->mbBidiChanged = true;
419  }
420 }
421 
422 bool wwSectionManager::SetCols(SwFrameFormat &rFormat, const wwSection &rSection,
423  sal_uInt32 nNetWidth)
424 {
425  //sprmSCcolumns - number of columns - 1
426  const sal_Int16 nCols = rSection.NoCols();
427 
428  if (nCols < 2) //check for no columns or other weird state
429  return false;
430 
431  const sal_uInt16 nNetWriterWidth = writer_cast<sal_uInt16>(nNetWidth);
432  if (nNetWriterWidth == 0)
433  return false;
434 
435  SwFormatCol aCol; // Create SwFormatCol
436 
437  //sprmSDxaColumns - Default distance is 1.25 cm
438  sal_Int32 nColSpace = rSection.StandardColSeparation();
439 
440  const SEPr& rSep = rSection.maSep;
441 
442  // sprmSLBetween
443  if (rSep.fLBetween)
444  {
445  aCol.SetLineAdj(COLADJ_TOP); // Line
446  aCol.SetLineHeight(100);
447  aCol.SetLineColor(COL_BLACK);
448  aCol.SetLineWidth(1);
449  }
450 
451  aCol.Init(nCols, writer_cast<sal_uInt16>(nColSpace), nNetWriterWidth);
452 
453  // sprmSFEvenlySpaced
454  if (!rSep.fEvenlySpaced)
455  {
456  aCol.SetOrtho_(false);
457  const sal_uInt16 maxIdx = SAL_N_ELEMENTS(rSep.rgdxaColumnWidthSpacing);
458  for (sal_uInt16 i = 0, nIdx = 1; i < nCols && nIdx < maxIdx; i++, nIdx+=2 )
459  {
460  SwColumn* pCol = &aCol.GetColumns()[i];
461  const sal_Int32 nLeft = rSep.rgdxaColumnWidthSpacing[nIdx-1]/2;
462  const sal_Int32 nRight = rSep.rgdxaColumnWidthSpacing[nIdx+1]/2;
463  const sal_Int32 nWishWidth = rSep.rgdxaColumnWidthSpacing[nIdx]
464  + nLeft + nRight;
465  pCol->SetWishWidth(writer_cast<sal_uInt16>(nWishWidth));
466  pCol->SetLeft(writer_cast<sal_uInt16>(nLeft));
467  pCol->SetRight(writer_cast<sal_uInt16>(nRight));
468  }
469  aCol.SetWishWidth(nNetWriterWidth);
470  }
471  rFormat.SetFormatAttr(aCol);
472  return true;
473 }
474 
476 {
477  // 3. LR-Margin
478  sal_uInt32 nWWLe = MSRoundTweak(rSection.maSep.dxaLeft);
479  sal_uInt32 nWWRi = MSRoundTweak(rSection.maSep.dxaRight);
480  sal_uInt32 nWWGu = rSection.maSep.dzaGutter;
481 
482  /*
483  fRTLGutter is set if the gutter is on the right, the gutter is otherwise
484  placed on the left unless the global dop options are to put it on top, that
485  case is handled in GetPageULData.
486  */
487  if (rSection.maSep.fRTLGutter)
488  {
489  rSection.m_bRtlGutter = true;
490  }
491 
492  // Left / Right
493  if ((rSection.nPgWidth - nWWLe - nWWRi) < MINLAY)
494  {
495  /*
496  There are some label templates which are "broken", they specify
497  margins which make no sense e.g. Left 16.10cm, Right 16.10cm. So the
498  space left between the margins is less than 0 In word the left margin
499  is honoured and if the right margin would be past the left margin is
500  left at the left margin position.
501 
502  Now this will work fine for importing, layout and exporting, *but* the
503  page layout dialog has a hardcoded minimum page width of 0.5cm so it
504  will report a different value than what is actually being used. i.e.
505  it will add up the values to give a wider page than is actually being
506  used.
507  */
508  nWWRi = rSection.nPgWidth - nWWLe - MINLAY;
509  }
510 
511  rSection.nPgLeft = nWWLe;
512  rSection.nPgRight = nWWRi;
513  rSection.nPgGutter = nWWGu;
514 }
515 
517  const wwSection &rSection, bool bIgnoreCols)
518 {
519  // 1. orientation
520  rInPageDesc.SetLandscape(rSection.IsLandScape());
521 
522  // 2. paper size
523  SwFormatFrameSize aSz( rFormat.GetFrameSize() );
524  aSz.SetWidth(rSection.GetPageWidth());
525  aSz.SetHeight(SvxPaperInfo::GetSloppyPaperDimension(rSection.GetPageHeight()));
526  rFormat.SetFormatAttr(aSz);
527 
528  SvxLRSpaceItem aLR(rSection.GetPageLeft(), rSection.GetPageRight(), 0, 0, RES_LR_SPACE);
529  aLR.SetGutterMargin(rSection.nPgGutter);
530  rFormat.SetFormatAttr(aLR);
531 
532  SfxBoolItem aRtlGutter(RES_RTL_GUTTER, rSection.m_bRtlGutter);
533  rFormat.SetFormatAttr(aRtlGutter);
534 
535  if (!bIgnoreCols)
536  SetCols(rFormat, rSection, rSection.GetTextAreaWidth());
537 }
538 
539 namespace {
540 // Returns corrected (ODF) margin size
541 tools::Long SetBorderDistance(bool bFromEdge, SvxBoxItem& aBox, SvxBoxItemLine eLine, tools::Long nMSMargin)
542 {
543  const editeng::SvxBorderLine* pLine = aBox.GetLine(eLine);
544  if (!pLine)
545  return nMSMargin;
546  sal_Int32 nNewMargin = nMSMargin;
547  sal_Int32 nNewDist = aBox.GetDistance(eLine);
548  sal_Int32 nLineWidth = pLine->GetScaledWidth();
549 
550  editeng::BorderDistanceFromWord(bFromEdge, nNewMargin, nNewDist, nLineWidth);
551  aBox.SetDistance(nNewDist, eLine);
552 
553  return nNewMargin;
554 }
555 }
556 
558 {
559  if (!IsBorder(rSection.brc))
560  return;
561 
562  SfxItemSet aSet(rFormat.GetAttrSet());
563  short aSizeArray[5]={0};
564  SetFlyBordersShadow(aSet, rSection.brc, &aSizeArray[0]);
565  SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE));
566  SvxULSpaceItem aUL(ItemGet<SvxULSpaceItem>(aSet, RES_UL_SPACE));
567  SvxBoxItem aBox(ItemGet<SvxBoxItem>(aSet, RES_BOX));
568  bool bFromEdge = rSection.maSep.pgbOffsetFrom == 1;
569 
570  aLR.SetLeft(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::LEFT, aLR.GetLeft()));
571  aLR.SetRight(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::RIGHT, aLR.GetRight()));
572  aUL.SetUpper(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::TOP, aUL.GetUpper()));
573  aUL.SetLower(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::BOTTOM, aUL.GetLower()));
574 
575  aSet.Put(aBox);
576  aSet.Put(aLR);
577  aSet.Put(aUL);
578  rFormat.SetFormatAttr(aSet);
579 }
580 
582  wwSectionManager::wwULSpaceData& rData) const
583 {
584  sal_Int32 nWWUp = rSection.maSep.dyaTop;
585  sal_Int32 nWWLo = rSection.maSep.dyaBottom;
586  sal_uInt32 nWWHTop = rSection.maSep.dyaHdrTop;
587  sal_uInt32 nWWFBot = rSection.maSep.dyaHdrBottom;
588 
589  /*
590  If there is gutter in 97+ and the dop says put it on top then get the
591  gutter distance and set it to the top margin. When we are "two pages
592  in one" the gutter is put at the top of odd pages, and bottom of
593  even pages, something we cannot do. So we will put it on top of all
594  pages, that way the pages are at least the right size.
595  */
596  if (!mrReader.m_bVer67 && mrReader.m_xWDop->iGutterPos &&
597  rSection.maSep.fRTLGutter)
598  {
599  nWWUp += rSection.maSep.dzaGutter;
600  }
601 
602  /* Check whether this section has headers / footers */
603  sal_uInt16 nHeaderMask = WW8_HEADER_EVEN | WW8_HEADER_ODD;
604  sal_uInt16 nFooterMask = WW8_FOOTER_EVEN | WW8_FOOTER_ODD;
605  /* Ignore the presence of a first-page header/footer unless it is enabled */
606  if( rSection.HasTitlePage() )
607  {
608  nHeaderMask |= WW8_HEADER_FIRST;
609  nFooterMask |= WW8_FOOTER_FIRST;
610  }
611  rData.bHasHeader = (rSection.maSep.grpfIhdt & nHeaderMask) != 0;
612  rData.bHasFooter = (rSection.maSep.grpfIhdt & nFooterMask) != 0;
613 
614  if( rData.bHasHeader )
615  {
616  rData.nSwUp = nWWHTop; // Header -> convert
617  // #i19922# - correction:
618  // consider that <nWWUp> can be negative, compare only if it's positive
619  if ( nWWUp > 0 &&
620  o3tl::make_unsigned(nWWUp) >= nWWHTop )
621  rData.nSwHLo = nWWUp - nWWHTop;
622  else
623  rData.nSwHLo = 0;
624 
625  // #i19922# - minimum page header height is now 1mm
626  // use new constant <cMinHdFtHeight>
627  if (rData.nSwHLo < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
628  rData.nSwHLo = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
629  }
630  else // no header -> just use Up as-is
631  rData.nSwUp = std::abs(nWWUp);
632 
633  if( rData.bHasFooter )
634  {
635  rData.nSwLo = nWWFBot; // footer -> convert
636  // #i19922# - correction: consider that <nWWLo> can be negative, compare only if it's positive
637  if ( nWWLo > 0 &&
638  o3tl::make_unsigned(nWWLo) >= nWWFBot )
639  rData.nSwFUp = nWWLo - nWWFBot;
640  else
641  rData.nSwFUp = 0;
642 
643  // #i19922# - minimum page header height is now 1mm
644  // use new constant <cMinHdFtHeight>
645  if (rData.nSwFUp < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
646  rData.nSwFUp = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
647  }
648  else // no footer -> just use Lo as-is
649  rData.nSwLo = std::abs(nWWLo);
650 }
651 
653  wwSectionManager::wwULSpaceData const & rData, const wwSection &rSection)
654 {
655  if (rData.bHasHeader) // ... and set Header-Lower
656  {
657  // set header height to minimum
658  if (SwFrameFormat* pHdFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat()))
659  {
660  SvxULSpaceItem aHdUL(pHdFormat->GetULSpace());
661  if (!rSection.IsFixedHeightHeader()) //normal
662  {
663  pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwHLo));
664  // #i19922# - minimum page header height is now 1mm
665  // use new constant <cMinHdFtHeight>
666  aHdUL.SetLower( writer_cast<sal_uInt16>(rData.nSwHLo - cMinHdFtHeight) );
667  pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
669  }
670  else
671  {
672  // Hack alert: these calculations are based on
673  // #112727# import negative height headers/footers as floating frames inside fixed height headers/footer
674  // #i48832# - set correct spacing between header and body.
675  const sal_Int32 nHdLowerSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaTop) - rData.nSwUp - rData.nSwHLo));
676  pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwHLo + nHdLowerSpace));
677  aHdUL.SetLower( static_cast< sal_uInt16 >(nHdLowerSpace) );
678  pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
680  }
681  pHdFormat->SetFormatAttr(aHdUL);
682  }
683  }
684 
685  if (rData.bHasFooter) // ... and set footer-upper
686  {
687  if (SwFrameFormat* pFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat()))
688  {
689  SvxULSpaceItem aFtUL(pFtFormat->GetULSpace());
690  if (!rSection.IsFixedHeightFooter()) //normal
691  {
692  pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwFUp));
693  // #i19922# - minimum page header height is now 1mm
694  // use new constant <cMinHdFtHeight>
695  aFtUL.SetUpper( writer_cast<sal_uInt16>(rData.nSwFUp - cMinHdFtHeight) );
696  pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
698  }
699  else
700  {
701  // #i48832# - set correct spacing between footer and body.
702  const sal_Int32 nFtUpperSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaBottom) - rData.nSwLo - rData.nSwFUp));
703  pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwFUp + nFtUpperSpace));
704  aFtUL.SetUpper( static_cast< sal_uInt16 >(nFtUpperSpace) );
705  pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
707  }
708  pFtFormat->SetFormatAttr(aFtUL);
709  }
710  }
711 
712  SvxULSpaceItem aUL(writer_cast<sal_uInt16>(rData.nSwUp),
713  writer_cast<sal_uInt16>(rData.nSwLo), RES_UL_SPACE);
714  rFormat.SetFormatAttr(aUL);
715 }
716 
718  SwPaM const & rMyPaM, wwSection &rSection)
719 {
721  mrReader.m_rDoc.GetUniqueSectionName() );
722 
723  SfxItemSet aSet( mrReader.m_rDoc.GetAttrPool(), aFrameFormatSetRange );
724 
725  bool bRTLPgn = !maSegments.empty() && maSegments.back().IsBiDi();
727  bRTLPgn ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
728 
729  if (2 == mrReader.m_xWDop->fpc)
731  if (0 == mrReader.m_xWDop->epc)
733 
734  aSection.SetProtectFlag(SectionIsProtected(rSection));
735 
736  rSection.mpSection =
737  mrReader.m_rDoc.InsertSwSection( rMyPaM, aSection, nullptr, & aSet );
738  OSL_ENSURE(rSection.mpSection, "section not inserted!");
739  if (!rSection.mpSection)
740  return nullptr;
741 
742  SwPageDesc *pPage = nullptr;
743  auto aIter = std::find_if(maSegments.rbegin(), maSegments.rend(),
744  [](const wwSection& rSegment) { return rSegment.mpPage != nullptr; });
745  if (aIter != maSegments.rend())
746  pPage = aIter->mpPage;
747 
748  OSL_ENSURE(pPage, "no page outside this section!");
749 
750  if (!pPage)
751  pPage = &mrReader.m_rDoc.GetPageDesc(0);
752 
753  SwSectionFormat *pFormat = rSection.mpSection->GetFormat();
754  OSL_ENSURE(pFormat, "impossible");
755  if (!pFormat)
756  return nullptr;
757 
758  SwFrameFormat& rFormat = pPage->GetMaster();
759  const SvxLRSpaceItem& rLR = rFormat.GetLRSpace();
760  tools::Long nPageLeft = rLR.GetLeft();
761  tools::Long nPageRight = rLR.GetRight();
762  tools::Long nSectionLeft = rSection.GetPageLeft() - nPageLeft;
763  tools::Long nSectionRight = rSection.GetPageRight() - nPageRight;
764  if ((nSectionLeft != 0) || (nSectionRight != 0))
765  {
766  SvxLRSpaceItem aLR(nSectionLeft, nSectionRight, 0, 0, RES_LR_SPACE);
767  pFormat->SetFormatAttr(aLR);
768  }
769 
770  SetCols(*pFormat, rSection, rSection.GetTextAreaWidth());
771  return pFormat;
772 }
773 
775 {
776  // check if Line Numbering must be activated or reset
777  if (!(m_bNewDoc && rSection.maSep.nLnnMod))
778  return;
779 
780  // restart-numbering-mode: 0 per page, 1 per section, 2 never restart
781  bool bRestartLnNumPerSection = (1 == rSection.maSep.lnc);
782 
783  if (m_bNoLnNumYet)
784  {
786 
787  aInfo.SetPaintLineNumbers(true);
788 
789  aInfo.SetRestartEachPage(rSection.maSep.lnc == 0);
790 
791  // A value of 0 (auto) indicates that the application MUST automatically determine positioning.
792  if ( rSection.maSep.dxaLnn )
793  aInfo.SetPosFromLeft(writer_cast<sal_uInt16>(rSection.maSep.dxaLnn));
794 
795  //Paint only for every n line
796  aInfo.SetCountBy(rSection.maSep.nLnnMod);
797 
798  // to be defaulted features ( HARDCODED in MS Word 6,7,8,9 )
799  aInfo.SetCountBlankLines(true);
800  aInfo.SetCountInFlys(false);
801  aInfo.SetPos( LINENUMBER_POS_LEFT );
802  SvxNumberType aNumType; // this sets SVX_NUM_ARABIC per default
803  aInfo.SetNumType( aNumType );
804 
805  m_rDoc.SetLineNumberInfo( aInfo );
806  m_bNoLnNumYet = false;
807  }
808 
809  if ((0 < rSection.maSep.lnnMin) || bRestartLnNumPerSection)
810  {
811  SwFormatLineNumber aLN;
812  if (const SwFormatLineNumber* pLN
813  = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
814  {
815  aLN.SetCountLines( pLN->IsCount() );
816  }
817  aLN.SetStartValue(1 + rSection.maSep.lnnMin);
818  NewAttr(aLN);
819  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LINENUMBER);
820  }
821 }
822 
823 wwSection::wwSection(const SwPosition &rPos) : maStart(rPos.nNode)
824  , mpSection(nullptr)
825  , mpPage(nullptr)
827  , nPgWidth(SvxPaperInfo::GetPaperSize(PAPER_A4).Width())
828  , nPgLeft(MM_250)
829  , nPgRight(MM_250)
830  , nPgGutter(0)
831  , mnVerticalAdjustment(drawing::TextVerticalAdjust_TOP)
832  , mnBorders(0)
833  , mbHasFootnote(false)
834 {
835 }
836 
838  SwPageDesc &rPageDesc)
839 {
840  // save page number format
841  static const SvxNumType aNumTyp[5] =
842  {
845  };
846 
847  SvxNumberType aType;
848  aType.SetNumberingType( aNumTyp[rNewSection.maSep.nfcPgn] );
849  rPageDesc.SetNumType(aType);
850 }
851 
852 // CreateSep is called for every section change (even at the start of
853 // the document. CreateSep also creates the pagedesc(s) and
854 // fills it/them with attributes and KF texts.
855 // This has become necessary because the translation of the various
856 // page attributes is interconnected too much.
858 {
859  /*
860  #i1909# section/page breaks should not occur in tables or subpage
861  elements like frames. Word itself ignores them in this case. The bug is
862  more likely that this filter created such documents in the past!
863  */
865  return;
866 
867  WW8PLCFx_SEPX* pSep = mrReader.m_xPlcxMan->GetSepPLCF();
868  OSL_ENSURE(pSep, "impossible!");
869  if (!pSep)
870  return;
871 
873  {
874  bool insert = true;
876  if( pam.Move(fnMoveBackward, GoInNode))
877  if( SwTextNode* txtNode = pam.GetPoint()->nNode.GetNode().GetTextNode())
878  if( txtNode->Len() == 0 )
879  insert = false;
880  if( insert )
882  }
883 
885 
886  // M.M. Create a linked section if the WkbPLCF
887  // has an entry for one at this cp
888  WW8PLCFspecial* pWkb = mrReader.m_xPlcxMan->GetWkbPLCF();
889  if (pWkb && pWkb->SeekPosExact(nTextPos) &&
890  pWkb->Where() == nTextPos)
891  {
892  void* pData;
893  WW8_CP nTest;
894  bool bSuccess = pWkb->Get(nTest, pData);
895  if (!bSuccess)
896  return;
897  OUString sSectionName = mrReader.m_aLinkStringMap[SVBT16ToUInt16( static_cast<WW8_WKB*>(pData)->nLinkId) ];
898  sSectionName = mrReader.ConvertFFileName(sSectionName);
899  SwSectionData aSection(SectionType::FileLink, sSectionName);
900  aSection.SetLinkFileName( sSectionName );
901  aSection.SetProtectFlag(true);
902  // #i19922# - improvement: return value of method <Insert> not used.
903  mrReader.m_rDoc.InsertSwSection(*mrReader.m_pPaM, aSection, nullptr, nullptr, false);
904  }
905 
906  wwSection aLastSection(*mrReader.m_pPaM->GetPoint());
907  if (!maSegments.empty())
908  aLastSection = maSegments.back();
909 
910  //Here
911  sal_uInt16 nLIdx = ( ( static_cast<sal_uInt16>(mrReader.m_xWwFib->m_lid) & 0xff ) == 0x9 ) ? 1 : 0;
912 
913  //BEGIN read section values
914  wwSection aNewSection(*mrReader.m_pPaM->GetPoint());
915 
916  static const sal_uInt16 aVer2Ids0[] =
917  {
918  /*sprmSBkc*/ 117,
919  /*sprmSFTitlePage*/ 118,
920  /*sprmSNfcPgn*/ 122,
921  /*sprmSCcolumns*/ 119,
922  /*sprmSDxaColumns*/ 120,
923  /*sprmSLBetween*/ 133
924  };
925 
926  static const sal_uInt16 aVer67Ids0[] =
927  {
934  };
935 
936  static const sal_uInt16 aVer8Ids0[] =
937  {
944  };
945 
946  const sal_uInt16* pIds = eVer <= ww::eWW2 ? aVer2Ids0 : eVer <= ww::eWW7 ? aVer67Ids0 : aVer8Ids0;
947 
948  SprmResult aRes = pSep->HasSprm(pIds[0]);
949  const sal_uInt8* pSprmBkc = aRes.pSprm;
950  if (!maSegments.empty())
951  {
952  // Type of break: break codes are:
953  // 0 No break
954  // 1 New column
955  // 2 New page
956  // 3 Even page
957  // 4 Odd page
958  if (pSprmBkc && aRes.nRemainingData >= 1)
959  aNewSection.maSep.bkc = *pSprmBkc;
960  }
961 
962  // Has a table page
963  aNewSection.maSep.fTitlePage =
964  sal_uInt8(0 != ReadBSprm( pSep, pIds[1], 0 ));
965 
966  // sprmSNfcPgn
967  aNewSection.maSep.nfcPgn = ReadBSprm( pSep, pIds[2], 0 );
968  if (aNewSection.maSep.nfcPgn > 4)
969  aNewSection.maSep.nfcPgn = 0;
970 
971  aNewSection.maSep.fUnlocked = eVer > ww::eWW2 ? ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFProtected : NS_sprm::SFProtected::val), 0 ) : 0;
972 
973  // sprmSFBiDi
974  aNewSection.maSep.fBiDi = eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFBiDi::val, 0) : 0;
975 
976  // Reading section property sprmSCcolumns - one less than the number of columns in the section.
977  // It must be less than MAX_NO_OF_SEP_COLUMNS according the WW8 specification.
978  aNewSection.maSep.ccolM1 = ReadSprm(pSep, pIds[3], 0 );
979  if ( aNewSection.maSep.ccolM1 >= MAX_NO_OF_SEP_COLUMNS )
980  {
981  // clip to max
982  aNewSection.maSep.ccolM1 = MAX_NO_OF_SEP_COLUMNS-1;
983  }
984 
985  //sprmSDxaColumns - default distance 1.25 cm
986  aNewSection.maSep.dxaColumns = ReadUSprm( pSep, pIds[4], 708 );
987 
988  // sprmSLBetween
989  aNewSection.maSep.fLBetween = ReadBSprm(pSep, pIds[5], 0 );
990 
991  if (eVer >= ww::eWW6)
992  {
993  // sprmSFEvenlySpaced
994  aNewSection.maSep.fEvenlySpaced =
996 
997  if (aNewSection.maSep.ccolM1 > 0 && !aNewSection.maSep.fEvenlySpaced)
998  {
999  int nColumnDataIdx = 0;
1000  aNewSection.maSep.rgdxaColumnWidthSpacing[nColumnDataIdx] = 0;
1001 
1002  const sal_uInt16 nColumnWidthSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColWidth : NS_sprm::SDxaColWidth::val);
1003  const sal_uInt16 nColumnSpacingSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColSpacing : NS_sprm::SDxaColSpacing::val);
1004  const sal_uInt8 nColumnCount = static_cast< sal_uInt8 >(aNewSection.maSep.ccolM1 + 1);
1005  for ( sal_uInt8 nColumn = 0; nColumn < nColumnCount; ++nColumn )
1006  {
1007  //sprmSDxaColWidth
1008  SprmResult aSWRes = pSep->HasSprm(nColumnWidthSprmId, nColumn);
1009  const sal_uInt8* pSW = aSWRes.pSprm;
1010 
1011  OSL_ENSURE( pSW, "+Sprm 136 (resp. 0xF203) (ColWidth) missing" );
1012  sal_uInt16 nWidth = (pSW && aSWRes.nRemainingData >= 3) ? SVBT16ToUInt16(pSW + 1) : 1440;
1013 
1014  aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
1015 
1016  if ( nColumn < nColumnCount - 1 )
1017  {
1018  //sprmSDxaColSpacing
1019  SprmResult aSDRes = pSep->HasSprm(nColumnSpacingSprmId, nColumn);
1020  const sal_uInt8* pSD = aSDRes.pSprm;
1021 
1022  OSL_ENSURE( pSD, "+Sprm 137 (resp. 0xF204) (Colspacing) missing" );
1023  if (pSD && aSDRes.nRemainingData >= 3)
1024  {
1025  nWidth = SVBT16ToUInt16(pSD + 1);
1026  aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
1027  }
1028  }
1029  }
1030  }
1031  }
1032 
1033  static const sal_uInt16 aVer2Ids1[] =
1034  {
1035  /*sprmSBOrientation*/ 137,
1036  /*sprmSXaPage*/ 139,
1037  /*sprmSYaPage*/ 140,
1038  /*sprmSDxaLeft*/ 141,
1039  /*sprmSDxaRight*/ 142,
1040  /*sprmSDzaGutter*/ 145,
1041  /*sprmSFPgnRestart*/ 125,
1042  /*sprmSPgnStart*/ 136,
1043  /*sprmSDmBinFirst*/ 115,
1044  /*sprmSDmBinOther*/ 116
1045  };
1046 
1047  static const sal_uInt16 aVer67Ids1[] =
1048  {
1059  };
1060 
1061  static const sal_uInt16 aVer8Ids1[] =
1062  {
1073  };
1074 
1075  pIds = eVer <= ww::eWW2 ? aVer2Ids1 : eVer <= ww::eWW7 ? aVer67Ids1 : aVer8Ids1;
1076 
1077  // 1. orientation
1078  aNewSection.maSep.dmOrientPage = ReadBSprm(pSep, pIds[0], 0);
1079 
1080  // 2. paper size
1081  aNewSection.maSep.xaPage = ReadUSprm(pSep, pIds[1], lLetterWidth);
1082  aNewSection.nPgWidth = SvxPaperInfo::GetSloppyPaperDimension(aNewSection.maSep.xaPage);
1083 
1084  aNewSection.maSep.yaPage = ReadUSprm(pSep, pIds[2], lLetterHeight);
1085 
1086  // 3. LR borders
1087  static const sal_uInt16 nLef[] = { MM_250, 1800 };
1088  static const sal_uInt16 nRig[] = { MM_250, 1800 };
1089 
1090  aNewSection.maSep.dxaLeft = ReadUSprm( pSep, pIds[3], nLef[nLIdx]);
1091  aNewSection.maSep.dxaRight = ReadUSprm( pSep, pIds[4], nRig[nLIdx]);
1092 
1093  // 2pages in 1sheet hackery ?
1094  // #i31806# but only swap if 2page in 1sheet is enabled.
1095  // it's not clear if dmOrientPage is the correct member to
1096  // decide on this.
1097  if(mrReader.m_xWDop->doptypography.m_f2on1 &&
1098  aNewSection.maSep.dmOrientPage == 2)
1099  std::swap(aNewSection.maSep.dxaLeft, aNewSection.maSep.dxaRight);
1100 
1101  aNewSection.maSep.dzaGutter = ReadUSprm( pSep, pIds[5], 0);
1102 
1103  aNewSection.maSep.fRTLGutter = static_cast<sal_uInt8>(
1104  eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFRTLGutter::val, 0) : 0);
1105 
1106  // Page Number Restarts - sprmSFPgnRestart
1107  aNewSection.maSep.fPgnRestart = ReadBSprm(pSep, pIds[6], 0);
1108 
1109  aNewSection.maSep.pgnStart = ReadUSprm( pSep, pIds[7], 0 );
1110 
1111  // if the document's first page number is unspecified, but it starts with an even page break,
1112  // then set the first page number to two
1113  if ( maSegments.empty() && !aNewSection.maSep.fPgnRestart && pSprmBkc && *pSprmBkc == 3 )
1114  {
1115  aNewSection.maSep.pgnStart = 2;
1116  aNewSection.maSep.fPgnRestart = 1;
1117  }
1118 
1119  if (eVer >= ww::eWW6)
1120  {
1122  if (aRes.pSprm && aRes.nRemainingData >= 1)
1123  aNewSection.maSep.iHeadingPgn = *aRes.pSprm;
1124 
1126  if (aRes.pSprm && aRes.nRemainingData >= 1)
1127  aNewSection.maSep.cnsPgn = *aRes.pSprm;
1128  }
1129 
1130  aRes = pSep->HasSprm(pIds[8]);
1131  const sal_uInt8* pSprmSDmBinFirst = aRes.pSprm;
1132  if (pSprmSDmBinFirst && aRes.nRemainingData >= 1)
1133  aNewSection.maSep.dmBinFirst = *pSprmSDmBinFirst;
1134 
1135  aRes = pSep->HasSprm(pIds[9]);
1136  const sal_uInt8* pSprmSDmBinOther = aRes.pSprm;
1137  if (pSprmSDmBinOther && aRes.nRemainingData >= 1)
1138  aNewSection.maSep.dmBinOther = *pSprmSDmBinOther;
1139 
1140  static const sal_uInt16 nTop[] = { MM_250, 1440 };
1141  static const sal_uInt16 nBot[] = { MM_200, 1440 };
1142 
1143  static const sal_uInt16 aVer2Ids2[] =
1144  {
1145  /*sprmSDyaTop*/ 143,
1146  /*sprmSDyaBottom*/ 144,
1147  /*sprmSDyaHdrTop*/ 131,
1148  /*sprmSDyaHdrBottom*/ 132,
1149  /*sprmSNLnnMod*/ 129,
1150  /*sprmSLnc*/ 127,
1151  /*sprmSDxaLnn*/ 130,
1152  /*sprmSLnnMin*/ 135
1153  };
1154 
1155  static const sal_uInt16 aVer67Ids2[] =
1156  {
1165  };
1166  static const sal_uInt16 aVer8Ids2[] =
1167  {
1176  };
1177 
1178  pIds = eVer <= ww::eWW2 ? aVer2Ids2 : eVer <= ww::eWW7 ? aVer67Ids2 : aVer8Ids2;
1179 
1180  aNewSection.maSep.dyaTop = ReadSprm( pSep, pIds[0], nTop[nLIdx] );
1181  aNewSection.maSep.dyaBottom = ReadSprm( pSep, pIds[1], nBot[nLIdx] );
1182  aNewSection.maSep.dyaHdrTop = ReadUSprm( pSep, pIds[2], 720 );
1183  aNewSection.maSep.dyaHdrBottom = ReadUSprm( pSep, pIds[3], 720 );
1184 
1185  if (eVer >= ww::eWW8)
1186  {
1187  aNewSection.maSep.wTextFlow = ReadUSprm(pSep, NS_sprm::STextFlow::val, 0);
1188  aNewSection.maSep.clm = ReadUSprm( pSep, NS_sprm::SClm::val, 0 );
1189  aNewSection.maSep.dyaLinePitch = ReadUSprm(pSep, NS_sprm::SDyaLinePitch::val, 360);
1190  aRes = pSep->HasSprm(NS_sprm::SDxtCharSpace::val);
1191  if (aRes.pSprm && aRes.nRemainingData >= 4)
1192  aNewSection.maSep.dxtCharSpace = SVBT32ToUInt32(aRes.pSprm);
1193 
1194  //sprmSPgbProp
1195  sal_uInt16 pgbProp = ReadSprm( pSep, NS_sprm::SPgbProp::val, 0 );
1196  aNewSection.maSep.pgbApplyTo = pgbProp & 0x0007;
1197  aNewSection.maSep.pgbPageDepth = (pgbProp & 0x0018) >> 3;
1198  aNewSection.maSep.pgbOffsetFrom = (pgbProp & 0x00E0) >> 5;
1199 
1200  aNewSection.mnBorders = ::lcl_ReadBorders(false, aNewSection.brc, nullptr, nullptr, pSep);
1201  }
1202 
1203  // check if Line Numbering must be activated or reset
1204  SprmResult aSprmSNLnnMod = pSep->HasSprm(pIds[4]);
1205  if (aSprmSNLnnMod.pSprm && aSprmSNLnnMod.nRemainingData >= 1)
1206  aNewSection.maSep.nLnnMod = *aSprmSNLnnMod.pSprm;
1207 
1208  SprmResult aSprmSLnc = pSep->HasSprm(pIds[5]);
1209  if (aSprmSLnc.pSprm && aSprmSLnc.nRemainingData >= 1)
1210  aNewSection.maSep.lnc = *aSprmSLnc.pSprm;
1211 
1212  SprmResult aSprmSDxaLnn = pSep->HasSprm(pIds[6]);
1213  if (aSprmSDxaLnn.pSprm && aSprmSDxaLnn.nRemainingData >= 2)
1214  aNewSection.maSep.dxaLnn = SVBT16ToUInt16(aSprmSDxaLnn.pSprm);
1215 
1216  SprmResult aSprmSLnnMin = pSep->HasSprm(pIds[7]);
1217  if (aSprmSLnnMin.pSprm && aSprmSLnnMin.nRemainingData >= 1)
1218  aNewSection.maSep.lnnMin = *aSprmSLnnMin.pSprm;
1219 
1220  if (eVer <= ww::eWW7)
1221  aNewSection.maSep.grpfIhdt = ReadBSprm(pSep, eVer <= ww::eWW2 ? 128 : 153, 0);
1222  else if (mrReader.m_xHdFt)
1223  {
1224  aNewSection.maSep.grpfIhdt = WW8_HEADER_ODD | WW8_FOOTER_ODD
1226 
1227  // It is possible for a first page header to be provided
1228  // for this section, but not actually shown in this section. In this
1229  // case (aNewSection.maSep.grpfIhdt & WW8_HEADER_FIRST) will be nonzero
1230  // but aNewSection.HasTitlePage() will be false.
1231  // Likewise for first page footer.
1232 
1233  if (mrReader.m_xWDop->fFacingPages)
1234  aNewSection.maSep.grpfIhdt |= WW8_HEADER_EVEN | WW8_FOOTER_EVEN;
1235 
1236  //See if we have a header or footer for each enabled possibility
1237  //if we do not then we inherit the previous sections header/footer,
1238  for (int nI = 0, nMask = 1; nI < 6; ++nI, nMask <<= 1)
1239  {
1240  if (aNewSection.maSep.grpfIhdt & nMask)
1241  {
1242  WW8_CP nStart, nLen;
1243  mrReader.m_xHdFt->GetTextPosExact( static_cast< short >(nI + ( maSegments.size() + 1) * 6), nStart, nLen);
1244  //No header or footer, inherit previous one, or set to zero
1245  //if no previous one
1246  if (!nLen)
1247  {
1248  if (
1249  maSegments.empty() ||
1250  !(maSegments.back().maSep.grpfIhdt & nMask)
1251  )
1252  {
1253  aNewSection.maSep.grpfIhdt &= ~nMask;
1254  }
1255  }
1256  }
1257  }
1258  }
1259 
1260  SetLeftRight(aNewSection);
1261  //END read section values
1262 
1263  if (eVer >= ww::eWW8)
1264  aNewSection.SetDirection();
1265 
1266  mrReader.HandleLineNumbering(aNewSection);
1267  maSegments.push_back(aNewSection);
1268 }
1269 
1271  SwPageDesc* pNewPageDesc, sal_uInt8 nCode )
1272 {
1273  // copy odd header content section
1274  if( nCode & WW8_HEADER_ODD )
1275  {
1276  m_rDoc.CopyHeader(pOrgPageDesc->GetMaster(),
1277  pNewPageDesc->GetMaster() );
1278  }
1279  // copy odd footer content section
1280  if( nCode & WW8_FOOTER_ODD )
1281  {
1282  m_rDoc.CopyFooter(pOrgPageDesc->GetMaster(),
1283  pNewPageDesc->GetMaster());
1284  }
1285  // copy even header content section
1286  if( nCode & WW8_HEADER_EVEN )
1287  {
1288  m_rDoc.CopyHeader(pOrgPageDesc->GetLeft(),
1289  pNewPageDesc->GetLeft());
1290  }
1291  // copy even footer content section
1292  if( nCode & WW8_FOOTER_EVEN )
1293  {
1294  m_rDoc.CopyFooter(pOrgPageDesc->GetLeft(),
1295  pNewPageDesc->GetLeft());
1296  }
1297  // copy first page header content section
1298  if( nCode & WW8_HEADER_FIRST )
1299  {
1300  m_rDoc.CopyHeader(pOrgPageDesc->GetFirstMaster(),
1301  pNewPageDesc->GetFirstMaster());
1302  }
1303  // copy first page footer content section
1304  if( nCode & WW8_FOOTER_FIRST )
1305  {
1306  m_rDoc.CopyFooter(pOrgPageDesc->GetFirstMaster(),
1307  pNewPageDesc->GetFirstMaster());
1308  }
1309 }
1310 
1311 // helper functions for graphics, Apos and tables
1312 
1313 // Read BoRder Control structure
1314 // nBrcVer should be set to the version of the BRC record being read (6, 8 or 9)
1315 // This will be converted to the latest format (9).
1316 static bool SetWW8_BRC(int nBrcVer, WW8_BRCVer9& rVar, const sal_uInt8* pS, size_t nLen)
1317 {
1318 
1319  if( pS )
1320  {
1321  if (nBrcVer == 9 && nLen >= sizeof(WW8_BRCVer9))
1322  rVar = *reinterpret_cast<const WW8_BRCVer9*>(pS);
1323  else if (nBrcVer == 8 && nLen >= sizeof(WW8_BRC))
1324  rVar = WW8_BRCVer9(*reinterpret_cast<const WW8_BRC*>(pS));
1325  else if (nLen >= sizeof(WW8_BRCVer6)) // nBrcVer == 6
1326  rVar = WW8_BRCVer9(WW8_BRC(*reinterpret_cast<const WW8_BRCVer6*>(pS)));
1327  }
1328 
1329  return nullptr != pS;
1330 }
1331 
1332 static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
1333  const WW8RStyle* pSty, const WW8PLCFx_SEPX* pSep)
1334 {
1335 
1336 //returns a sal_uInt8 filled with a bit for each position that had a sprm
1337 //setting that border
1338 
1339  sal_uInt8 nBorder = 0;
1340  if( pSep )
1341  {
1342  if( !bVer67 )
1343  {
1344  SprmResult a8Sprm[4];
1345  if (pSep->Find4Sprms(
1348  a8Sprm[0], a8Sprm[1], a8Sprm[2], a8Sprm[3]))
1349  {
1350  for( int i = 0; i < 4; ++i )
1351  nBorder |= int(SetWW8_BRC(8, brc[i], a8Sprm[i].pSprm, a8Sprm[i].nRemainingData))<<i;
1352  }
1353 
1354  // Version 9 BRCs if present will override version 8
1355  SprmResult a9Sprm[4];
1356  if (pSep->Find4Sprms(
1359  a9Sprm[0], a9Sprm[1], a9Sprm[2], a9Sprm[3]))
1360  {
1361  for( int i = 0; i < 4; ++i )
1362  nBorder |= int(SetWW8_BRC(9, brc[i], a9Sprm[i].pSprm, a9Sprm[i].nRemainingData))<<i;
1363  }
1364  }
1365  }
1366  else
1367  {
1368 
1369  static const sal_uInt16 aVer67Ids[5] = {
1375  };
1376 
1377  static const sal_uInt16 aVer8Ids[5] = {
1383  };
1384 
1385  static const sal_uInt16 aVer9Ids[5] = {
1391  };
1392 
1393  if( pPap )
1394  {
1395  if (bVer67)
1396  {
1397  for( int i = 0; i < 5; ++i )
1398  {
1399  SprmResult aRes(pPap->HasSprm(aVer67Ids[i]));
1400  nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1401  }
1402  }
1403  else
1404  {
1405  for( int i = 0; i < 5; ++i )
1406  {
1407  SprmResult aRes(pPap->HasSprm(aVer8Ids[i]));
1408  nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1409  }
1410  // Version 9 BRCs if present will override version 8
1411  for( int i = 0; i < 5; ++i )
1412  {
1413  SprmResult aRes(pPap->HasSprm(aVer9Ids[i]));
1414  nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1415  }
1416  }
1417  }
1418  else if( pSty )
1419  {
1420  if (bVer67)
1421  {
1422  for( int i = 0; i < 5; ++i )
1423  {
1424  SprmResult aRes(pSty->HasParaSprm(aVer67Ids[i]));
1425  nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1426  }
1427  }
1428  else
1429  {
1430  for( int i = 0; i < 5; ++i )
1431  {
1432  SprmResult aRes(pSty->HasParaSprm(aVer8Ids[i]));
1433  nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1434  }
1435  // Version 9 BRCs if present will override version 8
1436  for( int i = 0; i < 5; ++i )
1437  {
1438  SprmResult aRes(pSty->HasParaSprm(aVer9Ids[i]));
1439  nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1440  }
1441  }
1442  }
1443  else {
1444  OSL_ENSURE( pSty || pPap, "WW8PLCFx_Cp_FKP and WW8RStyle "
1445  "and WW8PLCFx_SEPX is 0" );
1446  }
1447  }
1448 
1449  return nBorder;
1450 }
1451 
1452 static void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace,
1453  sal_uInt32 cv, short nIdx, SvxBoxItemLine nOOIndex, sal_uInt16 nWWIndex,
1454  short *pSize)
1455 {
1456  // LO cannot handle outset/inset (new in WW9 BRC) so fall back same as WW8
1457  if ( nIdx == 0x1A || nIdx == 0x1B )
1458  {
1459  nIdx = (nIdx == 0x1A) ? 0x12 : 0x11;
1460  cv = 0xc0c0c0;
1461  }
1462 
1463  SvxBorderLineStyle const eStyle(
1465 
1467  aLine.SetBorderLineStyle( eStyle );
1468  double const fConverted( (SvxBorderLineStyle::NONE == eStyle) ? 0.0 :
1469  ::editeng::ConvertBorderWidthFromWord(eStyle, nLineThickness, nIdx));
1470  aLine.SetWidth(fConverted);
1471 
1472  //No AUTO for borders as yet, so if AUTO, use BLACK
1473  Color col = (cv==0xff000000) ? COL_BLACK : msfilter::util::BGRToRGB(cv);
1474 
1475  aLine.SetColor(col);
1476 
1477  if (pSize)
1478  pSize[nWWIndex] = fConverted + nSpace;
1479 
1480  rBox.SetLine(&aLine, nOOIndex);
1481  rBox.SetDistance(nSpace, nOOIndex);
1482 
1483 }
1484 
1485 static void Set1Border(SvxBoxItem &rBox, const WW8_BRCVer9& rBor, SvxBoxItemLine nOOIndex,
1486  sal_uInt16 nWWIndex, short *pSize, const bool bIgnoreSpace)
1487 {
1488  short nSpace;
1489  short nLineThickness = rBor.DetermineBorderProperties(&nSpace);
1490 
1491  GetLineIndex(rBox, nLineThickness, bIgnoreSpace ? 0 : nSpace,
1492  rBor.cv(), rBor.brcType(), nOOIndex, nWWIndex, pSize );
1493 
1494 }
1495 
1496 static bool lcl_IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn = false)
1497 {
1498  return pbrc[WW8_TOP ].brcType() || // brcType != 0
1499  pbrc[WW8_LEFT ].brcType() ||
1500  pbrc[WW8_BOT ].brcType() ||
1501  pbrc[WW8_RIGHT].brcType() ||
1502  (bChkBtwn && pbrc[WW8_BETW ].brcType());
1503 }
1504 
1505 bool SwWW8ImplReader::IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn)
1506 {
1507  return lcl_IsBorder(pbrc, bChkBtwn);
1508 }
1509 
1511  short *pSizeArray, sal_uInt8 nSetBorders)
1512 {
1513  bool bChange = false;
1514  static const std::pair<sal_uInt16, SvxBoxItemLine> aIdArr[] =
1515  {
1516  { WW8_TOP, SvxBoxItemLine::TOP },
1517  { WW8_LEFT, SvxBoxItemLine::LEFT },
1518  { WW8_RIGHT, SvxBoxItemLine::RIGHT },
1519  { WW8_BOT, SvxBoxItemLine::BOTTOM },
1520  { WW8_BETW, SvxBoxItemLine::BOTTOM }
1521  };
1522 
1523  for( int i = 0; i < 4; ++i )
1524  {
1525  // filter out the invalid borders
1526  const WW8_BRCVer9& rB = pbrc[ aIdArr[ i ].first ];
1527  if( !rB.isNil() && rB.brcType() )
1528  {
1529  Set1Border(rBox, rB, aIdArr[i].second, aIdArr[i].first, pSizeArray, false);
1530  bChange = true;
1531  }
1532  else if ( nSetBorders & (1 << aIdArr[i].first) )
1533  {
1534  /*
1535  ##826##, ##653##
1536 
1537  If a style has borders set,and the para attributes attempt remove
1538  the borders, then this is perfectly acceptable, so we shouldn't
1539  ignore this blank entry
1540 
1541  nSetBorders has a bit set for each location that a sprm set a
1542  border, so with a sprm set, but no border, then disable the
1543  appropriate border
1544  */
1545  rBox.SetLine( nullptr, aIdArr[ i ].second );
1546  }
1547  }
1548  return bChange;
1549 }
1550 
1551 bool SwWW8ImplReader::SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
1552  const WW8_BRCVer9& aRightBrc)
1553 {
1554  bool bRet = aRightBrc.fShadow() && pSizeArray && pSizeArray[WW8_RIGHT];
1555  if (bRet)
1556  {
1557  rShadow.SetColor(COL_BLACK);
1558  //i120718
1559  short nVal = aRightBrc.DetermineBorderProperties();
1560  //End
1561  if (nVal < 0x10)
1562  nVal = 0x10;
1563  rShadow.SetWidth(nVal);
1564  rShadow.SetLocation(SvxShadowLocation::BottomRight);
1565  bRet = true;
1566  }
1567  return bRet;
1568 }
1569 
1571  tools::Rectangle& rInnerDist)
1572 {
1573  rInnerDist = tools::Rectangle( pbrc[ 1 ].dptSpace() * 20,
1574  pbrc[ 0 ].dptSpace() * 20,
1575  pbrc[ 3 ].dptSpace() * 20,
1576  pbrc[ 2 ].dptSpace() * 20 );
1577 }
1578 
1580  const WW8_BRCVer9 *pbrc, short *pSizeArray)
1581 {
1582  bool bShadowed = false;
1583  if (IsBorder(pbrc))
1584  {
1585  SvxBoxItem aBox( RES_BOX );
1586  SetBorder(aBox, pbrc, pSizeArray);
1587 
1588  rFlySet.Put( aBox );
1589 
1590  // fShadow
1591  SvxShadowItem aShadow( RES_SHADOW );
1592  if( SetShadow( aShadow, pSizeArray, pbrc[WW8_RIGHT] ))
1593  {
1594  bShadowed = true;
1595  rFlySet.Put( aShadow );
1596  }
1597  }
1598  return bShadowed;
1599 }
1600 
1601 // APOs
1602 
1603  // for computing the minimal FrameSize
1604 #define MAX_BORDER_SIZE 210 // max. size of border
1605 #define MAX_EMPTY_BORDER 10 // for off-by-one errors, at least 1
1606 
1607 static void FlySecur1(short& rSize, const bool bBorder)
1608 {
1609  short nMin = MINFLY +
1610  (bBorder ? MAX_BORDER_SIZE : MAX_EMPTY_BORDER);
1611 
1612  if ( rSize < nMin )
1613  rSize = nMin;
1614 }
1615 
1616 static bool SetValSprm( sal_Int16* pVar, WW8PLCFx_Cp_FKP* pPap, sal_uInt16 nId )
1617 {
1618  SprmResult aS = pPap->HasSprm(nId);
1619  if (aS.pSprm && aS.nRemainingData >= 2)
1620  *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
1621  return aS.pSprm != nullptr;
1622 }
1623 
1624 static bool SetValSprm( sal_Int16* pVar, const WW8RStyle* pStyle, sal_uInt16 nId )
1625 {
1626  SprmResult aS = pStyle->HasParaSprm(nId);
1627  if (aS.pSprm && aS.nRemainingData >= 2)
1628  *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
1629  return aS.pSprm != nullptr;
1630 }
1631 
1632 /*
1633 #i1930 revealed that sprm 0x360D (sprmTPc) as used in tables can affect the frame
1634 around the table. Its full structure is not fully understood as yet.
1635 */
1637 {
1638  if (pTabPos)
1639  {
1640  nSp26 = pTabPos->nSp26;
1641  nSp27 = pTabPos->nSp27;
1642  nSp29 = pTabPos->nSp29;
1643  nLeMgn = pTabPos->nLeMgn;
1644  nRiMgn = pTabPos->nRiMgn;
1645  nUpMgn = pTabPos->nUpMgn;
1646  nLoMgn = pTabPos->nLoMgn;
1647  nSp37 = pTabPos->nSp37;
1648  }
1649 }
1650 
1651 WW8FlyPara::WW8FlyPara(bool bIsVer67, const WW8FlyPara* pSrc /* = 0 */)
1652 {
1653  if ( pSrc )
1654  memcpy( this, pSrc, sizeof( WW8FlyPara ) ); // Copy-Ctor
1655  else
1656  {
1657  nSp26 = 0;
1658  nSp27 = 0;
1659  nSp45 = 0;
1660  nSp28 = 0;
1661  nLeMgn = 0;
1662  nRiMgn = 0;
1663  nUpMgn = 0;
1664  nLoMgn = 0;
1665  nSp29 = 0;
1666  nSp37 = 2; // Default: wrapping
1667  bBorderLines = false;
1668  bGrafApo = false;
1669  mbVertSet = false;
1670  }
1671  bVer67 = bIsVer67;
1672 }
1673 
1674 bool WW8FlyPara::operator==(const WW8FlyPara& rSrc) const
1675 {
1676  /*
1677  Compare the parts that word seems to compare for equivalence.
1678  Interestingly being autoheight or absolute height (the & 0x7fff) doesn't
1679  matter to word
1680  */
1681  return
1682  (
1683  (nSp26 == rSrc.nSp26) &&
1684  (nSp27 == rSrc.nSp27) &&
1685  ((nSp45 & 0x7fff) == (rSrc.nSp45 & 0x7fff)) &&
1686  (nSp28 == rSrc.nSp28) &&
1687  (nLeMgn == rSrc.nLeMgn) &&
1688  (nRiMgn == rSrc.nRiMgn) &&
1689  (nUpMgn == rSrc.nUpMgn) &&
1690  (nLoMgn == rSrc.nLoMgn) &&
1691  (nSp29 == rSrc.nSp29) &&
1692  (nSp37 == rSrc.nSp37)
1693  );
1694 }
1695 
1696 // Read for normal text
1698 {
1699  if( bVer67 )
1700  {
1701  SetValSprm( &nSp26, pPap, 26 ); // X-position //sprmPDxaAbs
1702  //set in me or in parent style
1703  mbVertSet |= SetValSprm( &nSp27, pPap, 27 ); // Y-position //sprmPDyaAbs
1704  SetValSprm( &nSp45, pPap, 45 ); // height //sprmPWHeightAbs
1705  SetValSprm( &nSp28, pPap, 28 ); // width //sprmPDxaWidth
1706  SetValSprm( &nLeMgn, pPap, 49 ); // L-border //sprmPDxaFromText
1707  SetValSprm( &nRiMgn, pPap, 49 ); // R-border //sprmPDxaFromText
1708  SetValSprm( &nUpMgn, pPap, 48 ); // U-border //sprmPDyaFromText
1709  SetValSprm( &nLoMgn, pPap, 48 ); // D-border //sprmPDyaFromText
1710 
1712  if (aS.pSprm && aS.nRemainingData >= 1)
1713  nSp37 = *aS.pSprm;
1714  }
1715  else
1716  {
1717  SetValSprm( &nSp26, pPap, NS_sprm::PDxaAbs::val ); // X-position
1718  //set in me or in parent style
1719  mbVertSet |= SetValSprm( &nSp27, pPap, NS_sprm::PDyaAbs::val ); // Y-position
1720  SetValSprm( &nSp45, pPap, NS_sprm::PWHeightAbs::val ); // height
1721  SetValSprm( &nSp28, pPap, NS_sprm::PDxaWidth::val ); // width
1722  SetValSprm( &nLeMgn, pPap, NS_sprm::PDxaFromText::val ); // L-border
1723  SetValSprm( &nRiMgn, pPap, NS_sprm::PDxaFromText::val ); // R-border
1724  SetValSprm( &nUpMgn, pPap, NS_sprm::PDyaFromText::val ); // U-border
1725  SetValSprm( &nLoMgn, pPap, NS_sprm::PDyaFromText::val ); // D-border
1726 
1727  SprmResult aS = pPap->HasSprm(NS_sprm::PWr::val); // wrapping
1728  if (aS.pSprm && aS.nRemainingData >= 1)
1729  nSp37 = *aS.pSprm;
1730  }
1731 
1732  if( ::lcl_ReadBorders( bVer67, brc, pPap )) // borders
1734 
1735  /*
1736  #i8798#
1737  Appears that with no dyaAbs set then the actual vert anchoring set is
1738  ignored and we remain relative to text, so if that is the case we are 0
1739  from para anchor, so we update the frame to have explicitly this type of
1740  anchoring
1741  */
1742  if (!mbVertSet)
1743  nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1744  else
1745  nSp29 = nOrigSp29;
1746 }
1747 
1749 {
1750  std::shared_ptr<WW8PLCFMan> xPlcxMan = pIo->m_xPlcxMan;
1751  WW8PLCFx_Cp_FKP* pPap = xPlcxMan->GetPapPLCF();
1752 
1753  Read(nOrigSp29, pPap); // read Apo parameter
1754 
1755  do{ // block for quick exit
1756  if( nSp45 != 0 /* || nSp28 != 0 */ )
1757  break; // bGrafApo only automatic for height
1758  if( pIo->m_xWwFib->m_fComplex )
1759  break; // (*pPap)++ does not work for FastSave
1760  // -> for FastSave, no test for graphics APO
1761  SvStream* pIoStrm = pIo->m_pStrm;
1762  sal_uInt64 nPos = pIoStrm->Tell();
1763  WW8PLCFxSave1 aSave;
1764  xPlcxMan->GetPap()->Save( aSave );
1765  bGrafApo = false;
1766 
1767  do{ // block for quick exit
1768  sal_uInt8 nText[2];
1769 
1770  if (!checkRead(*pIoStrm, nText, 2)) // read text
1771  break;
1772 
1773  if( nText[0] != 0x01 || nText[1] != 0x0d )// only graphics + CR?
1774  break; // no
1775 
1776  pPap->advance(); // next line
1777 
1778  // in APO ?
1779  //sprmPPc
1781 
1782  // no -> graphics Apo
1783  if (!aS.pSprm || aS.nRemainingData < 1)
1784  {
1785  bGrafApo = true;
1786  break; // end of APO
1787  }
1788 
1789  ww::WordVersion eVer = pIo->GetFib().GetFIBVersion();
1790  WW8FlyPara *pNowStyleApo=nullptr;
1791  sal_uInt16 nColl = pPap->GetIstd();
1792 
1793  o3tl::sorted_vector<sal_uInt16> aSeenStyles;
1794  ww::sti eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc(nColl) : static_cast<ww::sti>(nColl);
1795  while (eSti != ww::stiNil && static_cast<size_t>(nColl) < pIo->m_vColl.size() && nullptr == (pNowStyleApo = pIo->m_vColl[nColl].m_xWWFly.get()))
1796  {
1797  aSeenStyles.insert(nColl);
1798 
1799  nColl = pIo->m_vColl[nColl].m_nBase;
1800 
1801  if (aSeenStyles.find(nColl) != aSeenStyles.end())
1802  {
1803  SAL_WARN("sw.ww8", "loop in style chain");
1804  break;
1805  }
1806 
1807  eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc(nColl) : static_cast<ww::sti>(nColl);
1808  }
1809 
1810  WW8FlyPara aF(bVer67, pNowStyleApo);
1811  // new FlaPara for comparison
1812  aF.Read(*aS.pSprm, pPap); // WWPara for new Para
1813  if( !( aF == *this ) ) // same APO? (or a new one?)
1814  bGrafApo = true; // no -> 1-line APO
1815  // -> graphics APO
1816  }
1817  while( false ); // block for quick exit
1818 
1819  xPlcxMan->GetPap()->Restore( aSave );
1820  pIoStrm->Seek( nPos );
1821  }while( false ); // block for quick exit
1822 }
1823 
1824 // read for Apo definitions in Styledefs
1825 void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8RStyle const * pStyle)
1826 {
1827  if (bVer67)
1828  {
1829  SetValSprm( &nSp26, pStyle, NS_sprm::v6::sprmPDxaAbs ); // X-position
1830  //set in me or in parent style
1831  mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::v6::sprmPDyaAbs); // Y-position
1832  SetValSprm( &nSp45, pStyle, NS_sprm::v6::sprmPWHeightAbs ); // height
1833  SetValSprm( &nSp28, pStyle, NS_sprm::v6::sprmPDxaWidth ); // width
1834  SetValSprm( &nLeMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // L-border
1835  SetValSprm( &nRiMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // R-border
1836  SetValSprm( &nUpMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // U-border
1837  SetValSprm( &nLoMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // D-border
1838 
1839  SprmResult aS = pStyle->HasParaSprm( NS_sprm::v6::sprmPWr ); // wrapping
1840  if (aS.pSprm && aS.nRemainingData >= 1)
1841  nSp37 = *aS.pSprm;
1842  }
1843  else
1844  {
1845  SetValSprm( &nSp26, pStyle, NS_sprm::PDxaAbs::val ); // X-position
1846  //set in me or in parent style
1847  mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::PDyaAbs::val); // Y-position
1848  SetValSprm( &nSp45, pStyle, NS_sprm::PWHeightAbs::val ); // height
1849  SetValSprm( &nSp28, pStyle, NS_sprm::PDxaWidth::val ); // width
1850  SetValSprm( &nLeMgn, pStyle, NS_sprm::PDxaFromText::val ); // L-border
1851  SetValSprm( &nRiMgn, pStyle, NS_sprm::PDxaFromText::val ); // R-border
1852  SetValSprm( &nUpMgn, pStyle, NS_sprm::PDyaFromText::val ); // U-border
1853  SetValSprm( &nLoMgn, pStyle, NS_sprm::PDyaFromText::val ); // D-border
1854 
1855  SprmResult aS = pStyle->HasParaSprm( NS_sprm::PWr::val ); // wrapping
1856  if (aS.pSprm && aS.nRemainingData >= 1)
1857  nSp37 = *aS.pSprm;
1858  }
1859 
1860  if (::lcl_ReadBorders(bVer67, brc, nullptr, pStyle)) // border
1862 
1863  /*
1864  #i8798#
1865  Appears that with no dyaAbs set then the actual vert anchoring set is
1866  ignored and we remain relative to text, so if that is the case we are 0
1867  from para anchor, so we update the frame to have explicitly this type of
1868  anchoring
1869  */
1870  if (!mbVertSet)
1871  nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1872  else
1873  nSp29 = nOrigSp29;
1874 }
1875 
1877 {
1878  WW8FlyPara aEmpty(bVer67);
1879  /*
1880  wr of 0 like 2 appears to me to be equivalent for checking here. See
1881  #107103# if wrong, so given that the empty is 2, if we are 0 then set
1882  empty to 0 to make 0 equiv to 2 for empty checking
1883  */
1884  OSL_ENSURE(aEmpty.nSp37 == 2, "this is not what we expect for nSp37");
1885  if (this->nSp37 == 0)
1886  aEmpty.nSp37 = 0;
1887  return aEmpty == *this;
1888 }
1889 
1890 // #i18732# - changes made on behalf of CMC
1892  SwWW8ImplReader& rIo,
1893  WW8FlyPara& rWW,
1894  const sal_uInt32 nWWPgTop,
1895  const sal_uInt32 nPgWidth,
1896  const sal_Int32 nIniFlyDx,
1897  const sal_Int32 nIniFlyDy ):
1898 pFlyFormat(nullptr),
1899 nXPos(0),
1900 nYPos(0),
1901 nLeMgn(rWW.nLeMgn),
1902 nRiMgn(rWW.nRiMgn),
1903 nUpMgn(rWW.nUpMgn),
1904 nLoMgn(rWW.nLoMgn),
1905 nWidth(rWW.nSp28),
1906 nHeight(rWW.nSp45),
1907 nNetWidth(rWW.nSp28),
1908 eHeightFix(SwFrameSize::Fixed),
1909 eHRel(text::RelOrientation::PAGE_FRAME),
1910 eVRel(text::RelOrientation::FRAME),
1911 eVAlign(text::VertOrientation::NONE),
1912 eHAlign(text::HoriOrientation::NONE),
1913 eSurround(( rWW.nSp37 > 1 ) ? css::text::WrapTextMode_DYNAMIC : css::text::WrapTextMode_NONE),
1914 nXBind(( rWW.nSp29 & 0xc0 ) >> 6),
1915 nYBind(( rWW.nSp29 & 0x30 ) >> 4),
1916 nNewNetWidth(MINFLY),
1917 nLineSpace(0),
1918 bAutoWidth(false),
1919 bTogglePos(false)
1920 {
1921  //#i119466 mapping "Around" wrap setting to "Parallel" for table
1922  const bool bIsTable = rIo.m_xPlcxMan->HasParaSprm(NS_sprm::PFInTable::val).pSprm;
1923  if (bIsTable && rWW.nSp37 == 2)
1924  eSurround = css::text::WrapTextMode_PARALLEL;
1925 
1926  /*
1927  #95905#, #83307# seems to have gone away now, so re-enable parallel
1928  wrapping support for frames in headers/footers. I don't know if we truly
1929  have an explicitly specified behaviour for these circumstances.
1930  */
1931 
1932  if( nHeight & 0x8000 )
1933  {
1934  nHeight &= 0x7fff;
1936  }
1937 
1938  if( nHeight <= MINFLY )
1939  { // no data, or bad data
1941  nHeight = MINFLY;
1942  }
1943 
1944  if( nWidth <= 10 ) // auto width
1945  {
1946  bAutoWidth = true;
1947  nWidth = nNetWidth =
1948  msword_cast<sal_Int16>(nPgWidth ? nPgWidth : 2268); // 4 cm
1949  }
1950  if( nWidth <= MINFLY )
1951  nWidth = nNetWidth = MINFLY; // minimum width
1952 
1953  /*
1954  See issue #i9178# for the 9 anchoring options, and make sure they stay
1955  working if you modify the anchoring logic here.
1956  */
1957 
1958  // If the Fly is aligned left, right, up, or down,
1959  // the outer text distance will be ignored, because otherwise
1960  // the Fly will end up in the wrong position.
1961  // The only problem is with inside/outside.
1962 
1963  //#i53725# - absolute positioned objects have to be
1964  // anchored at-paragraph to assure its correct anchor position.
1965  rIo.m_pLastAnchorPos.reset( new SwPosition(*rPaM.GetPoint()));
1966 
1967  switch (nYBind)
1968  {
1969  case 0: //relative to margin
1970  eVRel = text::RelOrientation::PAGE_PRINT_AREA;
1971  break;
1972  case 1: //relative to page
1973  eVRel = text::RelOrientation::PAGE_FRAME;
1974  break;
1975  default: //relative to text
1976  // put in initialization part eVRel = text::RelOrientation::FRAME;
1977  break;
1978  }
1979 
1980 // #i18732#
1981  switch( rWW.nSp27 ) // particular Y-positions ?
1982  {
1983  case -4:
1984  eVAlign = text::VertOrientation::TOP;
1985  if (nYBind < 2)
1986  nUpMgn = 0;
1987  break; // up
1988  case -8:
1989  eVAlign = text::VertOrientation::CENTER;
1990  break; // centered
1991  case -12:
1992  eVAlign = text::VertOrientation::BOTTOM;
1993  if (nYBind < 2)
1994  nLoMgn = 0;
1995  break; // down
1996  default:
1997  nYPos = rWW.nSp27 + static_cast<short>(nIniFlyDy);
1998  break; // corrections from ini file
1999  }
2000 
2001  switch( rWW.nSp26 ) // particular X-positions ?
2002  {
2003  case 0:
2004  eHAlign = text::HoriOrientation::LEFT;
2005  nLeMgn = 0;
2006  break; // left
2007  case -4:
2008  eHAlign = text::HoriOrientation::CENTER;
2009  break; // centered
2010  case -8:
2011  eHAlign = text::HoriOrientation::RIGHT;
2012  nRiMgn = 0;
2013  break; // right
2014  case -12:
2015  eHAlign = text::HoriOrientation::LEFT;
2016  bTogglePos = true;
2017  break; // inside
2018  case -16:
2019  eHAlign = text::HoriOrientation::RIGHT;
2020  bTogglePos = true;
2021  break; // outside
2022  default:
2023  nXPos = rWW.nSp26 + static_cast<short>(nIniFlyDx);
2024  break; // corrections from ini file
2025  }
2026 
2027 // #i18732#
2028  switch (nXBind) // X - binding -> transform coordinates
2029  {
2030  case 0: //relative to column
2031  eHRel = text::RelOrientation::FRAME;
2032  break;
2033  case 1: //relative to margin
2034  eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2035  break;
2036  default: //relative to page
2037  // put in initialization part eHRel= text::RelOrientation::PAGE_FRAME;
2038  break;
2039  }
2040 
2041  // #i36649# - adjustments for certain horizontal alignments
2042  // Note: These special adjustments found by an investigation of documents
2043  // containing frames with different left/right border distances and
2044  // distances to text. The outcome is somehow strange.
2045  // Note: These adjustments causes wrong horizontal positions for frames,
2046  // which are aligned inside|outside to page|margin on even pages,
2047  // the left and right border distances are different.
2048  // no adjustments possible, if frame has automatic width.
2049  // determine left border distance
2050  sal_Int16 nLeBorderMgn( 0 );
2051  if ( !bAutoWidth )
2052  {
2053  WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2054  sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeBorderMgn);
2055  nLeBorderMgn = nLeBorderMgn + nTemp;
2056  }
2057  // determine right border distance
2058  sal_Int16 nRiBorderMgn( 0 );
2059  if ( !bAutoWidth )
2060  {
2061  WW8_BRCVer9 &rBrc = rWW.brc[WW8_RIGHT];
2062  sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nRiBorderMgn);
2063  nRiBorderMgn = nRiBorderMgn + nTemp;
2064  }
2065  if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_FRAME )
2066  {
2067  // convert 'left to page' to
2068  // 'from left -<width>-<2*left border distance>-<right wrap distance>
2069  // to page text area'
2071  eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2072  nXPos = -nWidth - (2*nLeBorderMgn) - rWW.nRiMgn;
2073  // re-set left wrap distance
2074  nLeMgn = rWW.nLeMgn;
2075  }
2076  else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_FRAME )
2077  {
2078  // convert 'right to page' to
2079  // 'from left <right border distance-left border distance>+<left wrap distance>
2080  // to right page border'
2082  eHRel = text::RelOrientation::PAGE_RIGHT;
2083  nXPos = ( nRiBorderMgn - nLeBorderMgn ) + rWW.nLeMgn;
2084  // re-set right wrap distance
2085  nRiMgn = rWW.nRiMgn;
2086  }
2087  else if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2088  {
2089  // convert 'left to margin' to
2090  // 'from left -<left border distance> to page text area'
2092  eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2093  nXPos = -nLeBorderMgn;
2094  // re-set left wrap distance
2095  nLeMgn = rWW.nLeMgn;
2096  }
2097  else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2098  {
2099  // convert 'right to margin' to
2100  // 'from left -<width>-<left border distance> to right page border'
2102  eHRel = text::RelOrientation::PAGE_RIGHT;
2103  nXPos = -nWidth - nLeBorderMgn;
2104  // re-set right wrap distance
2105  nRiMgn = rWW.nRiMgn;
2106  }
2107  else if (rWW.bBorderLines)
2108  {
2109  /*
2110  #i582#
2111  Word has a curious bug where the offset stored do not take into
2112  account the internal distance from the corner both
2113  */
2114  WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2115  sal_Int16 nLeLMgn = 0;
2116  sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeLMgn);
2117  nLeLMgn = nLeLMgn + nTemp;
2118 
2119  if (nLeLMgn)
2120  {
2121  if (eHAlign == text::HoriOrientation::LEFT)
2123  nXPos = nXPos - nLeLMgn;
2124  }
2125  }
2126 
2127  // adjustments for certain vertical alignments
2128  if ( eVAlign == text::VertOrientation::NONE && eVRel == text::RelOrientation::PAGE_PRINT_AREA )
2129  {
2130  // convert "<X> from top page text area" to
2131  // "<X + page top margin> from page"
2132  eVRel = text::RelOrientation::PAGE_FRAME;
2133  nYPos = static_cast< sal_Int16 >( nYPos + nWWPgTop );
2134  }
2135 
2136  FlySecur1( nWidth, rWW.bBorderLines ); // Do the borders match ?
2137  FlySecur1( nHeight, rWW.bBorderLines );
2138 
2139 }
2140 
2141 // If a Fly in WW has automatic width, this has to be simulated
2142 // by modifying the Fly width (fixed in SW) afterwards.
2143 // This can increase or decrease the Fly width, because the default value
2144 // is set without knowledge of the contents.
2146 {
2147  if( bAutoWidth && nInWidth > nNewNetWidth )
2148  nNewNetWidth = nInWidth;
2149 };
2150 
2151 // The class WW8FlySet is derived from SfxItemSetFixed and does not
2152 // provide more, but is easier to handle for me.
2153 // WW8FlySet-ctor for Apos and graphics Apos
2155  const WW8SwFlyPara* pFS, bool bGraf)
2156  : SfxItemSetFixed(rReader.m_rDoc.GetAttrPool())
2157 {
2158  Reader::ResetFrameFormatAttrs(*this); // remove distance/border
2159  // position
2160  Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2161 
2162 /*Below can all go when we have from left in rtl mode*/
2163  SwTwips nXPos = pFS->nXPos;
2164  sal_Int16 eHRel = pFS->eHRel;
2165  rReader.MiserableRTLGraphicsHack(nXPos, pFS->nWidth, pFS->eHAlign, eHRel);
2166 /*Above can all go when we have from left in rtl mode*/
2167  Put( SwFormatHoriOrient(nXPos, pFS->eHAlign, pFS->eHRel, pFS->bTogglePos ));
2168  Put( SwFormatVertOrient( pFS->nYPos, pFS->eVAlign, pFS->eVRel ) );
2169 
2170  if (pFS->nLeMgn || pFS->nRiMgn) // set borders
2171  Put(SvxLRSpaceItem(pFS->nLeMgn, pFS->nRiMgn, 0, 0, RES_LR_SPACE));
2172 
2173  if (pFS->nUpMgn || pFS->nLoMgn)
2175 
2176  //we no longer need to hack around the header/footer problems
2177  SwFormatSurround aSurround(pFS->eSurround);
2178  if ( pFS->eSurround == css::text::WrapTextMode_DYNAMIC )
2179  aSurround.SetAnchorOnly( true );
2180  Put( aSurround );
2181 
2182  short aSizeArray[5]={0};
2183  SwWW8ImplReader::SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
2184 
2185  // the 5th parameter is always 0, thus we lose nothing due to the cast
2186 
2187  // #i27767#
2188  // #i35017# - constant name has changed
2190  text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) );
2191 
2192  if( bGraf )
2193  return;
2194 
2196  // adjust size
2197 
2198  //Ordinarily with frames, the border width and spacing is
2199  //placed outside the frame, making it larger. With these
2200  //types of frames, the left right thickness and space makes
2201  //it wider, but the top bottom spacing and border thickness
2202  //is placed inside.
2203  Put( SwFormatFrameSize( pFS->eHeightFix, pFS->nWidth +
2204  aSizeArray[WW8_LEFT] + aSizeArray[WW8_RIGHT],
2205  pFS->nHeight));
2206 }
2207 
2208 // WW8FlySet-ctor for character bound graphics
2210  const WW8_PIC& rPic, tools::Long nWidth, tools::Long nHeight )
2211  : SfxItemSetFixed<RES_FRMATR_BEGIN,RES_FRMATR_END-1>(rReader.m_rDoc.GetAttrPool())
2212 {
2213  Init(rReader, pPaM);
2214 
2215  Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2216 
2217  short aSizeArray[5]={0};
2218  /*
2219  If we have set borders then in word the graphic is displaced from the left
2220  and top the width of the borders of those sides, and then the shadow
2221  itself is drawn to the bottom and right of the displaced graphic. In word
2222  the total size is that of the graphic plus the borders, plus the total
2223  shadow around all edges, for this translation the top and left shadow
2224  region is translated spacing around the graphic to those sides, and the
2225  bottom and right shadow size is added to the graphic size.
2226  */
2227  WW8_BRCVer9 brcVer9[4];
2228  for (int i = 0; i < 4; i++)
2229  brcVer9[i] = WW8_BRCVer9(rPic.rgbrc[i]);
2230  if (SwWW8ImplReader::SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
2231  {
2232  Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, 0, RES_LR_SPACE ) );
2233  Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
2234  aSizeArray[WW8_RIGHT]*=2;
2235  aSizeArray[WW8_BOT]*=2;
2236  }
2237 
2238  Put( SwFormatFrameSize( SwFrameSize::Fixed, nWidth+aSizeArray[WW8_LEFT]+
2239  aSizeArray[WW8_RIGHT], nHeight+aSizeArray[WW8_TOP]
2240  + aSizeArray[WW8_BOT]) );
2241 }
2242 
2243 void WW8FlySet::Init(const SwWW8ImplReader& rReader, const SwPaM* pPaM)
2244 {
2245  Reader::ResetFrameFormatAttrs(*this); // remove distance/borders
2246 
2247  Put(SvxLRSpaceItem(RES_LR_SPACE)); //inline writer ole2 objects start with 0.2cm l/r
2248  SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
2249 
2250  aAnchor.SetAnchor(pPaM->GetPoint());
2251  Put(aAnchor);
2252 
2253  //The horizontal default is on the baseline, the vertical is centered
2254  //around the character center it appears
2256  Put(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER,text::RelOrientation::CHAR));
2257  else
2258  Put(SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME));
2259 }
2260 
2262  : pCtrlStck(pStack),
2263  aChrSet(rDoc.GetAttrPool()),
2264  aParSet(rDoc.GetAttrPool())
2265 {
2266  //Close any open character properties and duplicate them inside the
2267  //first table cell
2268  size_t nCnt = pCtrlStck->size();
2269  for (size_t i=0; i < nCnt; ++i)
2270  {
2271  const SwFltStackEntry& rEntry = (*pCtrlStck)[ i ];
2272  if (rEntry.m_bOpen)
2273  {
2274  if (isCHRATR(rEntry.m_pAttr->Which()))
2275  {
2276  aChrSet.Put( *rEntry.m_pAttr );
2277 
2278  }
2279  else if (isPARATR(rEntry.m_pAttr->Which()))
2280  {
2281  aParSet.Put( *rEntry.m_pAttr );
2282  }
2283  }
2284  }
2285 }
2286 
2288 {
2289  for (const SfxItemSet* pSet : {&aChrSet, &aParSet})
2290  {
2291  if( pSet->Count() )
2292  {
2293  SfxItemIter aIter( *pSet );
2294  const SfxPoolItem* pItem = aIter.GetCurItem();
2295  do
2296  {
2297  pCtrlStck->NewAttr(rPos, *pItem);
2298  } while ((pItem = aIter.NextItem()));
2299  }
2300  }
2301 }
2302 
2304 {
2305  WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2306 
2307  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2308 
2309  // set Pam in FlyFrame
2310  const SwFormatContent& rContent = pFlyFormat->GetContent();
2311  OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
2312  m_pPaM->GetPoint()->nNode = rContent.GetContentIdx()->GetIndex() + 1;
2314 
2315  aDup.Insert(*m_pPaM->GetPoint());
2316 }
2317 
2319  const SwPosition &rPos, bool bTableJoin)
2320 {
2321  SwTwips nRetWidth = 0;
2322  if (!pFlyFormat)
2323  return nRetWidth;
2324  // Close all attributes, because otherwise attributes can appear
2325  // that extend out of Flys
2326  WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2327  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2328 
2329  /*
2330  #i1291
2331  If this fly frame consists entirely of one table inside a frame
2332  followed by an empty paragraph then we want to delete the empty
2333  paragraph so as to get the frame to autoshrink to the size of the
2334  table to emulate words behaviour closer.
2335  */
2336  if (bTableJoin)
2337  {
2338  const SwNodeIndex* pNodeIndex = pFlyFormat->GetContent().
2339  GetContentIdx();
2340  if (pNodeIndex)
2341  {
2342  SwNodeIndex aIdx( *pNodeIndex, 1 ),
2343  aEnd( *pNodeIndex->GetNode().EndOfSectionNode() );
2344 
2345  if (aIdx < aEnd)
2346  {
2347  if(aIdx.GetNode().IsTableNode())
2348  {
2349  SwTableNode *pTable = aIdx.GetNode().GetTableNode();
2350  aIdx = *aIdx.GetNode().EndOfSectionNode();
2351  ++aIdx;
2352  if ( (aIdx < aEnd) && aIdx.GetNode().IsTextNode() )
2353  {
2354  SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2355  ++aIdx;
2356  if (aIdx == aEnd && pNd && pNd->GetText().isEmpty())
2357  {
2358  //An extra pre-created by writer unused paragraph
2359 
2360  //delete after import is complete rather than now
2361  //to avoid the complication of managing uncommitted
2362  //ctrlstack properties that refer to it.
2364 
2365  SwTable& rTable = pTable->GetTable();
2366  SwFrameFormat* pTableFormat = rTable.GetFrameFormat();
2367 
2368  if (pTableFormat)
2369  {
2370  SwFormatFrameSize aSize = pTableFormat->GetFrameSize();
2372  aSize.SetHeight(MINLAY);
2373  pFlyFormat->SetFormatAttr(aSize);
2374  SwFormatHoriOrient aHori = pTableFormat->GetHoriOrient();
2375  // passing the table orientation of
2376  // LEFT_AND_WIDTH to the frame seems to
2377  // work better than FULL, especially if the
2378  // table width exceeds the page width, however
2379  // I am not brave enough to set it in all
2380  // instances
2381  pTableFormat->SetFormatAttr( SwFormatHoriOrient(0, ( aHori.GetHoriOrient() == text::HoriOrientation::LEFT_AND_WIDTH ) ? ::text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::FULL ) );
2382  nRetWidth = aSize.GetWidth();
2383  }
2384  }
2385  }
2386  }
2387  }
2388  }
2389  }
2390 
2391  *m_pPaM->GetPoint() = rPos;
2392  aDup.Insert(*m_pPaM->GetPoint());
2393  return nRetWidth;
2394 }
2395 
2396 std::unique_ptr<WW8FlyPara> SwWW8ImplReader::ConstructApo(const ApoTestResults &rApo,
2397  const WW8_TablePos *pTabPos)
2398 {
2399  OSL_ENSURE(rApo.HasFrame() || pTabPos,
2400  "If no frame found, *MUST* be in a table");
2401 
2402  std::unique_ptr<WW8FlyPara> pRet(new WW8FlyPara(m_bVer67, rApo.mpStyleApo));
2403 
2404  // find APO parameter and test for bGrafApo
2405  if (rApo.HasFrame())
2406  pRet->ReadFull(rApo.m_nSprm29, this);
2407 
2408  pRet->ApplyTabPos(pTabPos);
2409 
2410  if (pRet->IsEmpty())
2411  {
2412  pRet.reset();
2413  }
2414  return pRet;
2415 }
2416 
2418 {
2419  // Find the DCS (Drop Cap Specifier) for the paragraph
2420  // if does not exist or if the first three bits are 0
2421  // then there is no dropcap on the paragraph
2422  WW8PLCFx_Cp_FKP *pPap = m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr;
2423  if (pPap)
2424  {
2425  SprmResult aDCS;
2426  if (m_bVer67)
2427  aDCS = pPap->HasSprm(NS_sprm::v6::sprmPDcs);
2428  else
2429  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PDcs::val);
2430  if (aDCS.pSprm && aDCS.nRemainingData >= 2)
2431  {
2432  /*
2433  fdct short :3 0007 drop cap type
2434  0 no drop cap
2435  1 normal drop cap
2436  2 drop cap in margin
2437  */
2438  short nDCS = SVBT16ToUInt16(aDCS.pSprm);
2439  if (nDCS & 7)
2440  return true;
2441  }
2442  }
2443  return false;
2444 }
2445 
2446 bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *pTabPos)
2447 {
2448  m_xWFlyPara = ConstructApo(rApo, pTabPos);
2449  if (!m_xWFlyPara)
2450  return false;
2451 
2452  // <WW8SwFlyPara> constructor has changed - new 4th parameter
2453  // containing WW8 page top margin.
2454  m_xSFlyPara.reset(new WW8SwFlyPara( *m_pPaM, *this, *m_xWFlyPara,
2458 
2459  // If this paragraph is a Dropcap set the flag and we will deal with it later
2460  if (IsDropCap())
2461  {
2462  m_bDropCap = true;
2464  return false;
2465  }
2466 
2467  if (!m_xWFlyPara->bGrafApo)
2468  {
2469 
2470  // Within the GrafApo text attributes have to be ignored, because
2471  // they would apply to the following lines. The frame is only inserted
2472  // if it is not merely positioning a single image. If it is an image
2473  // frame, pWFlyPara and pSFlyPara are retained and the resulting
2474  // attributes applied to the image when inserting the image.
2475 
2476  WW8FlySet aFlySet(*this, m_xWFlyPara.get(), m_xSFlyPara.get(), false);
2477 
2478  if (pTabPos && pTabPos->bNoFly)
2479  {
2480  m_xSFlyPara->pFlyFormat = nullptr;
2481  }
2482  else
2483  {
2484  // ofz#34749 we shouldn't anchor anything into an 'extra' paragraph scheduled for
2485  // removal at end of import, but check if that scenario is happening
2488  m_pPaM->GetPoint(), &aFlySet);
2489  OSL_ENSURE(m_xSFlyPara->pFlyFormat->GetAnchor().GetAnchorId() ==
2490  WW8SwFlyPara::eAnchor, "Not the anchor type requested!");
2491  }
2492 
2493  if (m_xSFlyPara->pFlyFormat)
2494  {
2495  if (!m_pDrawModel)
2496  GraphicCtor();
2497 
2498  SdrObject* pOurNewObject = CreateContactObject(m_xSFlyPara->pFlyFormat);
2499  m_xWWZOrder->InsertTextLayerObject(pOurNewObject);
2500  }
2501 
2502  if (RndStdIds::FLY_AS_CHAR != WW8SwFlyPara::eAnchor && m_xSFlyPara->pFlyFormat)
2503  {
2504  m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), m_xSFlyPara->pFlyFormat);
2505  }
2506 
2507  // remember Pos in body text
2508  m_xSFlyPara->xMainTextPos.reset(new SwPosition(*m_pPaM->GetPoint()));
2509 
2510  //remove fltanchors, otherwise they will be closed inside the
2511  //frame, which makes no sense, restore them after the frame is
2512  //closed
2513  m_xSFlyPara->xOldAnchorStck = std::move(m_xAnchorStck);
2515 
2516  if (m_xSFlyPara->pFlyFormat)
2517  MoveInsideFly(m_xSFlyPara->pFlyFormat);
2518 
2519  // 1) ReadText() is not called recursively because the length of
2520  // the Apo is unknown at that time, and ReadText() needs it.
2521  // 2) the CtrlStck is not re-created.
2522  // the Char attributes continue (trouble with Sw-attributes)
2523  // Para attributes must be reset at the end of every paragraph,
2524  // i.e. at the end of a paragraph there must not be para attributes
2525  // on the stack
2526  }
2527  return true;
2528 }
2529 
2530 void wwSectionManager::JoinNode(const SwPosition &rPos, const SwNode &rNode)
2531 {
2532  if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2533  maSegments.back().maStart.Assign(rNode);
2534 }
2535 
2536 bool SwWW8ImplReader::JoinNode(SwPaM &rPam, bool bStealAttr)
2537 {
2538  bool bRet = false;
2539  rPam.GetPoint()->nContent = 0; // go to start of paragraph
2540 
2541  SwNodeIndex aPref(rPam.GetPoint()->nNode, -1);
2542 
2543  if (SwTextNode* pNode = aPref.GetNode().GetTextNode())
2544  {
2545  m_aSectionManager.JoinNode(*rPam.GetPoint(), aPref.GetNode());
2546  rPam.GetPoint()->nNode = aPref;
2547  rPam.GetPoint()->nContent.Assign(pNode, pNode->GetText().getLength());
2548  if (bStealAttr)
2549  m_xCtrlStck->StealAttr(rPam.GetPoint()->nNode);
2550 
2551  if (m_pLastAnchorPos || m_pPreviousNode || (m_xSFlyPara && m_xSFlyPara->xMainTextPos))
2552  {
2553  SwNodeIndex aToBeJoined(aPref, 1);
2554 
2555  if (m_pLastAnchorPos)
2556  {
2557  //If the last anchor pos is here, then clear the anchor pos.
2558  //This "last anchor pos" is only used for fixing up the
2559  //positions of things anchored to page breaks and here
2560  //we are removing the last paragraph of a frame, so there
2561  //cannot be a page break at this point so we can
2562  //safely reset m_pLastAnchorPos to avoid any dangling
2563  //SwIndex's pointing into the deleted paragraph
2564  SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2565  if (aLastAnchorPos == aToBeJoined)
2566  m_pLastAnchorPos.reset();
2567  }
2568 
2569  if (m_pPreviousNode)
2570  {
2571  //If the drop character start pos is here, then clear it.
2572  SwNodeIndex aDropCharPos(*m_pPreviousNode);
2573  if (aDropCharPos == aToBeJoined)
2574  m_pPreviousNode = nullptr;
2575  }
2576 
2577  if (m_xSFlyPara && m_xSFlyPara->xMainTextPos)
2578  {
2579  // If an open apo pos is here, then clear it before
2580  // JoinNext destroys it
2581  SwNodeIndex aOpenApoPos(m_xSFlyPara->xMainTextPos->nNode);
2582  if (aOpenApoPos == aToBeJoined)
2583  m_xSFlyPara->xMainTextPos.reset();
2584  }
2585  }
2586 
2587  pNode->JoinNext();
2588 
2589  bRet = true;
2590  }
2591  return bRet;
2592 }
2593 
2594 //In auto-width word frames negative after-indent values are ignored
2596 {
2597  const SwNodeIndex* pSttNd = pFlyFormat->GetContent().GetContentIdx();
2598  if (!pSttNd)
2599  return;
2600 
2601  SwNodeIndex aIdx(*pSttNd, 1);
2602  SwNodeIndex aEnd(*pSttNd->GetNode().EndOfSectionNode());
2603  while (aIdx < aEnd)
2604  {
2605  SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2606  if (pNd)
2607  {
2608  const SvxLRSpaceItem& rLR = ItemGet<SvxLRSpaceItem>(*pNd, RES_LR_SPACE);
2609  if (rLR.GetRight() < 0)
2610  {
2611  SvxLRSpaceItem aLR(rLR);
2612  aLR.SetRight(0);
2613  pNd->SetAttr(aLR);
2614  }
2615  }
2616  ++aIdx;
2617  }
2618 }
2619 
2621 {
2622  OSL_ENSURE(m_xWFlyPara, "no pWFlyPara to close");
2623  if (!m_xWFlyPara)
2624  return;
2625  if (m_xWFlyPara->bGrafApo)
2626  {
2627  // image frame that has not been inserted: delete empty paragraph + attr
2628  JoinNode(*m_pPaM, true);
2629 
2630  }
2631  else
2632  {
2633  if (!m_xSFlyPara->xMainTextPos)
2634  {
2635  OSL_ENSURE(m_xSFlyPara->xMainTextPos, "StopApo: xMainTextPos is nullptr");
2636  return;
2637  }
2638 
2639  /*
2640  What we are doing with this temporary nodeindex is as follows: The
2641  stack of attributes normally only places them into the document when
2642  the current insertion point has passed them by. Otherwise the end
2643  point of the attribute gets pushed along with the insertion point. The
2644  insertion point is moved and the properties committed during
2645  MoveOutsideFly. We also may want to remove the final paragraph in the
2646  frame, but we need to wait until the properties for that frame text
2647  have been committed otherwise they will be lost. So we first get a
2648  handle to the last the filter inserted. After the attributes are
2649  committed, if that paragraph exists we join it with the para after it
2650  that comes with the frame by default so that as normal we don't end up
2651  with one more paragraph than we wanted.
2652  */
2653  SwNodeIndex aPref(m_pPaM->GetPoint()->nNode, -1);
2654 
2655  SwTwips nNewWidth =
2656  MoveOutsideFly(m_xSFlyPara->pFlyFormat, *m_xSFlyPara->xMainTextPos);
2657  if (nNewWidth)
2658  m_xSFlyPara->BoxUpWidth(nNewWidth);
2659 
2660  Color aBg(ColorTransparency, 0xFE, 0xFF, 0xFF, 0xFF); //Transparent by default
2661 
2662  SwTextNode* pNd = aPref.GetNode().GetTextNode();
2663  SwTextNode* pJoinNext = nullptr;
2664  if (pNd && m_xSFlyPara->pFlyFormat)
2665  {
2666  /*
2667  #i582#
2668  Take the last paragraph background colour and fill the frame with
2669  it. Otherwise, make it transparent, this appears to be how MSWord
2670  works
2671  */
2672  const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_BACKGROUND);
2673  const SvxBrushItem &rBrush = static_cast<const SvxBrushItem&>(rItm);
2674  if (rBrush.GetColor() != COL_AUTO)
2675  aBg = rBrush.GetColor();
2676 
2677  if (m_pLastAnchorPos)
2678  {
2679  //If the last anchor pos is here, then clear the anchor pos.
2680  //This "last anchor pos" is only used for fixing up the
2681  //positions of things anchored to page breaks and here
2682  //we are removing the last paragraph of a frame, so there
2683  //cannot be a page break at this point so we can
2684  //safely reset m_pLastAnchorPos to avoid any dangling
2685  //SwIndex's pointing into the deleted paragraph
2686  SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2687  SwNodeIndex aToBeJoined(aPref, 1);
2688  if (aLastAnchorPos == aToBeJoined)
2689  m_pLastAnchorPos.reset();
2690  }
2691 
2692  //Get rid of extra empty paragraph
2693  pJoinNext = pNd;
2694  }
2695 
2696  if (m_xSFlyPara->pFlyFormat)
2697  m_xSFlyPara->pFlyFormat->SetFormatAttr(SvxBrushItem(aBg, RES_BACKGROUND));
2698 
2700  if (pJoinNext)
2701  pJoinNext->JoinNext();
2702 
2703  m_xAnchorStck = std::move(m_xSFlyPara->xOldAnchorStck);
2704 
2705  // When inserting a graphic into the fly frame using the auto
2706  // function, the extension of the SW-fly has to be set
2707  // manually as the SW fly has no auto function to adjust the
2708  // frameĀ“s size.
2709  if (m_xSFlyPara->nNewNetWidth > MINFLY && m_xSFlyPara->pFlyFormat) // BoxUpWidth ?
2710  {
2711  tools::Long nW = m_xSFlyPara->nNewNetWidth;
2712  nW += m_xSFlyPara->nWidth - m_xSFlyPara->nNetWidth; // border for it
2713  m_xSFlyPara->pFlyFormat->SetFormatAttr(
2714  SwFormatFrameSize(m_xSFlyPara->eHeightFix, nW, m_xSFlyPara->nHeight));
2715  }
2716  /*
2717  Word set *no* width meaning it's an automatic width. The
2718  SwFlyPara reader will have already set a fallback width of the
2719  printable regions width, so we should reuse it. Despite the related
2720  problems with layout addressed with a hack in WW8FlyPara's constructor
2721  #i27204# Added AutoWidth setting. Left the old CalculateFlySize in place
2722  so that if the user unselects autowidth, the width doesn't max out
2723  */
2724  else if (!m_xWFlyPara->nSp28 && m_xSFlyPara->pFlyFormat)
2725  {
2726  using namespace sw::util;
2727  SfxItemSet aFlySet( m_xSFlyPara->pFlyFormat->GetAttrSet() );
2728 
2729  SwFormatFrameSize aSize(ItemGet<SwFormatFrameSize>(aFlySet, RES_FRM_SIZE));
2730 
2731  aFlySet.ClearItem(RES_FRM_SIZE);
2732 
2733  if (!m_bFuzzing)
2734  {
2735  CalculateFlySize(aFlySet, m_xSFlyPara->xMainTextPos->nNode,
2736  m_xSFlyPara->nWidth);
2737  }
2738 
2739  nNewWidth = ItemGet<SwFormatFrameSize>(aFlySet, RES_FRM_SIZE).GetWidth();
2740 
2741  aSize.SetWidth(nNewWidth);
2742  aSize.SetWidthSizeType(SwFrameSize::Variable);
2743 
2744  m_xSFlyPara->pFlyFormat->SetFormatAttr(aSize);
2745  }
2746 
2747  m_xSFlyPara->xMainTextPos.reset();
2748 // To create the SwFrames when inserting into an existing document, fltshell.cxx
2749 // will call pFlyFrame->MakeFrames() when setting the FltAnchor attribute
2750 
2751  }
2752 
2753  //#i8062#
2754  if (m_xSFlyPara && m_xSFlyPara->pFlyFormat)
2756 
2757  m_xSFlyPara.reset();
2758  m_xWFlyPara.reset();
2759 }
2760 
2761 // TestSameApo() returns if it's the same Apo or a different one
2763  const WW8_TablePos *pTabPos)
2764 {
2765  if (!m_xWFlyPara)
2766  {
2767  OSL_ENSURE(m_xWFlyPara, " Where is my pWFlyPara ? ");
2768  return true;
2769  }
2770 
2771  // We need to a full comparison (excepting borders) to identify all
2772  // combinations style/hard correctly. For this reason we create a
2773  // temporary WW8FlyPara (depending on if style or not), apply the
2774  // hard attributes and then compare.
2775 
2776  // For comparison
2777  WW8FlyPara aF(m_bVer67, rApo.mpStyleApo);
2778  // WWPara for current para
2779  if (rApo.HasFrame())
2780  aF.Read(rApo.m_nSprm29, m_xPlcxMan->GetPapPLCF());
2781  aF.ApplyTabPos(pTabPos);
2782 
2783  return aF == *m_xWFlyPara;
2784 }
2785 
2787  const bool bFirstLineOfStSet,
2788  const bool bLeftIndentSet )
2789 {
2790  if( m_bNoAttrImport ) // for ignoring styles during doc inserts
2791  return;
2792 
2793  if (m_pCurrentColl)
2794  {
2795  OSL_ENSURE(rAttr.Which() != RES_FLTR_REDLINE, "redline in style!");
2796  m_pCurrentColl->SetFormatAttr(rAttr);
2797  }
2798  else if (m_xCurrentItemSet)
2799  {
2800  m_xCurrentItemSet->Put(rAttr);
2801  }
2802  else if (rAttr.Which() == RES_FLTR_REDLINE)
2803  {
2804  m_xRedlineStack->open(*m_pPaM->GetPoint(), rAttr);
2805  }
2806  else
2807  {
2808  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), rAttr);
2809  // #i103711#
2810  if ( bFirstLineOfStSet )
2811  {
2812  const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2814  }
2815  // #i105414#
2816  if ( bLeftIndentSet )
2817  {
2818  const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2820  }
2821  }
2822 
2824  m_pPostProcessAttrsInfo->mItemSet.Put(rAttr);
2825 }
2826 
2827 // fetches attribute from FormatColl / Stack / Doc
2828 const SfxPoolItem* SwWW8ImplReader::GetFormatAttr( sal_uInt16 nWhich )
2829 {
2830  const SfxPoolItem* pRet = nullptr;
2831  if (m_pCurrentColl)
2832  pRet = &(m_pCurrentColl->GetFormatAttr(nWhich));
2833  else if (m_xCurrentItemSet)
2834  {
2835  pRet = m_xCurrentItemSet->GetItem(nWhich);
2836  if (!pRet)
2837  pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2838  if (!pRet)
2839  pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2840  }
2841  else if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2842  {
2843  pRet = m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), nWhich);
2844  if (!pRet)
2845  {
2846  if (m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_pFormat &&
2847  m_vColl[m_nCurrentColl].m_bColl)
2848  {
2849  pRet = &(m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(nWhich));
2850  }
2851  }
2852  if (!pRet)
2853  pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2854  if (!pRet)
2855  pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2856  }
2857  else
2858  pRet = m_xCtrlStck->GetFormatAttr(*m_pPaM->GetPoint(), nWhich);
2859  return pRet;
2860 }
2861 
2862 // The methods get as parameters the token id and the length of the following
2863 // parameters according to the table in WWScan.cxx.
2864 void SwWW8ImplReader::Read_Special(sal_uInt16, const sal_uInt8* pData, short nLen)
2865 {
2866  if (nLen < 1)
2867  {
2868  m_bSpec = false;
2869  return;
2870  }
2871  m_bSpec = ( *pData != 0 );
2872 }
2873 
2874 // Read_Obj is used for fObj and for fOle2 !
2875 void SwWW8ImplReader::Read_Obj(sal_uInt16 , const sal_uInt8* pData, short nLen)
2876 {
2877  if (nLen < 1)
2878  m_bObj = false;
2879  else
2880  {
2881  m_bObj = 0 != *pData;
2882 
2883  if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2884  {
2885  if (!m_aFieldStack.empty() && m_aFieldStack.back().mnFieldId == 56)
2886  {
2887  // For LINK fields, store the nObjLocFc value in the field entry
2888  m_aFieldStack.back().mnObjLocFc = m_nPicLocFc;
2889  }
2890  else
2891  {
2893  }
2894  }
2895  }
2896 }
2897 
2898 void SwWW8ImplReader::Read_PicLoc(sal_uInt16 , const sal_uInt8* pData, short nLen )
2899 {
2900  if (nLen < 4)
2901  {
2902  m_nPicLocFc = 0;
2903  m_bSpec = false; // Is this always correct?
2904  }
2905  else
2906  {
2907  m_nPicLocFc = SVBT32ToUInt32( pData );
2908  m_bSpec = true;
2909 
2910  if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2912  }
2913 }
2914 
2915 void SwWW8ImplReader::Read_POutLvl(sal_uInt16, const sal_uInt8* pData, short nLen )
2916 {
2917  if (nLen < 0)
2918  {
2920  return;
2921  }
2922 
2923  if (m_pCurrentColl != nullptr)
2924  {
2926  if (pSI && pSI->m_bColl && pSI->m_pFormat)
2927  {
2928  pSI->mnWW8OutlineLevel =
2929  static_cast< sal_uInt8 >( ( (pData && nLen >= 1) ? *pData : 0 ) );
2931  if (nLevel == 0)
2932  {
2933  SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pSI->m_pFormat);
2934  pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
2935  }
2937  }
2938  }
2939  else if (m_pPaM != nullptr)
2940  {
2941  const sal_uInt8 nOutlineLevel
2943  static_cast<sal_uInt8>(((pData && nLen >= 1) ? *pData : 0)));
2945  }
2946 }
2947 
2948 void SwWW8ImplReader::Read_Symbol(sal_uInt16, const sal_uInt8* pData, short nLen )
2949 {
2950  if( m_bIgnoreText )
2951  return;
2952 
2953  if (nLen < (m_bVer67 ? 3 : 4))
2954  {
2955  //otherwise disable after we print the char
2956  if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2957  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
2958  m_bSymbol = false;
2959  }
2960  else
2961  {
2962  // Make new Font-Attribute
2963  // (will be closed in SwWW8ImplReader::ReadChars() )
2964 
2965  //Will not be added to the charencoding stack, for styles the real
2966  //font setting will be put in as the styles charset, and for plain
2967  //text encoding for symbols is moot. Drawing boxes will check bSymbol
2968  //themselves so they don't need to add it to the stack either.
2969  if (SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_FONT))
2970  {
2971  SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CJK_FONT);
2972  SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CTL_FONT);
2973  if( m_bVer67 )
2974  {
2975  //convert single byte from MS1252 to Unicode
2976  m_cSymbol = OUString(
2977  reinterpret_cast<const char*>(pData+2), 1,
2978  RTL_TEXTENCODING_MS_1252).toChar();
2979  }
2980  else
2981  {
2982  //already is Unicode
2983  m_cSymbol = SVBT16ToUInt16( pData+2 );
2984  }
2985  m_bSymbol = true;
2986  }
2987  }
2988 }
2989 
2990 SwWW8StyInf *SwWW8ImplReader::GetStyle(sal_uInt16 nColl) const
2991 {
2992  return const_cast<SwWW8StyInf *>(nColl < m_vColl.size() ? &m_vColl[nColl] : nullptr);
2993 }
2994 
2995 // Read_BoldUsw for italic, bold, small caps, majuscule, struck out,
2996 // contour and shadow
2997 void SwWW8ImplReader::Read_BoldUsw( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
2998 {
2999  const int nContiguousWestern = 8;
3000  const int nWestern = nContiguousWestern + 1;
3001  const int nEastern = 2;
3002  const int nCTL = 2;
3003  const int nIds = nWestern + nEastern + nCTL;
3004  static const sal_uInt16 nEndIds[ nIds ] =
3005  {
3010 
3012 
3014 
3016  };
3017 
3018  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3019 
3020  sal_uInt8 nI;
3021  // the attribute number for "double strike-through" breaks rank
3022  if (NS_sprm::CFDStrike::val == nId)
3023  nI = nContiguousWestern; // The out of sequence western id
3024  else
3025  {
3026  // The contiguous western ids
3027  if (eVersion <= ww::eWW2)
3028  nI = static_cast< sal_uInt8 >(nId - 60);
3029  else if (eVersion < ww::eWW8)
3030  nI = static_cast< sal_uInt8 >(nId - NS_sprm::v6::sprmCFBold);
3031  else
3032  nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBold::val);
3033  }
3034 
3035  sal_uInt16 nMask = 1 << nI;
3036 
3037  if (nLen < 1)
3038  {
3039  if (nI < 2)
3040  {
3041  if (eVersion <= ww::eWW6)
3042  {
3043  // reset the CTL Weight and Posture, because they are the same as their
3044  // western equivalents in ww6
3045  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nEastern + nI ] );
3046  }
3047  // reset the CJK Weight and Posture, because they are the same as their
3048  // western equivalents in word
3049  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nI ] );
3050  }
3051  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nI ] );
3052  m_xCtrlStck->SetToggleAttr(nI, false);
3053  return;
3054  }
3055  // value: 0 = off, 1 = on, 128 = like style, 129 contrary to style
3056  bool bOn = *pData & 1;
3058  if (m_xPlcxMan && eVersion > ww::eWW2)
3059  {
3060  SprmResult aCharIstd =
3061  m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3062  if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3063  pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3064  }
3065 
3066  if( m_pCurrentColl ) // StyleDef -> remember flags
3067  {
3068  if (pSI)
3069  {
3070  // The style based on has Bit 7 set ?
3071  if (
3072  pSI->m_nBase < m_vColl.size() && (*pData & 0x80) &&
3073  (m_vColl[pSI->m_nBase].m_n81Flags & nMask)
3074  )
3075  {
3076  bOn = !bOn; // invert
3077  }
3078 
3079  if (bOn)
3080  pSI->m_n81Flags |= nMask; // set flag
3081  else
3082  pSI->m_n81Flags &= ~nMask; // delete flag
3083  }
3084  }
3085  else
3086  {
3087 
3088  // in text -> look at flags
3089  if( *pData & 0x80 ) // bit 7 set?
3090  {
3091  if (pSI && pSI->m_n81Flags & nMask) // and in StyleDef at ?
3092  bOn = !bOn; // then invert
3093  // remember on stack that this is a toggle-attribute
3094  m_xCtrlStck->SetToggleAttr(nI, true);
3095  }
3096  }
3097 
3098  SetToggleAttr( nI, bOn );
3099 }
3100 
3101 void SwWW8ImplReader::Read_Bidi(sal_uInt16, const sal_uInt8* pData, short nLen)
3102 {
3103  if (nLen < 1) //Property end
3104  {
3105  m_bBidi = false;
3107  }
3108  else //Property start
3109  {
3110  m_bBidi = true;
3111  sal_uInt8 nBidi = *pData;
3112  NewAttr( SfxInt16Item( RES_CHRATR_BIDIRTL, (nBidi!=0)? 1 : 0 ) );
3113  }
3114 }
3115 
3116 /*
3117  tdf#91916, #i8726, #i42685# there is an ambiguity
3118  around certain properties as to what they mean,
3119  which appears to be a problem with different versions
3120  of the file format where properties conflict, i.e.
3121 
3122 ooo40606-2.doc, magic is a699
3123  : 0x6f 0x4 0x0 0x71 0x4 0x0
3124 ooo40635-1.doc, magic is a699
3125  : 0x6f 0x4 0x0 0x71 0x4 0x0
3126 ooo31093/SIMPCHIN.doc, magic is a699
3127  : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3128  : 0x6f 0x5 0x0 0x70 0x5 0x0
3129 ooo31093/TRADCHIN.doc, magic is a699
3130  : 0x6f 0x1 0x0 0x70 0x0 0x0 0x71 0x1 0x0
3131 ooo31093/JAPANESE.doc, magic is a697
3132  : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3133 ooo31093/KOREAN.doc, magic is a698
3134  : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3135 ooo31093-1.doc, magic is a698
3136  : 0x6f 0x5 0x0 0x70 0x5 0x0
3137 ooo31093-1.doc, magic is a698
3138  : 0x6f 0x5 0x0 0x70 0x5 0x0
3139 
3140 meanwhile...
3141 
3142 ooo27954-1.doc, magic is a5dc
3143  : 0x6f 0x1 0x81 0x71 0x2 0x4 0x0 0x74 0x2 0x20 0x0
3144 
3145 ooo33251-1.doc, magic is a5dc
3146  : 0x6f 0x1 0x81 0x71 0x2 0x3 0x0 0x74 0x2 0x1c 0x0
3147 
3148 ---
3149 
3150 So we have the same sprm values, but different payloads, where
3151 the a5dc versions appear to use a len argument, followed by len
3152 bytes, while the a698<->a699 versions use a 2byte argument
3153 
3154 commit c2213db9ed70c1fd546482d22e36e4029c10aa45
3155 
3156  INTEGRATION: CWS tl28 (1.169.24); FILE MERGED
3157  2006/10/25 13:40:41 tl 1.169.24.2: RESYNC: (1.169-1.170); FILE MERGED
3158  2006/09/20 11:55:50 hbrinkm 1.169.24.1: #i42685# applied patch
3159 
3160 changed 0x6f and 0x70 from Read_BoldBiDiUsw to Read_FontCode for all versions.
3161 
3162 In the Word for Window 2 spec we have...
3163  78 //sprmCMajority
3164  80 //sprmCFBoldBi
3165  81 //sprmCFItalicBi
3166  82 //sprmCFtcBi
3167  83 //sprmClidBi
3168  84 //sprmCIcoBi
3169  85 //sprmCHpsBi
3170 as see in GetWW2SprmDispatcher, different numbers, but the sequence starts with
3171 the same sprmCMajority as appears before 0x6f in word 6/95
3172 
3173 I think the easiest explanation is that the CJK Word for Window 95, or whatever
3174 the product was went rogue, and did their own things with at least first three
3175 slots after sprmCMajority to do a different thing. I have no reason to think Tono
3176 was wrong with what they do in the a698<->a699 versions, but with magic
3177 a5dc they probably did mean sprmCFBoldBi, sprmCFItalicBi cause they have that 0x81
3178 pattern which has significance for those types of properties.
3179 */
3180 void SwWW8ImplReader::Read_AmbiguousSPRM(sal_uInt16 nId, const sal_uInt8* pData,
3181  short nLen)
3182 {
3183  if (m_xWwFib->m_wIdent >= 0xa697 && m_xWwFib->m_wIdent <= 0xa699)
3184  {
3185  Read_FontCode(nId, pData, nLen);
3186  }
3187  else
3188  {
3189  Read_BoldBiDiUsw(nId, pData, nLen);
3190  }
3191 }
3192 
3193 // Read_BoldUsw for BiDi Italic, Bold
3194 void SwWW8ImplReader::Read_BoldBiDiUsw(sal_uInt16 nId, const sal_uInt8* pData,
3195  short nLen)
3196 {
3197  static const sal_uInt16 nEndIds[2] =
3198  {
3200  };
3201 
3202  sal_uInt8 nI;
3203  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3204  if (eVersion <= ww::eWW2)
3205  nI = static_cast< sal_uInt8 >(nId - 80);
3206  else if (eVersion < ww::eWW8)
3207  nI = static_cast< sal_uInt8 >(nId - 111);
3208  else
3209  nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBoldBi::val);
3210 
3211  OSL_ENSURE(nI <= 1, "not happening");
3212  if (nI > 1)
3213  return;
3214 
3215  sal_uInt16 nMask = 1 << nI;
3216 
3217  if (nLen < 1)
3218  {
3219  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),nEndIds[nI]);
3220  m_xCtrlStck->SetToggleBiDiAttr(nI, false);
3221  return;
3222  }
3223  bool bOn = *pData & 1;
3225  if (m_xPlcxMan)
3226  {
3227  SprmResult aCharIstd =
3228  m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3229  if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3230  pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3231  }
3232 
3233  if (m_pCurrentColl && eVersion > ww::eWW2) // StyleDef -> remember flags
3234  {
3235  if (pSI)
3236  {
3237  if( pSI->m_nBase < m_vColl.size() // Style Based on
3238  && ( *pData & 0x80 ) // bit 7 set?
3239  && ( m_vColl[pSI->m_nBase].m_n81BiDiFlags & nMask ) ) // base mask?
3240  bOn = !bOn; // invert
3241 
3242  if( bOn )
3243  pSI->m_n81BiDiFlags |= nMask; // set flag
3244  else
3245  pSI->m_n81BiDiFlags &= ~nMask; // delete flag
3246  }
3247  }
3248  else
3249  {
3250 
3251  // in text -> look at flags
3252  if (*pData & 0x80) // Bit 7 set?
3253  {
3254  if (pSI && pSI->m_n81BiDiFlags & nMask) // and in StyleDef at ?
3255  bOn = !bOn; // then invert
3256  // remember on stack that this is a toggle-attribute
3257  m_xCtrlStck->SetToggleBiDiAttr(nI, true);
3258  }
3259  }
3260 
3261  SetToggleBiDiAttr(nI, bOn);
3262 }
3263 
3265 {
3266  switch (nAttrId)
3267  {
3268  case 0:
3269  {
3271  aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3272  NewAttr( aAttr );
3273  }
3274  break;
3275  case 1:
3276  {
3278  aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3279  NewAttr( aAttr );
3280  }
3281  break;
3282  default:
3283  OSL_ENSURE(false, "Unhandled unknown bidi toggle attribute");
3284  break;
3285 
3286  }
3287 }
3288 
3290 {
3291  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3292 
3293  switch (nAttrId)
3294  {
3295  case 0:
3296  {
3298  NewAttr( aAttr );
3299  aAttr.SetWhich( RES_CHRATR_CJK_WEIGHT );
3300  NewAttr( aAttr );
3301  if (eVersion <= ww::eWW6)
3302  {
3303  aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3304  NewAttr( aAttr );
3305  }
3306  }
3307  break;
3308  case 1:
3309  {
3311  NewAttr( aAttr );
3312  aAttr.SetWhich( RES_CHRATR_CJK_POSTURE );
3313  NewAttr( aAttr );
3314  if (eVersion <= ww::eWW6)
3315  {
3316  aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3317  NewAttr( aAttr );
3318  }
3319  }
3320  break;
3321  case 2:
3323  break;
3324  case 3:
3326  break;
3327  case 4:
3329  break;
3330  case 5:
3331  NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::SmallCaps
3332  : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3333  break;
3334  case 6:
3335  NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::Uppercase
3336  : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3337  break;
3338  case 7:
3340  break;
3341  case 8:
3343  : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ) );
3344  break;
3345  default:
3346  OSL_ENSURE(false, "Unhandled unknown toggle attribute");
3347  break;
3348  }
3349 }
3350 
3351 void SwWW8ImplReader::ChkToggleAttr_( sal_uInt16 nOldStyle81Mask,
3352  sal_uInt16 nNewStyle81Mask )
3353 {
3354  sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleAttrFlags();
3355  for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3356  {
3357  if (
3358  (i & nToggleAttrFlags) &&
3359  ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3360  )
3361  {
3362  SetToggleAttr(n, (i & nOldStyle81Mask));
3363  }
3364  }
3365 }
3366 
3367 void SwWW8ImplReader::ChkToggleBiDiAttr_( sal_uInt16 nOldStyle81Mask,
3368  sal_uInt16 nNewStyle81Mask )
3369 {
3370  sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleBiDiAttrFlags();
3371  for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3372  {
3373  if (
3374  (i & nToggleAttrFlags) &&
3375  ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3376  )
3377  {
3378  SetToggleBiDiAttr(n, (i & nOldStyle81Mask));
3379  }
3380  }
3381 }
3382 
3383 void SwWW8ImplReader::Read_SubSuper( sal_uInt16, const sal_uInt8* pData, short nLen )
3384 {
3385  if (nLen < 1)
3386  {
3388  return;
3389  }
3390 
3391  short nEs;
3392  sal_uInt8 nProp;
3393  switch( *pData )
3394  {
3395  case 1:
3396  nEs = DFLT_ESC_AUTO_SUPER;
3397  nProp = DFLT_ESC_PROP;
3398  break;
3399  case 2:
3400  nEs = DFLT_ESC_AUTO_SUB;
3401  nProp = DFLT_ESC_PROP;
3402  break;
3403  default:
3404  nEs = 0;
3405  nProp = 100;
3406  break;
3407  }
3409 }
3410 
3412 {
3413  /*
3414  For inline graphics and objects word has a hacked in feature to use
3415  subscripting to force the graphic into a centered position on the line, so
3416  we must check when applying sub/super to see if it the subscript range
3417  contains only a single graphic, and if that graphic is anchored as
3418  RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3419  */
3420  SwFrameFormat *pRet=nullptr;
3421  SwNodeIndex aBegin(rRegion.Start()->nNode);
3422  const sal_Int32 nBegin(rRegion.Start()->nContent.GetIndex());
3423  SwNodeIndex aEnd(rRegion.End()->nNode);
3424  const sal_Int32 nEnd(rRegion.End()->nContent.GetIndex());
3425  const SwTextNode* pTNd;
3426  const SwTextAttr* pTFlyAttr;
3427  if (
3428  aBegin == aEnd && nBegin == nEnd - 1 &&
3429  nullptr != (pTNd = aBegin.GetNode().GetTextNode()) &&
3430  nullptr != (pTFlyAttr = pTNd->GetTextAttrForCharAt(nBegin, RES_TXTATR_FLYCNT))
3431  )
3432  {
3433  const SwFormatFlyCnt& rFly = pTFlyAttr->GetFlyCnt();
3434  SwFrameFormat *pFlyFormat = rFly.GetFrameFormat();
3435  if (pFlyFormat &&
3436  (RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()))
3437  {
3438  pRet = pFlyFormat;
3439  }
3440  }
3441  return pRet;
3442 }
3443 
3445 {
3446  /*
3447  For inline graphics and objects word has a hacked in feature to use
3448  subscripting to force the graphic into a centered position on the line, so
3449  we must check when applying sub/super to see if it the subscript range
3450  contains only a single graphic, and if that graphic is anchored as
3451  RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3452  */
3453  bool bIsGraphicPlacementHack = false;
3454  sal_uInt16 nPos;
3455  if (m_xCtrlStck->GetFormatStackAttr(RES_CHRATR_ESCAPEMENT, &nPos))
3456  {
3457  SwPaM aRegion(*m_pPaM->GetPoint());
3458 
3459  SwFltPosition aMkPos((*m_xCtrlStck)[nPos].m_aMkPos);
3460  SwFltPosition aPtPos(*m_pPaM->GetPoint());
3461 
3462  SwFrameFormat *pFlyFormat = nullptr;
3464  && nullptr != (pFlyFormat = ContainsSingleInlineGraphic(aRegion)))
3465  {
3466  m_xCtrlStck->DeleteAndDestroy(nPos);
3467  pFlyFormat->SetFormatAttr(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER, text::RelOrientation::CHAR));
3468  bIsGraphicPlacementHack = true;
3469  }
3470  }
3471  return bIsGraphicPlacementHack;
3472 }
3473 
3474 void SwWW8ImplReader::Read_SubSuperProp( sal_uInt16, const sal_uInt8* pData, short nLen )
3475 {
3476  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3477 
3478  if (nLen < (eVersion <= ww::eWW2 ? 1 : 2))
3479  {
3482  return;
3483  }
3484 
3485  // if the fontsize for these characters is specified, make sure it is updated first
3486  if ( m_xPlcxMan )
3487  {
3488  const sal_uInt16 nFontsizeID = m_bVer67 ? NS_sprm::v6::sprmCHps : NS_sprm::CHps::val;
3489  const SprmResult aFontsize = m_xPlcxMan->GetChpPLCF()->HasSprm( nFontsizeID, /*bFindFirst=*/false );
3490  if ( aFontsize.pSprm && aFontsize.nRemainingData )
3491  Read_FontSize(nFontsizeID, aFontsize.pSprm, aFontsize.nRemainingData);
3492  }
3493 
3494  // font position in HalfPoints
3495  short nPos = eVersion <= ww::eWW2 ? static_cast< sal_Int8 >( *pData ) : SVBT16ToInt16( pData );
3496  sal_Int32 nPos2 = nPos * ( 10 * 100 ); // HalfPoints in 100 * tw
3497  const SvxFontHeightItem* pF
3498  = static_cast<const SvxFontHeightItem*>(GetFormatAttr(RES_CHRATR_FONTSIZE));
3499  OSL_ENSURE(pF, "Expected to have the fontheight available here");
3500 
3501  // #i59022: Check ensure nHeight != 0. Div by zero otherwise.
3502  sal_Int32 nHeight = 240;
3503  if (pF != nullptr && pF->GetHeight() != 0)
3504  nHeight = pF->GetHeight();
3505  nPos2 /= nHeight; // ... now in % (rounded)
3506  if( nPos2 > MAX_ESC_POS )
3507  nPos2 = MAX_ESC_POS;
3508  if( nPos2 < -MAX_ESC_POS )
3509  nPos2 = -MAX_ESC_POS;
3510  SvxEscapementItem aEs( static_cast<short>(nPos2), 100, RES_CHRATR_ESCAPEMENT );
3511  NewAttr( aEs );
3512 }
3513 
3514 void SwWW8ImplReader::Read_Underline( sal_uInt16, const sal_uInt8* pData, short nLen )
3515 {
3516  FontLineStyle eUnderline = LINESTYLE_NONE;
3517  bool bWordLine = false;
3518  if (pData && nLen)
3519  {
3520  // Parameter: 0 = none, 1 = single, 2 = by Word,
3521  // 3 = double, 4 = dotted, 5 = hidden
3522  // 6 = thick, 7 = dash, 8 = dot(not used)
3523  // 9 = dotdash 10 = dotdotdash 11 = wave
3524  switch( *pData )
3525  {
3526  case 2: bWordLine = true;
3527  [[fallthrough]];
3528  case 1: eUnderline = LINESTYLE_SINGLE; break;
3529  case 3: eUnderline = LINESTYLE_DOUBLE; break;
3530  case 4: eUnderline = LINESTYLE_DOTTED; break;
3531  case 7: eUnderline = LINESTYLE_DASH; break;
3532  case 9: eUnderline = LINESTYLE_DASHDOT; break;
3533  case 10:eUnderline = LINESTYLE_DASHDOTDOT; break;
3534  case 6: eUnderline = LINESTYLE_BOLD; break;
3535  case 11:eUnderline = LINESTYLE_WAVE; break;
3536  case 20:eUnderline = LINESTYLE_BOLDDOTTED; break;
3537  case 23:eUnderline = LINESTYLE_BOLDDASH; break;
3538  case 39:eUnderline = LINESTYLE_LONGDASH; break;
3539  case 55:eUnderline = LINESTYLE_BOLDLONGDASH; break;
3540  case 25:eUnderline = LINESTYLE_BOLDDASHDOT; break;
3541  case 26:eUnderline = LINESTYLE_BOLDDASHDOTDOT;break;
3542  case 27:eUnderline = LINESTYLE_BOLDWAVE; break;
3543  case 43:eUnderline = LINESTYLE_DOUBLEWAVE; break;
3544  }
3545  }
3546 
3547  // if necessary, mix up stack and exit!
3548  if (nLen < 1)
3549  {
3552  }
3553  else
3554  {
3556  if( bWordLine )
3558  }
3559 }
3560 
3561 /*
3562 //The last three vary, measurements, rotation ? ?
3563 NoBracket 78 CA 06 - 02 00 00 02 34 52
3564 () 78 CA 06 - 02 01 00 02 34 52
3565 [] 78 CA 06 - 02 02 00 02 34 52
3566 <> 78 CA 06 - 02 03 00 02 34 52
3567 {} 78 CA 06 - 02 04 00 02 34 52
3568 */
3570  short nLen )
3571 {
3572  if (nLen < 0) // close the tag
3573  {
3575  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ROTATE );
3576  }
3577  else if( pData && 6 == nLen )
3578  {
3579  switch( *pData )
3580  {
3581  case 2: // double line
3582  {
3583  sal_Unicode cStt = 0, cEnd = 0;
3584  switch( SVBT16ToUInt16( pData+1 ) )
3585  {
3586  case 1: cStt = '('; cEnd = ')'; break;
3587  case 2: cStt = '['; cEnd = ']'; break;
3588  case 3: cStt = '<'; cEnd = '>'; break;
3589  case 4: cStt = '{'; cEnd = '}'; break;
3590  }
3591  NewAttr( SvxTwoLinesItem( true, cStt, cEnd, RES_CHRATR_TWO_LINES ));
3592  }
3593  break;
3594 
3595  case 1: // rotated characters
3596  {
3597  bool bFitToLine = 0 != *(pData+1);
3598  NewAttr( SvxCharRotateItem( 900_deg10, bFitToLine, RES_CHRATR_ROTATE ));
3599  }
3600  break;
3601  }
3602  }
3603 }
3604 
3605 void SwWW8ImplReader::Read_TextColor( sal_uInt16, const sal_uInt8* pData, short nLen )
3606 {
3607  //Has newer colour variant, ignore this old variant
3608  if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CCv::val).pSprm)
3609  return;
3610 
3611  if (nLen < 1)
3612  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3613  else
3614  {
3615  sal_uInt8 b = *pData; // parameter: 0 = Auto, 1..16 colors
3616 
3617  if( b > 16 ) // unknown -> Black
3618  b = 0;
3619 
3621  if (m_pCurrentColl && m_xStyles)
3622  m_xStyles->mbTextColChanged = true;
3623  }
3624 }
3625 
3626 void SwWW8ImplReader::Read_TextForeColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3627 {
3628  if (nLen < 4)
3629  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3630  else
3631  {
3632  Color aColor = msfilter::util::BGRToRGB(SVBT32ToUInt32(pData));
3633 
3634  // At least when transparency is 0xff and the color is black, Word renders that as black.
3635  if (aColor.IsTransparent() && aColor != COL_AUTO)
3636  {
3637  aColor.SetAlpha(255);
3638  }
3639 
3641  if (m_pCurrentColl && m_xStyles)
3642  m_xStyles->mbTextColChanged = true;
3643  }
3644 }
3645 
3646 void SwWW8ImplReader::Read_UnderlineColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3647 {
3648  if (nLen < 0)
3649  {
3650  //because the UnderlineColor is not a standalone attribute in SW, it belongs to the underline attribute.
3651  //And, the .doc file stores attributes separately, this attribute ends here, the "underline"
3652  //attribute also terminates (if the character next owns underline, that will be a new underline attribute).
3653  //so nothing is left to be done here.
3654  return;
3655  }
3656  else
3657  {
3658  if ( m_pCurrentColl ) //importing style
3659  {
3660  if( SfxItemState::SET == m_pCurrentColl->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3661  {
3662  if (nLen >= 4)
3663  {
3664  const SwAttrSet& aSet = m_pCurrentColl->GetAttrSet();
3665  std::unique_ptr<SvxUnderlineItem> pUnderline(aSet.Get(RES_CHRATR_UNDERLINE, false).Clone());
3666  pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3667  m_pCurrentColl->SetFormatAttr( *pUnderline );
3668  }
3669  }
3670  }
3671  else if (m_xCurrentItemSet)
3672  {
3673  if ( SfxItemState::SET == m_xCurrentItemSet->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3674  {
3675  if (nLen >= 4)
3676  {
3677  std::unique_ptr<SvxUnderlineItem> pUnderline(m_xCurrentItemSet->Get(RES_CHRATR_UNDERLINE, false).Clone());
3678  pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3679  m_xCurrentItemSet->Put( std::move(pUnderline) );
3680  }
3681  }
3682  }
3683  else
3684  {
3685  SvxUnderlineItem* pUnderlineAttr = const_cast<SvxUnderlineItem*>(static_cast<const SvxUnderlineItem*>(m_xCtrlStck->GetOpenStackAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE )));
3686  if (pUnderlineAttr && nLen >= 4)
3687  pUnderlineAttr->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32( pData ) ));
3688  }
3689  }
3690 }
3691 bool SwWW8ImplReader::GetFontParams( sal_uInt16 nFCode, FontFamily& reFamily,
3692  OUString& rName, FontPitch& rePitch, rtl_TextEncoding& reCharSet )
3693 {
3694  // the definitions that are the base for these tables are in windows.h
3695  static const FontPitch ePitchA[] =
3696  {
3698  };
3699 
3700  static const FontFamily eFamilyA[] =
3701  {
3704  };
3705 
3706  const WW8_FFN* pF = m_xFonts->GetFont( nFCode ); // Info for it
3707  if( !pF ) // font number unknown ?
3708  return false; // then ignore
3709 
3710  rName = pF->sFontname;
3711 
3712  // pF->prg : Pitch
3713  rePitch = ePitchA[pF->aFFNBase.prg];
3714 
3715  // pF->chs: Charset
3716  if( 77 == pF->aFFNBase.chs ) // Mac font in Mac Charset or
3717  reCharSet = m_eTextCharSet; // translated to ANSI charset
3718  else
3719  {
3720  // #i52786#, for word 67 we'll assume that ANSI is basically invalid,
3721  // might be true for (above) mac as well, but would need a mac example
3722  // that exercises this to be sure
3723  if (m_bVer67 && pF->aFFNBase.chs == 0)
3724  reCharSet = RTL_TEXTENCODING_DONTKNOW;
3725  else
3726  reCharSet = rtl_getTextEncodingFromWindowsCharset(pF->aFFNBase.chs);
3727  }
3728 
3729  // make sure Font Family Code is set correctly
3730  // at least for the most important fonts
3731  // ( might be set wrong when Doc was not created by
3732  // Winword but by third party program like Applixware... )
3733  if (rName.startsWithIgnoreAsciiCase("Tms Rmn") ||
3734  rName.startsWithIgnoreAsciiCase("Timmons") ||
3735  rName.startsWithIgnoreAsciiCase("CG Times") ||
3736  rName.startsWithIgnoreAsciiCase("MS Serif") ||
3737  rName.startsWithIgnoreAsciiCase("Garamond") ||
3738  rName.startsWithIgnoreAsciiCase("Times Roman") ||
3739  rName.startsWithIgnoreAsciiCase("Times New Roman"))
3740  {
3741  reFamily = FAMILY_ROMAN;
3742  }
3743  else if (rName.startsWithIgnoreAsciiCase("Helv") ||
3744  rName.startsWithIgnoreAsciiCase("Arial") ||
3745  rName.startsWithIgnoreAsciiCase("Univers") ||
3746  rName.startsWithIgnoreAsciiCase("LinePrinter") ||
3747  rName.startsWithIgnoreAsciiCase("Lucida Sans") ||
3748  rName.startsWithIgnoreAsciiCase("Small Fonts") ||
3749  rName.startsWithIgnoreAsciiCase("MS Sans Serif"))
3750  {
3751  reFamily = FAMILY_SWISS;
3752  }
3753  else
3754  {
3755  reFamily = eFamilyA[pF->aFFNBase.ff];
3756  }
3757 
3758  return true;
3759 }
3760 
3761 bool SwWW8ImplReader::SetNewFontAttr(sal_uInt16 nFCode, bool bSetEnums,
3762  sal_uInt16 nWhich)
3763 {
3764  FontFamily eFamily;
3765  OUString aName;
3766  FontPitch ePitch;
3767  rtl_TextEncoding eSrcCharSet;
3768 
3769  if( !GetFontParams( nFCode, eFamily, aName, ePitch, eSrcCharSet ) )
3770  {
3771  //If we fail (and are not doing a style) then put something into the
3772  //character encodings stack anyway so that the property end that pops
3773  //off the stack will keep in sync
3774  if (!m_pCurrentColl && IsListOrDropcap())
3775  {
3776  if (nWhich == RES_CHRATR_CJK_FONT)
3777  {
3778  if (!m_aFontSrcCJKCharSets.empty())
3779  {
3780  eSrcCharSet = m_aFontSrcCJKCharSets.top();
3781  }
3782  else
3783  {
3784  eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3785  }
3786 
3787  m_aFontSrcCJKCharSets.push(eSrcCharSet);
3788  }
3789  else
3790  {
3791  if (!m_aFontSrcCharSets.empty())
3792  {
3793  eSrcCharSet = m_aFontSrcCharSets.top();
3794  }
3795  else
3796  {
3797  eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3798  }
3799 
3800  m_aFontSrcCharSets.push(eSrcCharSet);
3801  }
3802  }
3803  return false;
3804  }
3805 
3806  rtl_TextEncoding eDstCharSet = eSrcCharSet;
3807 
3808  SvxFontItem aFont( eFamily, aName, OUString(), ePitch, eDstCharSet, nWhich);
3809 
3810  if( bSetEnums )
3811  {
3812  if( m_pCurrentColl && m_nCurrentColl < m_vColl.size() ) // StyleDef
3813  {
3814  switch(nWhich)
3815  {
3816  default:
3817  case RES_CHRATR_FONT:
3818  m_vColl[m_nCurrentColl].m_eLTRFontSrcCharSet = eSrcCharSet;
3819  break;
3820  case RES_CHRATR_CTL_FONT:
3821  m_vColl[m_nCurrentColl].m_eRTLFontSrcCharSet = eSrcCharSet;
3822  break;
3823  case RES_CHRATR_CJK_FONT:
3824  m_vColl[m_nCurrentColl].m_eCJKFontSrcCharSet = eSrcCharSet;
3825  break;
3826  }
3827  }
3828  else if (IsListOrDropcap())
3829  {
3830  //Add character text encoding to stack
3831  if (nWhich == RES_CHRATR_CJK_FONT)
3832  m_aFontSrcCJKCharSets.push(eSrcCharSet);
3833  else
3834  m_aFontSrcCharSets.push(eSrcCharSet);
3835  }
3836  }
3837 
3838  NewAttr( aFont ); // ...and insert
3839 
3840  return true;
3841 }
3842 
3844 {
3845  OSL_ENSURE(!m_aFontSrcCharSets.empty(),"no charset to remove");
3846  if (!m_aFontSrcCharSets.empty())
3847  m_aFontSrcCharSets.pop();
3848 }
3849 
3851 {
3852  OSL_ENSURE(!m_aFontSrcCJKCharSets.empty(),"no charset to remove");
3853  if (!m_aFontSrcCJKCharSets.empty())
3854  m_aFontSrcCJKCharSets.pop();
3855 }
3856 
3857 void SwWW8ImplReader::openFont(sal_uInt16 nFCode, sal_uInt16 nId)
3858 {
3859  if (SetNewFontAttr(nFCode, true, nId) && m_pCurrentColl && m_xStyles)
3860  {
3861  // remember for simulating default font
3862  if (RES_CHRATR_CJK_FONT == nId)
3863  m_xStyles->mbCJKFontChanged = true;
3864  else if (RES_CHRATR_CTL_FONT == nId)
3865  m_xStyles->mbCTLFontChanged = true;
3866  else
3867  m_xStyles->mbFontChanged = true;
3868  }
3869 }
3870 
3871 void SwWW8ImplReader::closeFont(sal_uInt16 nId)
3872 {
3873  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3874  if (nId == RES_CHRATR_CJK_FONT)
3876  else
3877  ResetCharSetVars();
3878 }
3879 
3880 /*
3881  Turn font on or off:
3882 */
3883 void SwWW8ImplReader::Read_FontCode( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3884 {
3885  //Note: this function needs to be able to run multiple times on the same data.
3886  //It is called by Read_SubSuperProp to ensure that the current fontsize is known.
3887 
3888  if (m_bSymbol) // if bSymbol, the symbol's font
3889  return;
3890 
3891 // (see sprmCSymbol) is valid!
3892  switch( nId )
3893  {
3894  case 113: //WW7
3895  case NS_sprm::CRgFtc2::val: //"Other" font, override with BiDi if it exists
3896  case NS_sprm::CFtcBi::val: //BiDi Font
3897  nId = RES_CHRATR_CTL_FONT;
3898  break;
3899  case NS_sprm::v6::sprmCFtc: //WW6
3900  case 111: //WW7
3901  case NS_sprm::CRgFtc0::val:
3902  nId = RES_CHRATR_FONT;
3903  break;
3904  case 112: //WW7
3905  case NS_sprm::CRgFtc1::val:
3906  nId = RES_CHRATR_CJK_FONT;
3907  break;
3908  default:
3909  return ;
3910  }
3911 
3912  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3913 
3914  if (nLen < 2) // end of attribute
3915  {
3916  if (eVersion <= ww::eWW6)
3917  {
3920  }
3921  closeFont(nId);
3922  }
3923  else
3924  {
3925  sal_uInt16 nFCode = SVBT16ToUInt16( pData ); // font number
3926  openFont(nFCode, nId);
3927  if (eVersion <= ww::eWW6)
3928  {
3929  openFont(nFCode, RES_CHRATR_CJK_FONT);
3930  openFont(nFCode, RES_CHRATR_CTL_FONT);
3931  }
3932  }
3933 }
3934 
3935 void SwWW8ImplReader::Read_FontSize( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3936 {
3937  switch( nId )
3938  {
3939  case 74: // WW2
3940  case NS_sprm::v6::sprmCHps:
3941  case NS_sprm::CHps::val:
3942  nId = RES_CHRATR_FONTSIZE;
3943  break;
3944  case 85: //WW2
3945  case 116: //WW7
3946  case NS_sprm::CHpsBi::val:
3948  break;
3949  default:
3950  return ;
3951  }
3952 
3953  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3954 
3955  if (nLen < (eVersion <= ww::eWW2 ? 1 : 2)) // end of attribute
3956  {
3957  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3958  if (eVersion <= ww::eWW6) // reset additionally the CTL size
3960  if (RES_CHRATR_FONTSIZE == nId) // reset additionally the CJK size
3962  }
3963  else
3964  {
3965  // Font-Size in half points e.g. 10 = 1440 / ( 72 * 2 )
3966  sal_uLong nFSize = eVersion <= ww::eWW2 ? *pData : SVBT16ToUInt16(pData);
3967  nFSize*= 10;
3968 
3969  SvxFontHeightItem aSz( nFSize, 100, nId );
3970  NewAttr( aSz );
3971  if (RES_CHRATR_FONTSIZE == nId) // set additionally the CJK size
3972  {
3973  aSz.SetWhich( RES_CHRATR_CJK_FONTSIZE );
3974  NewAttr( aSz );
3975  }
3976  if (eVersion <= ww::eWW6) // set additionally the CTL size
3977  {
3978  aSz.SetWhich( RES_CHRATR_CTL_FONTSIZE );
3979  NewAttr( aSz );
3980  }
3981  if (m_pCurrentColl && m_xStyles) // Style-Def ?
3982  {
3983  // remember for simulating default font size
3984  if (nId == RES_CHRATR_CTL_FONTSIZE)
3985  m_xStyles->mbFCTLSizeChanged = true;
3986  else
3987  {
3988  m_xStyles->mbFSizeChanged = true;
3989  if (eVersion <= ww::eWW6)
3990  m_xStyles->mbFCTLSizeChanged= true;
3991  }
3992  }
3993  }
3994 }
3995 
3996 void SwWW8ImplReader::Read_CharSet(sal_uInt16 , const sal_uInt8* pData, short nLen)
3997 {
3998  if (nLen < 1)
3999  { // end of attribute
4000  m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
4001  return;
4002  }
4003  sal_uInt8 nfChsDiff = *pData;
4004 
4005  if (nfChsDiff && nLen >= 2)
4006  m_eHardCharSet = rtl_getTextEncodingFromWindowsCharset( *(pData + 1) );
4007  else
4008  m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
4009 }
4010 
4011 void SwWW8ImplReader::Read_Language( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4012 {
4013  switch( nId )
4014  {
4015  case NS_sprm::v6::sprmCLid:
4017  case NS_sprm::CRgLid0::val:
4018  nId = RES_CHRATR_LANGUAGE;
4019  break;
4021  case NS_sprm::CRgLid1::val:
4023  break;
4024  case 83: // WW2
4025  case 114: // WW7
4026  case NS_sprm::CLidBi::val:
4028  break;
4029  default:
4030  return;
4031  }
4032 
4033  if (nLen < 2) // end of attribute
4034  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4035  else
4036  {
4037  sal_uInt16 nLang = SVBT16ToUInt16( pData ); // Language-Id
4038  NewAttr(SvxLanguageItem(LanguageType(nLang), nId));
4039  }
4040 }
4041 
4042 /*
4043  Turn on character style:
4044 */
4045 void SwWW8ImplReader::Read_CColl( sal_uInt16, const sal_uInt8* pData, short nLen )
4046 {
4047  if (nLen < 2) // end of attribute
4048  {
4049  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_TXTATR_CHARFMT );
4050  m_nCharFormat = -1;
4051  return;
4052  }
4053  sal_uInt16 nId = SVBT16ToUInt16( pData ); // Style-Id (NOT Sprm-Id!)
4054 
4055  if( nId >= m_vColl.size() || !m_vColl[nId].m_pFormat // invalid Id?
4056  || m_vColl[nId].m_bColl ) // or paragraph style?
4057  return; // then ignore
4058 
4059  // if current on loading a TOX field, and current trying to apply a hyperlink character style,
4060  // just ignore. For the hyperlinks inside TOX in MS Word is not same with a common hyperlink
4061  // Character styles: without underline and blue font color. And such type style will be applied in others
4062  // processes.
4063  if (m_bLoadingTOXCache && m_vColl[nId].GetWWStyleId() == ww::stiHyperlink)
4064  {
4065  return;
4066  }
4067 
4068  NewAttr( SwFormatCharFormat( static_cast<SwCharFormat*>(m_vColl[nId].m_pFormat) ) );
4069  m_nCharFormat = static_cast<short>(nId);
4070 }
4071 
4072 /*
4073  Narrower or wider than normal:
4074 */
4075 void SwWW8ImplReader::Read_Kern( sal_uInt16, const sal_uInt8* pData, short nLen )
4076 {
4077  if (nLen < 2) // end of attribute
4078  {
4079  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_KERNING );
4080  return;
4081  }
4082  sal_Int16 nKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4084 }
4085 
4086 void SwWW8ImplReader::Read_FontKern( sal_uInt16, const sal_uInt8* pData, short nLen )
4087 {
4088  if (nLen < 2) // end of attribute
4089  {
4091  return;
4092  }
4093  sal_Int16 nAutoKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4094  NewAttr(SvxAutoKernItem(static_cast<bool>(nAutoKern), RES_CHRATR_AUTOKERN));
4095 }
4096 
4097 void SwWW8ImplReader::Read_CharShadow( sal_uInt16, const sal_uInt8* pData, short nLen )
4098 {
4099  //Has newer colour variant, ignore this old variant
4100  if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CShd::val).pSprm)
4101  return;
4102 
4103  if (nLen < 2)
4104  {
4106  }
4107  else
4108  {
4109  WW8_SHD aSHD;
4110  aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4111  SwWW8Shade aSh( m_bVer67, aSHD );
4112 
4114 
4115  // Add a marker to the grabbag indicating that character background was imported from MSO shading
4116  SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4117  std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4118  rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::makeAny(true)));
4119  NewAttr(aGrabBag);
4120  }
4121 }
4122 
4123 void SwWW8ImplReader::Read_TextBackColor(sal_uInt16, const sal_uInt8* pData, short nLen )
4124 {
4125  if (nLen <= 0)
4126  {
4128  }
4129  else
4130  {
4131  OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4132  if (nLen != 10)
4133  return;
4134  Color aColour(ExtractColour(pData, m_bVer67));
4136 
4137  // Add a marker to the grabbag indicating that character background was imported from MSO shading
4138  SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4139  std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4140  rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::makeAny(true)));
4141  NewAttr(aGrabBag);
4142  }
4143 }
4144 
4145 void SwWW8ImplReader::Read_CharHighlight(sal_uInt16, const sal_uInt8* pData, short nLen)
4146 {
4147  // MS Word completely ignores character highlighting in character styles.
4149  return;
4150 
4151  if (nLen < 1)
4152  {
4154  }
4155  else
4156  {
4157  sal_uInt8 b = *pData; // Parameter: 0 = Auto, 1..16 colors
4158 
4159  if( b > 16 ) // invalid -> Black
4160  b = 0; // Auto -> Black
4161 
4162  Color aCol(GetCol(b));
4164  }
4165 }
4166 
4167 void SwWW8ImplReader::Read_NoLineNumb(sal_uInt16 , const sal_uInt8* pData, short nLen)
4168 {
4169  if (nLen < 0) // end of attribute
4170  {
4171  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_LINENUMBER );
4172  return;
4173  }
4174  SwFormatLineNumber aLN;
4175  if (const SwFormatLineNumber* pLN
4176  = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
4177  {
4178  aLN.SetStartValue( pLN->GetStartValue() );
4179  }
4180 
4181  aLN.SetCountLines(pData && nLen >= 1 && (0 == *pData));
4182  NewAttr( aLN );
4183 }
4184 
4185 static bool lcl_HasExplicitLeft(const WW8PLCFMan *pPlcxMan, bool bVer67)
4186 {
4187  WW8PLCFx_Cp_FKP *pPap = pPlcxMan ? pPlcxMan->GetPapPLCF() : nullptr;
4188  if (pPap)
4189  {
4190  if (bVer67)
4191  return pPap->HasSprm(NS_sprm::v6::sprmPDxaLeft).pSprm;
4192  else
4194  }
4195  return false;
4196 }
4197 
4198 // Sprm 16, 17
4199 void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4200 {
4201  if (nLen < 2) // end of attribute
4202  {
4203  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LR_SPACE);
4204  return;
4205  }
4206 
4207  short nPara = SVBT16ToUInt16( pData );
4208 
4209  std::shared_ptr<SvxLRSpaceItem> aLR(std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE));
4210  const SfxPoolItem* pLR = GetFormatAttr(RES_LR_SPACE);
4211  if( pLR )
4212  aLR.reset(static_cast<SvxLRSpaceItem*>(pLR->Clone()));
4213 
4214  // Fix the regression issue: #i99822#: Discussion?
4215  // Since the list level formatting doesn't apply into paragraph style
4216  // for list levels of mode LABEL_ALIGNMENT.(see ww8par3.cxx
4217  // W8ImplReader::RegisterNumFormatOnTextNode).
4218  // Need to apply the list format to the paragraph here.
4219  SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode();
4220  if( pTextNode && pTextNode->AreListLevelIndentsApplicable() )
4221  {
4222  SwNumRule * pNumRule = pTextNode->GetNumRule();
4223  if( pNumRule )
4224  {
4225  sal_uInt8 nLvl = static_cast< sal_uInt8 >(pTextNode->GetActualListLevel());
4226  const SwNumFormat* pFormat = pNumRule->GetNumFormat( nLvl );
4227  if ( pFormat && pFormat->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
4228  {
4229  aLR->SetTextLeft( pFormat->GetIndentAt() );
4230  aLR->SetTextFirstLineOffset( static_cast<short>(pFormat->GetFirstLineIndent()) );
4231  // make paragraph have hard-set indent attributes
4232  pTextNode->SetAttr( *aLR );
4233  }
4234  }
4235  }
4236 
4237  /*
4238  The older word sprms mean left/right, while the new ones mean before/after.
4239  Writer now also works with before after, so when we see old left/right and
4240  we're RTL. We swap them
4241  */
4242  if (IsRightToLeft())
4243  {
4244  switch (nId)
4245  {
4246  //Left becomes after;
4249  break;
4252  break;
4253  //Right becomes before;
4256  break;
4259  break;
4260  }
4261  }
4262 
4263  bool bFirstLinOfstSet( false ); // #i103711#
4264  bool bLeftIndentSet( false ); // #i105414#
4265 
4266  switch (nId)
4267  {
4268  //sprmPDxaLeft
4272  aLR->SetTextLeft( nPara );
4273  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4274  {
4275  m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4276  }
4277  bLeftIndentSet = true; // #i105414#
4278  break;
4279  //sprmPDxaLeft1
4283  /*
4284  As part of an attempt to break my spirit ww 8+ formats can contain
4285  ww 7- lists. If they do and the list is part of the style, then
4286  when removing the list from a paragraph of that style there
4287  appears to be a bug where the hanging indent value which the list
4288  set is still factored into the left indent of the paragraph. Its
4289  not listed in the winword dialogs, but it is clearly there. So if
4290  our style has a broken ww 7- list and we know that the list has
4291  been removed then we will factor the original list applied hanging
4292  into our calculation.
4293  */
4294  if (m_xPlcxMan && m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_bHasBrokenWW6List)
4295  {
4296  SprmResult aIsZeroed = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PIlfo::val);
4297  if (aIsZeroed.pSprm && aIsZeroed.nRemainingData >= 1 && *aIsZeroed.pSprm == 0)
4298  {
4299  const SvxLRSpaceItem &rLR =
4300  ItemGet<SvxLRSpaceItem>(*(m_vColl[m_nCurrentColl].m_pFormat),
4301  RES_LR_SPACE);
4302  nPara = nPara - rLR.GetTextFirstLineOffset();
4303  }
4304  }
4305 
4306  aLR->SetTextFirstLineOffset(nPara);
4307 
4308  if (!m_pCurrentColl)
4309  {
4310  if (const SwTextNode* pNode = m_pPaM->GetNode().GetTextNode())
4311  {
4312  if ( const SwNumFormat *pNumFormat = GetNumFormatFromTextNode(*pNode) )
4313  {
4315  {
4316  aLR->SetTextLeft(pNumFormat->GetIndentAt());
4317 
4318  // If have not explicit left, set number format list tab position is doc default tab
4320  if ( pDefaultStopItem && pDefaultStopItem->Count() > 0 )
4321  const_cast<SwNumFormat*>(pNumFormat)->SetListtabPos( const_cast<SvxTabStop&>((*pDefaultStopItem)[0]).GetTabPos() );
4322  }
4323  }
4324  }
4325  }
4326  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4327  {
4328  m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4329  }
4330  bFirstLinOfstSet = true; // #i103711#
4331  break;
4332  //sprmPDxaRight
4336  aLR->SetRight( nPara );
4337  break;
4338  default:
4339  return;
4340  }
4341 
4342  NewAttr( *aLR, bFirstLinOfstSet, bLeftIndentSet ); // #i103711#, #i105414#
4343 }
4344 
4345 // Sprm 20
4346 void SwWW8ImplReader::Read_LineSpace( sal_uInt16, const sal_uInt8* pData, short nLen )
4347 {
4348 // comment see Read_UL()
4350  return;
4351 
4352  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
4353 
4354  if (nLen < (eVersion <= ww::eWW2 ? 3 : 4))
4355  {
4357  if( !( m_nIniFlags & WW8FL_NO_IMPLPASP ) )
4358  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4359  return;
4360  }
4361 
4362  short nSpace = SVBT16ToUInt16( pData );
4363  short nMulti = (eVersion <= ww::eWW2) ? 1 : SVBT16ToUInt16( pData + 2 );
4364 
4365  SvxLineSpaceRule eLnSpc;
4366  if( 0 > nSpace )
4367  {
4368  nSpace = -nSpace;
4369  eLnSpc = SvxLineSpaceRule::Fix;
4370  }
4371  else
4372  eLnSpc = SvxLineSpaceRule::Min;
4373 
4374  // WW has implicit additional paragraph spacing depending on
4375  // the line spacing. It is, for "exactly", 0.8 * line spacing "before"
4376  // and 0.2 * line spacing "after".
4377  // For "at least", it is 1 * line spacing "before" and 0 * line spacing "after".
4378  // For "multiple", it is 0 "before" and min(0cm, FontSize*(nFach-1)) "after".
4379 
4380  // SW also has implicit line spacing. It is, for "at least"
4381  // 1 * line spacing "before" and 0 "after".
4382  // For proportional, it is min(0cm, FontSize*(nFach-1)) both "before" and "after".
4383 
4384  sal_uInt16 nSpaceTw = 0;
4385 
4387 
4388  if( 1 == nMulti ) // MultilineSpace ( proportional )
4389  {
4390  tools::Long n = nSpace * 10 / 24; // WW: 240 = 100%, SW: 100 = 100%
4391 
4392  // here n is in [0..13653]
4393  aLSpc.SetPropLineSpace( o3tl::narrowing<sal_uInt16>(n) );
4394  const SvxFontHeightItem* pH = static_cast<const SvxFontHeightItem*>(
4396  nSpaceTw = o3tl::narrowing<sal_uInt16>( n * pH->GetHeight() / 100 );
4397  }
4398  else // Fixed / Minimum
4399  {
4400  // for negative space, the distance is "exact", otherwise "at least"
4401  nSpaceTw = o3tl::narrowing<sal_uInt16>(nSpace);
4402  aLSpc.SetLineHeight( nSpaceTw );
4403  aLSpc.SetLineSpaceRule( eLnSpc);
4404  }
4405  NewAttr( aLSpc );
4406  if (m_xSFlyPara)
4407  m_xSFlyPara->nLineSpace = nSpaceTw; // linespace for graphics APOs
4408 }
4409 
4410 //#i18519# AutoSpace value depends on Dop fDontUseHTMLAutoSpacing setting
4411 sal_uInt16 SwWW8ImplReader::GetParagraphAutoSpace(bool fDontUseHTMLAutoSpacing)
4412 {
4413  if (fDontUseHTMLAutoSpacing)
4414  return 100; //Seems to be always 5points in this case
4415  else
4416  return 280; //Seems to be always 14points in this case
4417 }
4418 
4419 void SwWW8ImplReader::Read_ParaAutoBefore(sal_uInt16, const sal_uInt8 *pData, short nLen)
4420 {
4421  if (nLen < 1)
4422  {
4423  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4424  return;
4425  }
4426 
4427  if (*pData)
4428  {
4429  SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4430  aUL.SetUpper(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4431  NewAttr(aUL);
4432  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4434  else
4435  m_bParaAutoBefore = true;
4436  }
4437  else
4438  {
4439  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4441  else
4442  m_bParaAutoBefore = false;
4443  }
4444 }
4445 
4446 void SwWW8ImplReader::Read_ParaAutoAfter(sal_uInt16, const sal_uInt8 *pData, short nLen)
4447 {
4448  if (nLen < 1)
4449  {
4450  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4451  return;
4452  }
4453 
4454  if (*pData)
4455  {
4456  SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4457  aUL.SetLower(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4458  NewAttr(aUL);
4459  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4461  else
4462  m_bParaAutoAfter = true;
4463  }
4464  else
4465  {
4466  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4468  else
4469  m_bParaAutoAfter = false;
4470  }
4471 }
4472 
4473 // Sprm 21, 22
4474 void SwWW8ImplReader::Read_UL( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4475 {
4476  // A workaround for an error in WW: For nProduct == 0c03d, usually
4477  // DyaAfter 240 (delta y distance after, comment of the translator)
4478  // is incorrectly inserted into style "Normal", even though it isn't there.
4479  // Using the ini flag WW8FL_NO_STY_DYA you can force this behavior for other
4480  // WW versions as well.
4481  // OSL_ENSURE( !bStyNormal || bWWBugNormal, "+This Document may point to a bug
4482  // in the WW version used for creating it. If the Styles <Standard> resp.
4483  // <Normal> differentiate between WW and SW in paragraph or line spacing,
4484  // then please send this Document to SH.");
4485  // bWWBugNormal is not a sufficient criterion for this distance being wrong.
4486 
4487  if (nLen < 2)
4488  {
4489  // end of attribute
4490  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4491  return;
4492  }
4493  short nPara = SVBT16ToUInt16( pData );
4494  if( nPara < 0 )
4495  nPara = -nPara;
4496 
4497  SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4498 
4499  switch( nId )
4500  {
4501  //sprmPDyaBefore
4504  aUL.SetUpper( nPara );
4505  break;
4506  //sprmPDyaAfter
4509  aUL.SetLower( nPara );
4510  break;
4511  default:
4512  return;
4513  }
4514 
4515  NewAttr( aUL );
4516 }
4517 
4518 void SwWW8ImplReader::Read_ParaContextualSpacing( sal_uInt16, const sal_uInt8* pData, short nLen )
4519 {
4520  if (nLen < 1)
4521  {
4522  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4523  return;
4524  }
4525  SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4526  aUL.SetContextValue(*pData != 0);
4527  NewAttr( aUL );
4528 }
4529 
4530 void SwWW8ImplReader::Read_IdctHint( sal_uInt16, const sal_uInt8* pData, short nLen )
4531 {
4532  // sprmcidcthint (opcode 0x286f) specifies a script bias for the text in the run.
4533  // for unicode characters that are shared between far east and non-far east scripts,
4534  // this property determines what font and language the character will use.
4535  // when this value is 0, text properties bias towards non-far east properties.
4536  // when this value is 1, text properties bias towards far east properties.
4537  // when this value is 2, text properties bias towards complex properties.
4538  if (nLen < 1) //Property end
4539  {
4541  }
4542  else //Property start
4543  {
4545  }
4546 }
4547 
4548 void SwWW8ImplReader::Read_Justify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4549 {
4550  if (nLen < 1)
4551  {
4552  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4553  return;
4554  }
4555 
4556  SvxAdjust eAdjust(SvxAdjust::Left);
4557  bool bDistributed = false;
4558  switch (*pData)
4559  {
4560  default:
4561  case 0:
4562  break;
4563  case 1:
4564  eAdjust = SvxAdjust::Center;
4565  break;
4566  case 2:
4567  eAdjust = SvxAdjust::Right;
4568  break;
4569  case 3:
4570  eAdjust = SvxAdjust::Block;
4571  break;
4572  case 4:
4573  eAdjust = SvxAdjust::Block;
4574  bDistributed = true;
4575  break;
4576  }
4577  SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4578  if (bDistributed)
4579  aAdjust.SetLastBlock(SvxAdjust::Block);
4580 
4581  NewAttr(aAdjust);
4583 }
4584 
4586 {
4587  bool bRTL = false;
4588  SprmResult aDir;
4589  if (m_xPlcxMan)
4590  aDir = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PFBiDi::val);
4591  if (aDir.pSprm && aDir.nRemainingData >= 1)
4592  bRTL = *aDir.pSprm != 0;
4593  else
4594  {
4595  const SvxFrameDirectionItem* pItem=
4596  static_cast<const SvxFrameDirectionItem*>(GetFormatAttr(RES_FRAMEDIR));
4597  if (pItem && (pItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4598  bRTL = true;
4599  }
4600  return bRTL;
4601 }
4602 
4603 void SwWW8ImplReader::Read_RTLJustify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4604 {
4605  if (nLen < 1)
4606  {
4607  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4608  return;
4609  }
4610 
4611  //If we are in a ltr paragraph this is the same as normal Justify,
4612  //If we are in a rtl paragraph the meaning is reversed.
4613  if (!IsRightToLeft())
4614  Read_Justify(nId, pData, nLen);
4615  else
4616  {
4617  SvxAdjust eAdjust(SvxAdjust::Right);
4618  bool bDistributed = false;
4619  switch (*pData)
4620  {
4621  default:
4622  case 0:
4623  break;
4624  case 1:
4625  eAdjust = SvxAdjust::Center;
4626  break;
4627  case 2:
4628  eAdjust = SvxAdjust::Left;
4629  break;
4630  case 3:
4631  eAdjust = SvxAdjust::Block;
4632  break;
4633  case 4:
4634  eAdjust = SvxAdjust::Block;
4635  bDistributed = true;
4636  break;
4637  }
4638  SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4639  if (bDistributed)
4640  aAdjust.SetLastBlock(SvxAdjust::Block);
4641 
4642  NewAttr(aAdjust);
4643  SetRelativeJustify( true );
4644  }
4645 }
4646 
4647 void SwWW8ImplReader::Read_BoolItem( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4648 {
4649  switch( nId )
4650  {
4653  break;
4656  break;
4658  nId = RES_PARATR_SCRIPTSPACE;
4659  break;
4660  default:
4661  OSL_ENSURE( false, "wrong Id" );
4662  return ;
4663  }
4664 
4665  if (nLen < 1)
4666  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4667  else
4668  {
4669  std::unique_ptr<SfxBoolItem> pI(static_cast<SfxBoolItem*>(GetDfltAttr( nId )->Clone()));
4670  pI->SetValue( 0 != *pData );
4671  NewAttr( *pI );
4672  }
4673 }
4674 
4675 void SwWW8ImplReader::Read_Emphasis( sal_uInt16, const sal_uInt8* pData, short nLen )
4676 {
4677  if (nLen < 1)
4679  else
4680  {
4682  //Check to see if there is an up and coming cjk language property. If
4683  //there is use it, if there is not fall back to the currently set one.
4684  //Only the cjk language setting seems to matter to word, the western
4685  //one is ignored
4686  SprmResult aLang;
4687  if (m_xPlcxMan)
4688  aLang = m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CRgLid1_80::val);
4689 
4690  if (aLang.pSprm && aLang.nRemainingData >= 2)
4691  nLang = LanguageType(SVBT16ToUInt16(aLang.pSprm));
4692  else
4693  {
4694  nLang = static_cast<const SvxLanguageItem *>(
4696  }
4697 
4698  FontEmphasisMark nVal;
4699  switch( *pData )
4700  {
4701  case 0:
4702  nVal = FontEmphasisMark::NONE;
4703  break;
4704  case 2:
4706  nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4707  else if (nLang == LANGUAGE_JAPANESE)
4708  nVal = (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove);
4709  else
4710  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4711  break;
4712  case 3:
4713  nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4714  break;
4715  case 4:
4716  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4717  break;
4718  case 1:
4719  if (MsLangId::isSimplifiedChinese(nLang))
4720  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4721  else
4722  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4723  break;
4724  default:
4725  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4726  break;
4727  }
4728 
4730  }
4731 }
4732 
4733 void SwWW8ImplReader::Read_ScaleWidth( sal_uInt16, const sal_uInt8* pData, short nLen )
4734 {
4735  if (nLen < 2)
4736  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SCALEW );
4737  else
4738  {
4739  sal_uInt16 nVal = SVBT16ToUInt16( pData );
4740  //The number must be between 1 and 600
4741  if (nVal < 1 || nVal > 600)
4742  nVal = 100;
4744  }
4745 }
4746 
4747 void SwWW8ImplReader::Read_Relief( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4748 {
4749  if (nLen < 1)
4750  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_RELIEF );
4751  else
4752  {
4753  if( *pData )
4754  {
4755 // not so easy because this is also a toggle attribute!
4756 // 2 x emboss on -> no emboss !!!
4757 // the actual value must be searched over the stack / template
4758 
4759  const SvxCharReliefItem* pOld = static_cast<const SvxCharReliefItem*>(
4761  FontRelief nNewValue = NS_sprm::CFImprint::val == nId ? FontRelief::Engraved
4762  : ( NS_sprm::CFEmboss::val == nId ? FontRelief::Embossed
4763  : FontRelief::NONE );
4764  if( pOld->GetValue() == nNewValue )
4765  {
4766  if( FontRelief::NONE != nNewValue )
4767  nNewValue = FontRelief::NONE;
4768  }
4770  }
4771  }
4772 }
4773 
4774 void SwWW8ImplReader::Read_TextAnim(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
4775 {
4776  if (nLen < 1)
4778  else
4779  {
4780  if (*pData)
4781  {
4782  bool bBlink;
4783 
4784  // The 7 animated text effects available in word all get
4785  // mapped to a blinking text effect in LibreOffice
4786  // 0 no animation 1 Las Vegas lights
4787  // 2 background blink 3 sparkle text
4788  // 4 marching ants 5 marching red ants
4789  // 6 shimmer
4790  bBlink = *pData > 0 && *pData < 7;
4791 
4793  }
4794  }
4795 }
4796 
4797 SwWW8Shade::SwWW8Shade(bool bVer67, const WW8_SHD& rSHD)
4798 {
4799  sal_uInt8 b = rSHD.GetFore();
4800  OSL_ENSURE(b < 17, "ww8: colour out of range");
4801  if (b >= 17)
4802  b = 0;
4803 
4804  Color nFore(SwWW8ImplReader::GetCol(b));
4805 
4806  b = rSHD.GetBack();
4807  OSL_ENSURE(b < 17, "ww8: colour out of range");
4808  if( b >= 17 )
4809  b = 0;
4810 
4811  Color nBack(SwWW8ImplReader::GetCol(b));
4812 
4813  b = rSHD.GetStyle(bVer67);
4814 
4815  SetShade(nFore, nBack, b);
4816 }
4817 
4818 void SwWW8Shade::SetShade(Color nFore, Color nBack, sal_uInt16 nIndex)
4819 {
4820  static const sal_uLong eMSGrayScale[] =
4821  {
4822  // Clear-Brush
4823  0, // 0 clear
4824  // Solid-Brush
4825  1000, // 1 solid
4826  // Percent values
4827  50, // 2 pct5
4828  100, // 3 pct10
4829  200, // 4 pct20
4830  250, // 5 pct25
4831  300, // 6 pct30
4832  400, // 7 pct40
4833  500, // 8 pct50
4834  600, // 9 pct60
4835  700, // 10 pct70
4836  750, // 11 pct75
4837  800, // 12 pct80
4838  900, // 13 pct90
4839  // Special cases
4840  333, // 14 Dark Horizontal
4841  333, // 15 Dark Vertical
4842  333, // 16 Dark Forward Diagonal
4843  333, // 17 Dark Backward Diagonal
4844  333, // 18 Dark Cross
4845  333, // 19 Dark Diagonal Cross
4846  333, // 20 Horizontal
4847  333, // 21 Vertical
4848  333, // 22 Forward Diagonal
4849  333, // 23 Backward Diagonal
4850  333, // 24 Cross
4851  333, // 25 Diagonal Cross
4852  // Undefined values in DOC spec-sheet
4853  500, // 26
4854  500, // 27
4855  500, // 28
4856  500, // 29
4857  500, // 30
4858  500, // 31
4859  500, // 32
4860  500, // 33
4861  500, // 34
4862  // Different shading types
4863  25, // 35 [available in DOC, not available in DOCX]
4864  75, // 36 [available in DOC, not available in DOCX]
4865  125, // 37 pct12
4866  150, // 38 pct15
4867  175, // 39 [available in DOC, not available in DOCX]
4868  225, // 40 [available in DOC, not available in DOCX]
4869  275, // 41 [available in DOC, not available in DOCX]
4870  325, // 42 [available in DOC, not available in DOCX]
4871  350, // 43 pct35
4872  375, // 44 pct37
4873  425, // 45 [available in DOC, not available in DOCX]
4874  450, // 46 pct45
4875  475, // 47 [available in DOC, not available in DOCX]
4876  525, // 48 [available in DOC, not available in DOCX]
4877  550, // 49 pct55
4878  575, // 50 [available in DOC, not available in DOCX]
4879  625, // 51 pct62
4880  650, // 52 pct65
4881  675, // 53 [available in DOC, not available in DOCX]
4882  725, // 54 [available in DOC, not available in DOCX]
4883  775, // 55 [available in DOC, not available in DOCX]
4884  825, // 56 [available in DOC, not available in DOCX]
4885  850, // 57 pct85
4886  875, // 58 pct87
4887  925, // 59 [available in DOC, not available in DOCX]
4888  950, // 60 pct95
4889  975 // 61 [available in DOC, not available in DOCX]
4890  };// 62
4891 
4892  //NO auto for shading so Foreground: Auto = Black
4893  if (nFore == COL_AUTO)
4894  nFore = COL_BLACK;
4895 
4896  //NO auto for shading so background: Auto = White
4897  Color nUseBack = nBack;
4898  if (nUseBack == COL_AUTO)
4899  nUseBack = COL_WHITE;
4900 
4901  if( nIndex >= SAL_N_ELEMENTS( eMSGrayScale ) )
4902  nIndex = 0;
4903 
4904  sal_uLong nWW8BrushStyle = eMSGrayScale[nIndex];
4905 
4906  switch (nWW8BrushStyle)
4907  {
4908  case 0: // Null-Brush
4909  aColor = nBack;
4910  break;
4911  default:
4912  {
4913  Color aForeColor(nFore);
4914  Color aBackColor(nUseBack);
4915 
4916  sal_uInt32 nRed = aForeColor.GetRed() * nWW8BrushStyle;
4917  sal_uInt32 nGreen = aForeColor.GetGreen() * nWW8BrushStyle;
4918  sal_uInt32 nBlue = aForeColor.GetBlue() * nWW8BrushStyle;
4919  nRed += aBackColor.GetRed() * (1000 - nWW8BrushStyle);
4920  nGreen += aBackColor.GetGreen()* (1000 - nWW8BrushStyle);
4921  nBlue += aBackColor.GetBlue() * (1000 - nWW8BrushStyle);
4922 
4923  aColor = Color( nRed/1000, nGreen/1000, nBlue/1000 );
4924  }
4925  break;
4926  }
4927 }
4928 
4929 void SwWW8ImplReader::Read_Shade( sal_uInt16, const sal_uInt8* pData, short nLen )
4930 {
4931  if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PShd::val).pSprm)
4932  return;
4933 
4934  if (nLen < 2)
4935  {
4936  // end of attribute
4937  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
4938  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
4939  }
4940  else
4941  {
4942  WW8_SHD aSHD;
4943  aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4944  SwWW8Shade aSh( m_bVer67, aSHD );
4945 
4946  NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
4947  NewAttr( XFillColorItem(OUString(), aSh.aColor) );
4948  }
4949 }
4950 
4951 void SwWW8ImplReader::Read_ParaBackColor(sal_uInt16, const sal_uInt8* pData, short nLen)
4952 {
4953  if (nLen <= 0)
4954  {
4955  // end of attribute
4956  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
4957  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
4958  }
4959  else
4960  {
4961  OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4962  if (nLen != 10)
4963  return;
4964 
4965  const Color aColor = ExtractColour(pData, m_bVer67);
4966  NewAttr( XFillColorItem(OUString(), aColor) );
4967  if ( aColor == COL_AUTO )
4968  NewAttr( XFillStyleItem(drawing::FillStyle_NONE) );
4969  else
4970  NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
4971  }
4972 }
4973 
4974 Color SwWW8ImplReader::ExtractColour(const sal_uInt8* &rpData, bool bVer67)
4975 {
4976  OSL_ENSURE(!bVer67, "Impossible");
4977  Color nFore = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
4978  rpData+=4;
4979  Color nBack = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
4980  rpData+=4;
4981  sal_uInt16 nIndex = SVBT16ToUInt16(rpData);
4982  rpData+=2;
4983  //Being a transparent background colour doesn't actually show the page
4984  //background through, it merely acts like white
4985  if (nBack == Color(ColorTransparency, 0xFF000000))
4986  nBack = COL_AUTO;
4987  OSL_ENSURE(nBack == COL_AUTO || !nBack.IsTransparent(),
4988  "ww8: don't know what to do with such a transparent bg colour, report");
4989  SwWW8Shade aShade(nFore, nBack, nIndex);
4990  return aShade.aColor;
4991 }
4992 
4993 void SwWW8ImplReader::Read_TextVerticalAdjustment( sal_uInt16, const sal_uInt8* pData, short nLen )
4994 {
4995  if( nLen <= 0 )
4996  return;
4997 
4998  drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
4999  switch( *pData )
5000  {
5001  case 1:
5002  nVA = drawing::TextVerticalAdjust_CENTER;
5003  break;
5004  case 2: //justify
5005  nVA = drawing::TextVerticalAdjust_BLOCK;
5006  break;
5007  case 3:
5008  nVA = drawing::TextVerticalAdjust_BOTTOM;
5009  break;
5010  default:
5011  break;
5012  }
5014 }
5015 
5016 void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
5017 {
5018  if (nLen < 0)
5019  {
5020