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();
726  aSet.Put(SvxFrameDirectionItem(
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_uLong 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  ww::sti eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc( static_cast< sal_uInt8 >(nColl) ) : static_cast<ww::sti>(nColl);
1793  while (eSti != ww::stiNil && sal::static_int_cast<size_t>(nColl) < pIo->m_vColl.size() && nullptr == (pNowStyleApo = pIo->m_vColl[nColl].m_xWWFly.get()))
1794  {
1795  nColl = pIo->m_vColl[nColl].m_nBase;
1796  eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc( static_cast< sal_uInt8 >(nColl) ) : static_cast<ww::sti>(nColl);
1797  }
1798 
1799  WW8FlyPara aF(bVer67, pNowStyleApo);
1800  // new FlaPara for comparison
1801  aF.Read(*aS.pSprm, pPap); // WWPara for new Para
1802  if( !( aF == *this ) ) // same APO? (or a new one?)
1803  bGrafApo = true; // no -> 1-line APO
1804  // -> graphics APO
1805  }
1806  while( false ); // block for quick exit
1807 
1808  xPlcxMan->GetPap()->Restore( aSave );
1809  pIoStrm->Seek( nPos );
1810  }while( false ); // block for quick exit
1811 }
1812 
1813 // read for Apo definitions in Styledefs
1814 void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8RStyle const * pStyle)
1815 {
1816  if (bVer67)
1817  {
1818  SetValSprm( &nSp26, pStyle, NS_sprm::v6::sprmPDxaAbs ); // X-position
1819  //set in me or in parent style
1820  mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::v6::sprmPDyaAbs); // Y-position
1821  SetValSprm( &nSp45, pStyle, NS_sprm::v6::sprmPWHeightAbs ); // height
1822  SetValSprm( &nSp28, pStyle, NS_sprm::v6::sprmPDxaWidth ); // width
1823  SetValSprm( &nLeMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // L-border
1824  SetValSprm( &nRiMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // R-border
1825  SetValSprm( &nUpMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // U-border
1826  SetValSprm( &nLoMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // D-border
1827 
1828  SprmResult aS = pStyle->HasParaSprm( NS_sprm::v6::sprmPWr ); // wrapping
1829  if (aS.pSprm && aS.nRemainingData >= 1)
1830  nSp37 = *aS.pSprm;
1831  }
1832  else
1833  {
1834  SetValSprm( &nSp26, pStyle, NS_sprm::PDxaAbs::val ); // X-position
1835  //set in me or in parent style
1836  mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::PDyaAbs::val); // Y-position
1837  SetValSprm( &nSp45, pStyle, NS_sprm::PWHeightAbs::val ); // height
1838  SetValSprm( &nSp28, pStyle, NS_sprm::PDxaWidth::val ); // width
1839  SetValSprm( &nLeMgn, pStyle, NS_sprm::PDxaFromText::val ); // L-border
1840  SetValSprm( &nRiMgn, pStyle, NS_sprm::PDxaFromText::val ); // R-border
1841  SetValSprm( &nUpMgn, pStyle, NS_sprm::PDyaFromText::val ); // U-border
1842  SetValSprm( &nLoMgn, pStyle, NS_sprm::PDyaFromText::val ); // D-border
1843 
1844  SprmResult aS = pStyle->HasParaSprm( NS_sprm::PWr::val ); // wrapping
1845  if (aS.pSprm && aS.nRemainingData >= 1)
1846  nSp37 = *aS.pSprm;
1847  }
1848 
1849  if (::lcl_ReadBorders(bVer67, brc, nullptr, pStyle)) // border
1851 
1852  /*
1853  #i8798#
1854  Appears that with no dyaAbs set then the actual vert anchoring set is
1855  ignored and we remain relative to text, so if that is the case we are 0
1856  from para anchor, so we update the frame to have explicitly this type of
1857  anchoring
1858  */
1859  if (!mbVertSet)
1860  nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1861  else
1862  nSp29 = nOrigSp29;
1863 }
1864 
1866 {
1867  WW8FlyPara aEmpty(bVer67);
1868  /*
1869  wr of 0 like 2 appears to me to be equivalent for checking here. See
1870  #107103# if wrong, so given that the empty is 2, if we are 0 then set
1871  empty to 0 to make 0 equiv to 2 for empty checking
1872  */
1873  OSL_ENSURE(aEmpty.nSp37 == 2, "this is not what we expect for nSp37");
1874  if (this->nSp37 == 0)
1875  aEmpty.nSp37 = 0;
1876  return aEmpty == *this;
1877 }
1878 
1879 // #i18732# - changes made on behalf of CMC
1881  SwWW8ImplReader& rIo,
1882  WW8FlyPara& rWW,
1883  const sal_uInt32 nWWPgTop,
1884  const sal_uInt32 nPgWidth,
1885  const sal_Int32 nIniFlyDx,
1886  const sal_Int32 nIniFlyDy ):
1887 pFlyFormat(nullptr),
1888 nXPos(0),
1889 nYPos(0),
1890 nLeMgn(rWW.nLeMgn),
1891 nRiMgn(rWW.nRiMgn),
1892 nUpMgn(rWW.nUpMgn),
1893 nLoMgn(rWW.nLoMgn),
1894 nWidth(rWW.nSp28),
1895 nHeight(rWW.nSp45),
1896 nNetWidth(rWW.nSp28),
1897 eHeightFix(SwFrameSize::Fixed),
1898 eHRel(text::RelOrientation::PAGE_FRAME),
1899 eVRel(text::RelOrientation::FRAME),
1900 eVAlign(text::VertOrientation::NONE),
1901 eHAlign(text::HoriOrientation::NONE),
1902 eSurround(( rWW.nSp37 > 1 ) ? css::text::WrapTextMode_DYNAMIC : css::text::WrapTextMode_NONE),
1903 nXBind(( rWW.nSp29 & 0xc0 ) >> 6),
1904 nYBind(( rWW.nSp29 & 0x30 ) >> 4),
1905 nNewNetWidth(MINFLY),
1906 nLineSpace(0),
1907 bAutoWidth(false),
1908 bTogglePos(false)
1909 {
1910  //#i119466 mapping "Around" wrap setting to "Parallel" for table
1911  const bool bIsTable = rIo.m_xPlcxMan->HasParaSprm(NS_sprm::PFInTable::val).pSprm;
1912  if (bIsTable && rWW.nSp37 == 2)
1913  eSurround = css::text::WrapTextMode_PARALLEL;
1914 
1915  /*
1916  #95905#, #83307# seems to have gone away now, so re-enable parallel
1917  wrapping support for frames in headers/footers. I don't know if we truly
1918  have an explicitly specified behaviour for these circumstances.
1919  */
1920 
1921  if( nHeight & 0x8000 )
1922  {
1923  nHeight &= 0x7fff;
1925  }
1926 
1927  if( nHeight <= MINFLY )
1928  { // no data, or bad data
1930  nHeight = MINFLY;
1931  }
1932 
1933  if( nWidth <= 10 ) // auto width
1934  {
1935  bAutoWidth = true;
1936  nWidth = nNetWidth =
1937  msword_cast<sal_Int16>(nPgWidth ? nPgWidth : 2268); // 4 cm
1938  }
1939  if( nWidth <= MINFLY )
1940  nWidth = nNetWidth = MINFLY; // minimum width
1941 
1942  /*
1943  See issue #i9178# for the 9 anchoring options, and make sure they stay
1944  working if you modify the anchoring logic here.
1945  */
1946 
1947  // If the Fly is aligned left, right, up, or down,
1948  // the outer text distance will be ignored, because otherwise
1949  // the Fly will end up in the wrong position.
1950  // The only problem is with inside/outside.
1951 
1952  //#i53725# - absolute positioned objects have to be
1953  // anchored at-paragraph to assure its correct anchor position.
1954  rIo.m_pLastAnchorPos.reset( new SwPosition(*rPaM.GetPoint()));
1955 
1956  switch (nYBind)
1957  {
1958  case 0: //relative to margin
1959  eVRel = text::RelOrientation::PAGE_PRINT_AREA;
1960  break;
1961  case 1: //relative to page
1962  eVRel = text::RelOrientation::PAGE_FRAME;
1963  break;
1964  default: //relative to text
1965  // put in initialization part eVRel = text::RelOrientation::FRAME;
1966  break;
1967  }
1968 
1969 // #i18732#
1970  switch( rWW.nSp27 ) // particular Y-positions ?
1971  {
1972  case -4:
1973  eVAlign = text::VertOrientation::TOP;
1974  if (nYBind < 2)
1975  nUpMgn = 0;
1976  break; // up
1977  case -8:
1978  eVAlign = text::VertOrientation::CENTER;
1979  break; // centered
1980  case -12:
1981  eVAlign = text::VertOrientation::BOTTOM;
1982  if (nYBind < 2)
1983  nLoMgn = 0;
1984  break; // down
1985  default:
1986  nYPos = rWW.nSp27 + static_cast<short>(nIniFlyDy);
1987  break; // corrections from ini file
1988  }
1989 
1990  switch( rWW.nSp26 ) // particular X-positions ?
1991  {
1992  case 0:
1993  eHAlign = text::HoriOrientation::LEFT;
1994  nLeMgn = 0;
1995  break; // left
1996  case -4:
1997  eHAlign = text::HoriOrientation::CENTER;
1998  break; // centered
1999  case -8:
2000  eHAlign = text::HoriOrientation::RIGHT;
2001  nRiMgn = 0;
2002  break; // right
2003  case -12:
2004  eHAlign = text::HoriOrientation::LEFT;
2005  bTogglePos = true;
2006  break; // inside
2007  case -16:
2008  eHAlign = text::HoriOrientation::RIGHT;
2009  bTogglePos = true;
2010  break; // outside
2011  default:
2012  nXPos = rWW.nSp26 + static_cast<short>(nIniFlyDx);
2013  break; // corrections from ini file
2014  }
2015 
2016 // #i18732#
2017  switch (nXBind) // X - binding -> transform coordinates
2018  {
2019  case 0: //relative to column
2020  eHRel = text::RelOrientation::FRAME;
2021  break;
2022  case 1: //relative to margin
2023  eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2024  break;
2025  default: //relative to page
2026  // put in initialization part eHRel= text::RelOrientation::PAGE_FRAME;
2027  break;
2028  }
2029 
2030  // #i36649# - adjustments for certain horizontal alignments
2031  // Note: These special adjustments found by an investigation of documents
2032  // containing frames with different left/right border distances and
2033  // distances to text. The outcome is somehow strange.
2034  // Note: These adjustments causes wrong horizontal positions for frames,
2035  // which are aligned inside|outside to page|margin on even pages,
2036  // the left and right border distances are different.
2037  // no adjustments possible, if frame has automatic width.
2038  // determine left border distance
2039  sal_Int16 nLeBorderMgn( 0 );
2040  if ( !bAutoWidth )
2041  {
2042  WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2043  sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeBorderMgn);
2044  nLeBorderMgn = nLeBorderMgn + nTemp;
2045  }
2046  // determine right border distance
2047  sal_Int16 nRiBorderMgn( 0 );
2048  if ( !bAutoWidth )
2049  {
2050  WW8_BRCVer9 &rBrc = rWW.brc[WW8_RIGHT];
2051  sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nRiBorderMgn);
2052  nRiBorderMgn = nRiBorderMgn + nTemp;
2053  }
2054  if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_FRAME )
2055  {
2056  // convert 'left to page' to
2057  // 'from left -<width>-<2*left border distance>-<right wrap distance>
2058  // to page text area'
2060  eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2061  nXPos = -nWidth - (2*nLeBorderMgn) - rWW.nRiMgn;
2062  // re-set left wrap distance
2063  nLeMgn = rWW.nLeMgn;
2064  }
2065  else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_FRAME )
2066  {
2067  // convert 'right to page' to
2068  // 'from left <right border distance-left border distance>+<left wrap distance>
2069  // to right page border'
2071  eHRel = text::RelOrientation::PAGE_RIGHT;
2072  nXPos = ( nRiBorderMgn - nLeBorderMgn ) + rWW.nLeMgn;
2073  // re-set right wrap distance
2074  nRiMgn = rWW.nRiMgn;
2075  }
2076  else if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2077  {
2078  // convert 'left to margin' to
2079  // 'from left -<left border distance> to page text area'
2081  eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2082  nXPos = -nLeBorderMgn;
2083  // re-set left wrap distance
2084  nLeMgn = rWW.nLeMgn;
2085  }
2086  else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2087  {
2088  // convert 'right to margin' to
2089  // 'from left -<width>-<left border distance> to right page border'
2091  eHRel = text::RelOrientation::PAGE_RIGHT;
2092  nXPos = -nWidth - nLeBorderMgn;
2093  // re-set right wrap distance
2094  nRiMgn = rWW.nRiMgn;
2095  }
2096  else if (rWW.bBorderLines)
2097  {
2098  /*
2099  #i582#
2100  Word has a curious bug where the offset stored do not take into
2101  account the internal distance from the corner both
2102  */
2103  WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2104  sal_Int16 nLeLMgn = 0;
2105  sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeLMgn);
2106  nLeLMgn = nLeLMgn + nTemp;
2107 
2108  if (nLeLMgn)
2109  {
2110  if (eHAlign == text::HoriOrientation::LEFT)
2112  nXPos = nXPos - nLeLMgn;
2113  }
2114  }
2115 
2116  // adjustments for certain vertical alignments
2117  if ( eVAlign == text::VertOrientation::NONE && eVRel == text::RelOrientation::PAGE_PRINT_AREA )
2118  {
2119  // convert "<X> from top page text area" to
2120  // "<X + page top margin> from page"
2121  eVRel = text::RelOrientation::PAGE_FRAME;
2122  nYPos = static_cast< sal_Int16 >( nYPos + nWWPgTop );
2123  }
2124 
2125  FlySecur1( nWidth, rWW.bBorderLines ); // Do the borders match ?
2126  FlySecur1( nHeight, rWW.bBorderLines );
2127 
2128 }
2129 
2130 // If a Fly in WW has automatic width, this has to be simulated
2131 // by modifying the Fly width (fixed in SW) afterwards.
2132 // This can increase or decrease the Fly width, because the default value
2133 // is set without knowledge of the contents.
2135 {
2136  if( bAutoWidth && nInWidth > nNewNetWidth )
2137  nNewNetWidth = nInWidth;
2138 };
2139 
2140 // The class WW8FlySet is derived from SfxItemSet and does not
2141 // provide more, but is easier to handle for me.
2142 // WW8FlySet-ctor for Apos and graphics Apos
2144  const WW8SwFlyPara* pFS, bool bGraf)
2145  : SfxItemSet(rReader.m_rDoc.GetAttrPool(),svl::Items<RES_FRMATR_BEGIN,RES_FRMATR_END-1>{})
2146 {
2147  Reader::ResetFrameFormatAttrs(*this); // remove distance/border
2148  // position
2149  Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2150 
2151 /*Below can all go when we have from left in rtl mode*/
2152  SwTwips nXPos = pFS->nXPos;
2153  sal_Int16 eHRel = pFS->eHRel;
2154  rReader.MiserableRTLGraphicsHack(nXPos, pFS->nWidth, pFS->eHAlign, eHRel);
2155 /*Above can all go when we have from left in rtl mode*/
2156  Put( SwFormatHoriOrient(nXPos, pFS->eHAlign, pFS->eHRel, pFS->bTogglePos ));
2157  Put( SwFormatVertOrient( pFS->nYPos, pFS->eVAlign, pFS->eVRel ) );
2158 
2159  if (pFS->nLeMgn || pFS->nRiMgn) // set borders
2160  Put(SvxLRSpaceItem(pFS->nLeMgn, pFS->nRiMgn, 0, 0, RES_LR_SPACE));
2161 
2162  if (pFS->nUpMgn || pFS->nLoMgn)
2163  Put(SvxULSpaceItem(pFS->nUpMgn, pFS->nLoMgn, RES_UL_SPACE));
2164 
2165  //we no longer need to hack around the header/footer problems
2166  SwFormatSurround aSurround(pFS->eSurround);
2167  if ( pFS->eSurround == css::text::WrapTextMode_DYNAMIC )
2168  aSurround.SetAnchorOnly( true );
2169  Put( aSurround );
2170 
2171  short aSizeArray[5]={0};
2172  SwWW8ImplReader::SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
2173 
2174  // the 5th parameter is always 0, thus we lose nothing due to the cast
2175 
2176  // #i27767#
2177  // #i35017# - constant name has changed
2179  text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) );
2180 
2181  if( bGraf )
2182  return;
2183 
2185  // adjust size
2186 
2187  //Ordinarily with frames, the border width and spacing is
2188  //placed outside the frame, making it larger. With these
2189  //types of frames, the left right thickness and space makes
2190  //it wider, but the top bottom spacing and border thickness
2191  //is placed inside.
2192  Put( SwFormatFrameSize( pFS->eHeightFix, pFS->nWidth +
2193  aSizeArray[WW8_LEFT] + aSizeArray[WW8_RIGHT],
2194  pFS->nHeight));
2195 }
2196 
2197 // WW8FlySet-ctor for character bound graphics
2199  const WW8_PIC& rPic, tools::Long nWidth, tools::Long nHeight )
2200  : SfxItemSet(rReader.m_rDoc.GetAttrPool(),svl::Items<RES_FRMATR_BEGIN,RES_FRMATR_END-1>{})
2201 {
2202  Init(rReader, pPaM);
2203 
2204  Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2205 
2206  short aSizeArray[5]={0};
2207  /*
2208  If we have set borders then in word the graphic is displaced from the left
2209  and top the width of the borders of those sides, and then the shadow
2210  itself is drawn to the bottom and right of the displaced graphic. In word
2211  the total size is that of the graphic plus the borders, plus the total
2212  shadow around all edges, for this translation the top and left shadow
2213  region is translated spacing around the graphic to those sides, and the
2214  bottom and right shadow size is added to the graphic size.
2215  */
2216  WW8_BRCVer9 brcVer9[4];
2217  for (int i = 0; i < 4; i++)
2218  brcVer9[i] = WW8_BRCVer9(rPic.rgbrc[i]);
2219  if (SwWW8ImplReader::SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
2220  {
2221  Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, 0, RES_LR_SPACE ) );
2222  Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
2223  aSizeArray[WW8_RIGHT]*=2;
2224  aSizeArray[WW8_BOT]*=2;
2225  }
2226 
2227  Put( SwFormatFrameSize( SwFrameSize::Fixed, nWidth+aSizeArray[WW8_LEFT]+
2228  aSizeArray[WW8_RIGHT], nHeight+aSizeArray[WW8_TOP]
2229  + aSizeArray[WW8_BOT]) );
2230 }
2231 
2232 void WW8FlySet::Init(const SwWW8ImplReader& rReader, const SwPaM* pPaM)
2233 {
2234  Reader::ResetFrameFormatAttrs(*this); // remove distance/borders
2235 
2236  Put(SvxLRSpaceItem(RES_LR_SPACE)); //inline writer ole2 objects start with 0.2cm l/r
2237  SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
2238 
2239  aAnchor.SetAnchor(pPaM->GetPoint());
2240  Put(aAnchor);
2241 
2242  //The horizontal default is on the baseline, the vertical is centered
2243  //around the character center it appears
2245  Put(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER,text::RelOrientation::CHAR));
2246  else
2247  Put(SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME));
2248 }
2249 
2251  : pCtrlStck(pStack),
2252  aChrSet(rDoc.GetAttrPool(), svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>{} ),
2253  aParSet(rDoc.GetAttrPool(), svl::Items<RES_PARATR_BEGIN, RES_PARATR_END - 1>{} )
2254 {
2255  //Close any open character properties and duplicate them inside the
2256  //first table cell
2257  size_t nCnt = pCtrlStck->size();
2258  for (size_t i=0; i < nCnt; ++i)
2259  {
2260  const SwFltStackEntry& rEntry = (*pCtrlStck)[ i ];
2261  if (rEntry.bOpen)
2262  {
2263  if (isCHRATR(rEntry.pAttr->Which()))
2264  {
2265  aChrSet.Put( *rEntry.pAttr );
2266 
2267  }
2268  else if (isPARATR(rEntry.pAttr->Which()))
2269  {
2270  aParSet.Put( *rEntry.pAttr );
2271  }
2272  }
2273  }
2274 }
2275 
2277 {
2278  for (const SfxItemSet* pSet : {&aChrSet, &aParSet})
2279  {
2280  if( pSet->Count() )
2281  {
2282  SfxItemIter aIter( *pSet );
2283  const SfxPoolItem* pItem = aIter.GetCurItem();
2284  do
2285  {
2286  pCtrlStck->NewAttr(rPos, *pItem);
2287  } while ((pItem = aIter.NextItem()));
2288  }
2289  }
2290 }
2291 
2293 {
2294  WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2295 
2296  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2297 
2298  // set Pam in FlyFrame
2299  const SwFormatContent& rContent = pFlyFormat->GetContent();
2300  OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
2301  m_pPaM->GetPoint()->nNode = rContent.GetContentIdx()->GetIndex() + 1;
2303 
2304  aDup.Insert(*m_pPaM->GetPoint());
2305 }
2306 
2308  const SwPosition &rPos, bool bTableJoin)
2309 {
2310  SwTwips nRetWidth = 0;
2311  if (!pFlyFormat)
2312  return nRetWidth;
2313  // Close all attributes, because otherwise attributes can appear
2314  // that extend out of Flys
2315  WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2316  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2317 
2318  /*
2319  #i1291
2320  If this fly frame consists entirely of one table inside a frame
2321  followed by an empty paragraph then we want to delete the empty
2322  paragraph so as to get the frame to autoshrink to the size of the
2323  table to emulate words behaviour closer.
2324  */
2325  if (bTableJoin)
2326  {
2327  const SwNodeIndex* pNodeIndex = pFlyFormat->GetContent().
2328  GetContentIdx();
2329  if (pNodeIndex)
2330  {
2331  SwNodeIndex aIdx( *pNodeIndex, 1 ),
2332  aEnd( *pNodeIndex->GetNode().EndOfSectionNode() );
2333 
2334  if (aIdx < aEnd)
2335  {
2336  if(aIdx.GetNode().IsTableNode())
2337  {
2338  SwTableNode *pTable = aIdx.GetNode().GetTableNode();
2339  aIdx = *aIdx.GetNode().EndOfSectionNode();
2340  ++aIdx;
2341  if ( (aIdx < aEnd) && aIdx.GetNode().IsTextNode() )
2342  {
2343  SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2344  ++aIdx;
2345  if (aIdx == aEnd && pNd && pNd->GetText().isEmpty())
2346  {
2347  //An extra pre-created by writer unused paragraph
2348 
2349  //delete after import is complete rather than now
2350  //to avoid the complication of managing uncommitted
2351  //ctrlstack properties that refer to it.
2353 
2354  SwTable& rTable = pTable->GetTable();
2355  SwFrameFormat* pTableFormat = rTable.GetFrameFormat();
2356 
2357  if (pTableFormat)
2358  {
2359  SwFormatFrameSize aSize = pTableFormat->GetFrameSize();
2361  aSize.SetHeight(MINLAY);
2362  pFlyFormat->SetFormatAttr(aSize);
2363  SwFormatHoriOrient aHori = pTableFormat->GetHoriOrient();
2364  // passing the table orientation of
2365  // LEFT_AND_WIDTH to the frame seems to
2366  // work better than FULL, especially if the
2367  // table width exceeds the page width, however
2368  // I am not brave enough to set it in all
2369  // instances
2370  pTableFormat->SetFormatAttr( SwFormatHoriOrient(0, ( aHori.GetHoriOrient() == text::HoriOrientation::LEFT_AND_WIDTH ) ? ::text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::FULL ) );
2371  nRetWidth = aSize.GetWidth();
2372  }
2373  }
2374  }
2375  }
2376  }
2377  }
2378  }
2379 
2380  *m_pPaM->GetPoint() = rPos;
2381  aDup.Insert(*m_pPaM->GetPoint());
2382  return nRetWidth;
2383 }
2384 
2385 std::unique_ptr<WW8FlyPara> SwWW8ImplReader::ConstructApo(const ApoTestResults &rApo,
2386  const WW8_TablePos *pTabPos)
2387 {
2388  OSL_ENSURE(rApo.HasFrame() || pTabPos,
2389  "If no frame found, *MUST* be in a table");
2390 
2391  std::unique_ptr<WW8FlyPara> pRet(new WW8FlyPara(m_bVer67, rApo.mpStyleApo));
2392 
2393  // find APO parameter and test for bGrafApo
2394  if (rApo.HasFrame())
2395  pRet->ReadFull(rApo.m_nSprm29, this);
2396 
2397  pRet->ApplyTabPos(pTabPos);
2398 
2399  if (pRet->IsEmpty())
2400  {
2401  pRet.reset();
2402  }
2403  return pRet;
2404 }
2405 
2407 {
2408  // Find the DCS (Drop Cap Specifier) for the paragraph
2409  // if does not exist or if the first three bits are 0
2410  // then there is no dropcap on the paragraph
2411  WW8PLCFx_Cp_FKP *pPap = m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr;
2412  if (pPap)
2413  {
2414  SprmResult aDCS;
2415  if (m_bVer67)
2416  aDCS = pPap->HasSprm(NS_sprm::v6::sprmPDcs);
2417  else
2418  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PDcs::val);
2419  if (aDCS.pSprm && aDCS.nRemainingData >= 2)
2420  {
2421  /*
2422  fdct short :3 0007 drop cap type
2423  0 no drop cap
2424  1 normal drop cap
2425  2 drop cap in margin
2426  */
2427  short nDCS = SVBT16ToUInt16(aDCS.pSprm);
2428  if (nDCS & 7)
2429  return true;
2430  }
2431  }
2432  return false;
2433 }
2434 
2435 bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *pTabPos)
2436 {
2437  m_xWFlyPara = ConstructApo(rApo, pTabPos);
2438  if (!m_xWFlyPara)
2439  return false;
2440 
2441  // <WW8SwFlyPara> constructor has changed - new 4th parameter
2442  // containing WW8 page top margin.
2443  m_xSFlyPara.reset(new WW8SwFlyPara( *m_pPaM, *this, *m_xWFlyPara,
2447 
2448  // If this paragraph is a Dropcap set the flag and we will deal with it later
2449  if (IsDropCap())
2450  {
2451  m_bDropCap = true;
2453  return false;
2454  }
2455 
2456  if (!m_xWFlyPara->bGrafApo)
2457  {
2458 
2459  // Within the GrafApo text attributes have to be ignored, because
2460  // they would apply to the following lines. The frame is only inserted
2461  // if it is not merely positioning a single image. If it is an image
2462  // frame, pWFlyPara and pSFlyPara are retained and the resulting
2463  // attributes applied to the image when inserting the image.
2464 
2465  WW8FlySet aFlySet(*this, m_xWFlyPara.get(), m_xSFlyPara.get(), false);
2466 
2467  if (pTabPos && pTabPos->bNoFly)
2468  {
2469  m_xSFlyPara->pFlyFormat = nullptr;
2470  }
2471  else
2472  {
2474  m_pPaM->GetPoint(), &aFlySet);
2475  OSL_ENSURE(m_xSFlyPara->pFlyFormat->GetAnchor().GetAnchorId() ==
2476  WW8SwFlyPara::eAnchor, "Not the anchor type requested!");
2477  }
2478 
2479  if (m_xSFlyPara->pFlyFormat)
2480  {
2481  if (!m_pDrawModel)
2482  GraphicCtor();
2483 
2484  SdrObject* pOurNewObject = CreateContactObject(m_xSFlyPara->pFlyFormat);
2485  m_xWWZOrder->InsertTextLayerObject(pOurNewObject);
2486  }
2487 
2488  if (RndStdIds::FLY_AS_CHAR != WW8SwFlyPara::eAnchor && m_xSFlyPara->pFlyFormat)
2489  {
2490  m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), m_xSFlyPara->pFlyFormat);
2491  }
2492 
2493  // remember Pos in body text
2494  m_xSFlyPara->xMainTextPos.reset(new SwPosition(*m_pPaM->GetPoint()));
2495 
2496  //remove fltanchors, otherwise they will be closed inside the
2497  //frame, which makes no sense, restore them after the frame is
2498  //closed
2499  m_xSFlyPara->xOldAnchorStck = std::move(m_xAnchorStck);
2501 
2502  if (m_xSFlyPara->pFlyFormat)
2503  MoveInsideFly(m_xSFlyPara->pFlyFormat);
2504 
2505  // 1) ReadText() is not called recursively because the length of
2506  // the Apo is unknown at that time, and ReadText() needs it.
2507  // 2) the CtrlStck is not re-created.
2508  // the Char attributes continue (trouble with Sw-attributes)
2509  // Para attributes must be reset at the end of every paragraph,
2510  // i.e. at the end of a paragraph there must not be para attributes
2511  // on the stack
2512  }
2513  return true;
2514 }
2515 
2516 void wwSectionManager::JoinNode(const SwPosition &rPos, const SwNode &rNode)
2517 {
2518  if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2519  maSegments.back().maStart.Assign(rNode);
2520 }
2521 
2522 bool SwWW8ImplReader::JoinNode(SwPaM &rPam, bool bStealAttr)
2523 {
2524  bool bRet = false;
2525  rPam.GetPoint()->nContent = 0; // go to start of paragraph
2526 
2527  SwNodeIndex aPref(rPam.GetPoint()->nNode, -1);
2528 
2529  if (SwTextNode* pNode = aPref.GetNode().GetTextNode())
2530  {
2531  m_aSectionManager.JoinNode(*rPam.GetPoint(), aPref.GetNode());
2532  rPam.GetPoint()->nNode = aPref;
2533  rPam.GetPoint()->nContent.Assign(pNode, pNode->GetText().getLength());
2534  if (bStealAttr)
2535  m_xCtrlStck->StealAttr(rPam.GetPoint()->nNode);
2536 
2537  if (m_pLastAnchorPos || m_pPreviousNode || (m_xSFlyPara && m_xSFlyPara->xMainTextPos))
2538  {
2539  SwNodeIndex aToBeJoined(aPref, 1);
2540 
2541  if (m_pLastAnchorPos)
2542  {
2543  //If the last anchor pos is here, then clear the anchor pos.
2544  //This "last anchor pos" is only used for fixing up the
2545  //positions of things anchored to page breaks and here
2546  //we are removing the last paragraph of a frame, so there
2547  //cannot be a page break at this point so we can
2548  //safely reset m_pLastAnchorPos to avoid any dangling
2549  //SwIndex's pointing into the deleted paragraph
2550  SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2551  if (aLastAnchorPos == aToBeJoined)
2552  m_pLastAnchorPos.reset();
2553  }
2554 
2555  if (m_pPreviousNode)
2556  {
2557  //If the drop character start pos is here, then clear it.
2558  SwNodeIndex aDropCharPos(*m_pPreviousNode);
2559  if (aDropCharPos == aToBeJoined)
2560  m_pPreviousNode = nullptr;
2561  }
2562 
2563  if (m_xSFlyPara && m_xSFlyPara->xMainTextPos)
2564  {
2565  // If an open apo pos is here, then clear it before
2566  // JoinNext destroys it
2567  SwNodeIndex aOpenApoPos(m_xSFlyPara->xMainTextPos->nNode);
2568  if (aOpenApoPos == aToBeJoined)
2569  m_xSFlyPara->xMainTextPos.reset();
2570  }
2571  }
2572 
2573  pNode->JoinNext();
2574 
2575  bRet = true;
2576  }
2577  return bRet;
2578 }
2579 
2580 //In auto-width word frames negative after-indent values are ignored
2582 {
2583  const SwNodeIndex* pSttNd = pFlyFormat->GetContent().GetContentIdx();
2584  if (!pSttNd)
2585  return;
2586 
2587  SwNodeIndex aIdx(*pSttNd, 1);
2588  SwNodeIndex aEnd(*pSttNd->GetNode().EndOfSectionNode());
2589  while (aIdx < aEnd)
2590  {
2591  SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2592  if (pNd)
2593  {
2594  const SvxLRSpaceItem& rLR = ItemGet<SvxLRSpaceItem>(*pNd, RES_LR_SPACE);
2595  if (rLR.GetRight() < 0)
2596  {
2597  SvxLRSpaceItem aLR(rLR);
2598  aLR.SetRight(0);
2599  pNd->SetAttr(aLR);
2600  }
2601  }
2602  ++aIdx;
2603  }
2604 }
2605 
2607 {
2608  OSL_ENSURE(m_xWFlyPara, "no pWFlyPara to close");
2609  if (!m_xWFlyPara)
2610  return;
2611  if (m_xWFlyPara->bGrafApo)
2612  {
2613  // image frame that has not been inserted: delete empty paragraph + attr
2614  JoinNode(*m_pPaM, true);
2615 
2616  }
2617  else
2618  {
2619  if (!m_xSFlyPara->xMainTextPos)
2620  {
2621  OSL_ENSURE(m_xSFlyPara->xMainTextPos, "StopApo: xMainTextPos is nullptr");
2622  return;
2623  }
2624 
2625  /*
2626  What we are doing with this temporary nodeindex is as follows: The
2627  stack of attributes normally only places them into the document when
2628  the current insertion point has passed them by. Otherwise the end
2629  point of the attribute gets pushed along with the insertion point. The
2630  insertion point is moved and the properties committed during
2631  MoveOutsideFly. We also may want to remove the final paragraph in the
2632  frame, but we need to wait until the properties for that frame text
2633  have been committed otherwise they will be lost. So we first get a
2634  handle to the last the filter inserted. After the attributes are
2635  committed, if that paragraph exists we join it with the para after it
2636  that comes with the frame by default so that as normal we don't end up
2637  with one more paragraph than we wanted.
2638  */
2639  SwNodeIndex aPref(m_pPaM->GetPoint()->nNode, -1);
2640 
2641  SwTwips nNewWidth =
2642  MoveOutsideFly(m_xSFlyPara->pFlyFormat, *m_xSFlyPara->xMainTextPos);
2643  if (nNewWidth)
2644  m_xSFlyPara->BoxUpWidth(nNewWidth);
2645 
2646  Color aBg(ColorTransparency, 0xFE, 0xFF, 0xFF, 0xFF); //Transparent by default
2647 
2648  SwTextNode* pNd = aPref.GetNode().GetTextNode();
2649  SwTextNode* pJoinNext = nullptr;
2650  if (pNd && m_xSFlyPara->pFlyFormat)
2651  {
2652  /*
2653  #i582#
2654  Take the last paragraph background colour and fill the frame with
2655  it. Otherwise, make it transparent, this appears to be how MSWord
2656  works
2657  */
2658  const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_BACKGROUND);
2659  const SvxBrushItem &rBrush = static_cast<const SvxBrushItem&>(rItm);
2660  if (rBrush.GetColor() != COL_AUTO)
2661  aBg = rBrush.GetColor();
2662 
2663  if (m_pLastAnchorPos)
2664  {
2665  //If the last anchor pos is here, then clear the anchor pos.
2666  //This "last anchor pos" is only used for fixing up the
2667  //positions of things anchored to page breaks and here
2668  //we are removing the last paragraph of a frame, so there
2669  //cannot be a page break at this point so we can
2670  //safely reset m_pLastAnchorPos to avoid any dangling
2671  //SwIndex's pointing into the deleted paragraph
2672  SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2673  SwNodeIndex aToBeJoined(aPref, 1);
2674  if (aLastAnchorPos == aToBeJoined)
2675  m_pLastAnchorPos.reset();
2676  }
2677 
2678  //Get rid of extra empty paragraph
2679  pJoinNext = pNd;
2680  }
2681 
2682  if (m_xSFlyPara->pFlyFormat)
2683  m_xSFlyPara->pFlyFormat->SetFormatAttr(SvxBrushItem(aBg, RES_BACKGROUND));
2684 
2686  if (pJoinNext)
2687  pJoinNext->JoinNext();
2688 
2689  m_xAnchorStck = std::move(m_xSFlyPara->xOldAnchorStck);
2690 
2691  // When inserting a graphic into the fly frame using the auto
2692  // function, the extension of the SW-fly has to be set
2693  // manually as the SW fly has no auto function to adjust the
2694  // frameĀ“s size.
2695  if (m_xSFlyPara->nNewNetWidth > MINFLY && m_xSFlyPara->pFlyFormat) // BoxUpWidth ?
2696  {
2697  tools::Long nW = m_xSFlyPara->nNewNetWidth;
2698  nW += m_xSFlyPara->nWidth - m_xSFlyPara->nNetWidth; // border for it
2699  m_xSFlyPara->pFlyFormat->SetFormatAttr(
2700  SwFormatFrameSize(m_xSFlyPara->eHeightFix, nW, m_xSFlyPara->nHeight));
2701  }
2702  /*
2703  Word set *no* width meaning it's an automatic width. The
2704  SwFlyPara reader will have already set a fallback width of the
2705  printable regions width, so we should reuse it. Despite the related
2706  problems with layout addressed with a hack in WW8FlyPara's constructor
2707  #i27204# Added AutoWidth setting. Left the old CalculateFlySize in place
2708  so that if the user unselects autowidth, the width doesn't max out
2709  */
2710  else if (!m_xWFlyPara->nSp28 && m_xSFlyPara->pFlyFormat)
2711  {
2712  using namespace sw::util;
2713  SfxItemSet aFlySet( m_xSFlyPara->pFlyFormat->GetAttrSet() );
2714 
2715  SwFormatFrameSize aSize(ItemGet<SwFormatFrameSize>(aFlySet, RES_FRM_SIZE));
2716 
2717  aFlySet.ClearItem(RES_FRM_SIZE);
2718 
2719  CalculateFlySize(aFlySet, m_xSFlyPara->xMainTextPos->nNode,
2720  m_xSFlyPara->nWidth);
2721 
2722  nNewWidth = ItemGet<SwFormatFrameSize>(aFlySet, RES_FRM_SIZE).GetWidth();
2723 
2724  aSize.SetWidth(nNewWidth);
2725  aSize.SetWidthSizeType(SwFrameSize::Variable);
2726 
2727  m_xSFlyPara->pFlyFormat->SetFormatAttr(aSize);
2728  }
2729 
2730  m_xSFlyPara->xMainTextPos.reset();
2731 // To create the SwFrames when inserting into an existing document, fltshell.cxx
2732 // will call pFlyFrame->MakeFrames() when setting the FltAnchor attribute
2733 
2734  }
2735 
2736  //#i8062#
2737  if (m_xSFlyPara && m_xSFlyPara->pFlyFormat)
2739 
2740  m_xSFlyPara.reset();
2741  m_xWFlyPara.reset();
2742 }
2743 
2744 // TestSameApo() returns if it's the same Apo or a different one
2746  const WW8_TablePos *pTabPos)
2747 {
2748  if (!m_xWFlyPara)
2749  {
2750  OSL_ENSURE(m_xWFlyPara, " Where is my pWFlyPara ? ");
2751  return true;
2752  }
2753 
2754  // We need to a full comparison (excepting borders) to identify all
2755  // combinations style/hard correctly. For this reason we create a
2756  // temporary WW8FlyPara (depending on if style or not), apply the
2757  // hard attributes and then compare.
2758 
2759  // For comparison
2760  WW8FlyPara aF(m_bVer67, rApo.mpStyleApo);
2761  // WWPara for current para
2762  if (rApo.HasFrame())
2763  aF.Read(rApo.m_nSprm29, m_xPlcxMan->GetPapPLCF());
2764  aF.ApplyTabPos(pTabPos);
2765 
2766  return aF == *m_xWFlyPara;
2767 }
2768 
2770  const bool bFirstLineOfStSet,
2771  const bool bLeftIndentSet )
2772 {
2773  if( m_bNoAttrImport ) // for ignoring styles during doc inserts
2774  return;
2775 
2776  if (m_pCurrentColl)
2777  {
2778  OSL_ENSURE(rAttr.Which() != RES_FLTR_REDLINE, "redline in style!");
2779  m_pCurrentColl->SetFormatAttr(rAttr);
2780  }
2781  else if (m_xCurrentItemSet)
2782  {
2783  m_xCurrentItemSet->Put(rAttr);
2784  }
2785  else if (rAttr.Which() == RES_FLTR_REDLINE)
2786  {
2787  m_xRedlineStack->open(*m_pPaM->GetPoint(), rAttr);
2788  }
2789  else
2790  {
2791  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), rAttr);
2792  // #i103711#
2793  if ( bFirstLineOfStSet )
2794  {
2795  const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2797  }
2798  // #i105414#
2799  if ( bLeftIndentSet )
2800  {
2801  const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2803  }
2804  }
2805 
2807  m_pPostProcessAttrsInfo->mItemSet.Put(rAttr);
2808 }
2809 
2810 // fetches attribute from FormatColl / Stack / Doc
2811 const SfxPoolItem* SwWW8ImplReader::GetFormatAttr( sal_uInt16 nWhich )
2812 {
2813  const SfxPoolItem* pRet = nullptr;
2814  if (m_pCurrentColl)
2815  pRet = &(m_pCurrentColl->GetFormatAttr(nWhich));
2816  else if (m_xCurrentItemSet)
2817  {
2818  pRet = m_xCurrentItemSet->GetItem(nWhich);
2819  if (!pRet)
2820  pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2821  if (!pRet)
2822  pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2823  }
2824  else if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2825  {
2826  pRet = m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), nWhich);
2827  if (!pRet)
2828  {
2829  if (m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_pFormat &&
2830  m_vColl[m_nCurrentColl].m_bColl)
2831  {
2832  pRet = &(m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(nWhich));
2833  }
2834  }
2835  if (!pRet)
2836  pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2837  if (!pRet)
2838  pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2839  }
2840  else
2841  pRet = m_xCtrlStck->GetFormatAttr(*m_pPaM->GetPoint(), nWhich);
2842  return pRet;
2843 }
2844 
2845 // The methods get as parameters the token id and the length of the following
2846 // parameters according to the table in WWScan.cxx.
2847 void SwWW8ImplReader::Read_Special(sal_uInt16, const sal_uInt8* pData, short nLen)
2848 {
2849  if (nLen < 1)
2850  {
2851  m_bSpec = false;
2852  return;
2853  }
2854  m_bSpec = ( *pData != 0 );
2855 }
2856 
2857 // Read_Obj is used for fObj and for fOle2 !
2858 void SwWW8ImplReader::Read_Obj(sal_uInt16 , const sal_uInt8* pData, short nLen)
2859 {
2860  if (nLen < 1)
2861  m_bObj = false;
2862  else
2863  {
2864  m_bObj = 0 != *pData;
2865 
2866  if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2867  {
2868  if (!m_aFieldStack.empty() && m_aFieldStack.back().mnFieldId == 56)
2869  {
2870  // For LINK fields, store the nObjLocFc value in the field entry
2871  m_aFieldStack.back().mnObjLocFc = m_nPicLocFc;
2872  }
2873  else
2874  {
2876  }
2877  }
2878  }
2879 }
2880 
2881 void SwWW8ImplReader::Read_PicLoc(sal_uInt16 , const sal_uInt8* pData, short nLen )
2882 {
2883  if (nLen < 4)
2884  {
2885  m_nPicLocFc = 0;
2886  m_bSpec = false; // Is this always correct?
2887  }
2888  else
2889  {
2890  m_nPicLocFc = SVBT32ToUInt32( pData );
2891  m_bSpec = true;
2892 
2893  if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2895  }
2896 }
2897 
2898 void SwWW8ImplReader::Read_POutLvl(sal_uInt16, const sal_uInt8* pData, short nLen )
2899 {
2900  if (nLen < 0)
2901  {
2903  return;
2904  }
2905 
2906  if (m_pCurrentColl != nullptr)
2907  {
2909  if (pSI && pSI->m_bColl && pSI->m_pFormat)
2910  {
2911  pSI->mnWW8OutlineLevel =
2912  static_cast< sal_uInt8 >( ( (pData && nLen >= 1) ? *pData : 0 ) );
2914  if (nLevel == 0)
2915  {
2916  SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pSI->m_pFormat);
2917  pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
2918  }
2920  }
2921  }
2922  else if (m_pPaM != nullptr)
2923  {
2924  const sal_uInt8 nOutlineLevel
2926  static_cast<sal_uInt8>(((pData && nLen >= 1) ? *pData : 0)));
2928  }
2929 }
2930 
2931 void SwWW8ImplReader::Read_Symbol(sal_uInt16, const sal_uInt8* pData, short nLen )
2932 {
2933  if( m_bIgnoreText )
2934  return;
2935 
2936  if (nLen < (m_bVer67 ? 3 : 4))
2937  {
2938  //otherwise disable after we print the char
2939  if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2940  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
2941  m_bSymbol = false;
2942  }
2943  else
2944  {
2945  // Make new Font-Attribute
2946  // (will be closed in SwWW8ImplReader::ReadChars() )
2947 
2948  //Will not be added to the charencoding stack, for styles the real
2949  //font setting will be put in as the styles charset, and for plain
2950  //text encoding for symbols is moot. Drawing boxes will check bSymbol
2951  //themselves so they don't need to add it to the stack either.
2952  if (SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_FONT))
2953  {
2954  SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CJK_FONT);
2955  SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CTL_FONT);
2956  if( m_bVer67 )
2957  {
2958  //convert single byte from MS1252 to Unicode
2959  m_cSymbol = OUString(
2960  reinterpret_cast<const char*>(pData+2), 1,
2961  RTL_TEXTENCODING_MS_1252).toChar();
2962  }
2963  else
2964  {
2965  //already is Unicode
2966  m_cSymbol = SVBT16ToUInt16( pData+2 );
2967  }
2968  m_bSymbol = true;
2969  }
2970  }
2971 }
2972 
2973 SwWW8StyInf *SwWW8ImplReader::GetStyle(sal_uInt16 nColl) const
2974 {
2975  return const_cast<SwWW8StyInf *>(nColl < m_vColl.size() ? &m_vColl[nColl] : nullptr);
2976 }
2977 
2978 // Read_BoldUsw for italic, bold, small caps, majuscule, struck out,
2979 // contour and shadow
2980 void SwWW8ImplReader::Read_BoldUsw( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
2981 {
2982  const int nContiguousWestern = 8;
2983  const int nWestern = nContiguousWestern + 1;
2984  const int nEastern = 2;
2985  const int nCTL = 2;
2986  const int nIds = nWestern + nEastern + nCTL;
2987  static const sal_uInt16 nEndIds[ nIds ] =
2988  {
2993 
2995 
2997 
2999  };
3000 
3001  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3002 
3003  sal_uInt8 nI;
3004  // the attribute number for "double strike-through" breaks rank
3005  if (NS_sprm::CFDStrike::val == nId)
3006  nI = nContiguousWestern; // The out of sequence western id
3007  else
3008  {
3009  // The contiguous western ids
3010  if (eVersion <= ww::eWW2)
3011  nI = static_cast< sal_uInt8 >(nId - 60);
3012  else if (eVersion < ww::eWW8)
3013  nI = static_cast< sal_uInt8 >(nId - NS_sprm::v6::sprmCFBold);
3014  else
3015  nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBold::val);
3016  }
3017 
3018  sal_uInt16 nMask = 1 << nI;
3019 
3020  if (nLen < 1)
3021  {
3022  if (nI < 2)
3023  {
3024  if (eVersion <= ww::eWW6)
3025  {
3026  // reset the CTL Weight and Posture, because they are the same as their
3027  // western equivalents in ww6
3028  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nEastern + nI ] );
3029  }
3030  // reset the CJK Weight and Posture, because they are the same as their
3031  // western equivalents in word
3032  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nI ] );
3033  }
3034  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nI ] );
3035  m_xCtrlStck->SetToggleAttr(nI, false);
3036  return;
3037  }
3038  // value: 0 = off, 1 = on, 128 = like style, 129 contrary to style
3039  bool bOn = *pData & 1;
3041  if (m_xPlcxMan && eVersion > ww::eWW2)
3042  {
3043  SprmResult aCharIstd =
3044  m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3045  if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3046  pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3047  }
3048 
3049  if( m_pCurrentColl ) // StyleDef -> remember flags
3050  {
3051  if (pSI)
3052  {
3053  // The style based on has Bit 7 set ?
3054  if (
3055  pSI->m_nBase < m_vColl.size() && (*pData & 0x80) &&
3056  (m_vColl[pSI->m_nBase].m_n81Flags & nMask)
3057  )
3058  {
3059  bOn = !bOn; // invert
3060  }
3061 
3062  if (bOn)
3063  pSI->m_n81Flags |= nMask; // set flag
3064  else
3065  pSI->m_n81Flags &= ~nMask; // delete flag
3066  }
3067  }
3068  else
3069  {
3070 
3071  // in text -> look at flags
3072  if( *pData & 0x80 ) // bit 7 set?
3073  {
3074  if (pSI && pSI->m_n81Flags & nMask) // and in StyleDef at ?
3075  bOn = !bOn; // then invert
3076  // remember on stack that this is a toggle-attribute
3077  m_xCtrlStck->SetToggleAttr(nI, true);
3078  }
3079  }
3080 
3081  SetToggleAttr( nI, bOn );
3082 }
3083 
3084 void SwWW8ImplReader::Read_Bidi(sal_uInt16, const sal_uInt8* pData, short nLen)
3085 {
3086  if (nLen < 1) //Property end
3087  {
3088  m_bBidi = false;
3090  }
3091  else //Property start
3092  {
3093  m_bBidi = true;
3094  sal_uInt8 nBidi = *pData;
3095  NewAttr( SfxInt16Item( RES_CHRATR_BIDIRTL, (nBidi!=0)? 1 : 0 ) );
3096  }
3097 }
3098 
3099 /*
3100  tdf#91916, #i8726, #i42685# there is an ambiguity
3101  around certain properties as to what they mean,
3102  which appears to be a problem with different versions
3103  of the file format where properties conflict, i.e.
3104 
3105 ooo40606-2.doc, magic is a699
3106  : 0x6f 0x4 0x0 0x71 0x4 0x0
3107 ooo40635-1.doc, magic is a699
3108  : 0x6f 0x4 0x0 0x71 0x4 0x0
3109 ooo31093/SIMPCHIN.doc, magic is a699
3110  : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3111  : 0x6f 0x5 0x0 0x70 0x5 0x0
3112 ooo31093/TRADCHIN.doc, magic is a699
3113  : 0x6f 0x1 0x0 0x70 0x0 0x0 0x71 0x1 0x0
3114 ooo31093/JAPANESE.doc, magic is a697
3115  : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3116 ooo31093/KOREAN.doc, magic is a698
3117  : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3118 ooo31093-1.doc, magic is a698
3119  : 0x6f 0x5 0x0 0x70 0x5 0x0
3120 ooo31093-1.doc, magic is a698
3121  : 0x6f 0x5 0x0 0x70 0x5 0x0
3122 
3123 meanwhile...
3124 
3125 ooo27954-1.doc, magic is a5dc
3126  : 0x6f 0x1 0x81 0x71 0x2 0x4 0x0 0x74 0x2 0x20 0x0
3127 
3128 ooo33251-1.doc, magic is a5dc
3129  : 0x6f 0x1 0x81 0x71 0x2 0x3 0x0 0x74 0x2 0x1c 0x0
3130 
3131 ---
3132 
3133 So we have the same sprm values, but different payloads, where
3134 the a5dc versions appear to use a len argument, followed by len
3135 bytes, while the a698<->a699 versions use a 2byte argument
3136 
3137 commit c2213db9ed70c1fd546482d22e36e4029c10aa45
3138 
3139  INTEGRATION: CWS tl28 (1.169.24); FILE MERGED
3140  2006/10/25 13:40:41 tl 1.169.24.2: RESYNC: (1.169-1.170); FILE MERGED
3141  2006/09/20 11:55:50 hbrinkm 1.169.24.1: #i42685# applied patch
3142 
3143 changed 0x6f and 0x70 from Read_BoldBiDiUsw to Read_FontCode for all versions.
3144 
3145 In the Word for Window 2 spec we have...
3146  78 //sprmCMajority
3147  80 //sprmCFBoldBi
3148  81 //sprmCFItalicBi
3149  82 //sprmCFtcBi
3150  83 //sprmClidBi
3151  84 //sprmCIcoBi
3152  85 //sprmCHpsBi
3153 as see in GetWW2SprmDispatcher, different numbers, but the sequence starts with
3154 the same sprmCMajority as appears before 0x6f in word 6/95
3155 
3156 I think the easiest explanation is that the CJK Word for Window 95, or whatever
3157 the product was went rogue, and did their own things with at least first three
3158 slots after sprmCMajority to do a different thing. I have no reason to think Tono
3159 was wrong with what they do in the a698<->a699 versions, but with magic
3160 a5dc they probably did mean sprmCFBoldBi, sprmCFItalicBi cause they have that 0x81
3161 pattern which has significance for those types of properties.
3162 */
3163 void SwWW8ImplReader::Read_AmbiguousSPRM(sal_uInt16 nId, const sal_uInt8* pData,
3164  short nLen)
3165 {
3166  if (m_xWwFib->m_wIdent >= 0xa697 && m_xWwFib->m_wIdent <= 0xa699)
3167  {
3168  Read_FontCode(nId, pData, nLen);
3169  }
3170  else
3171  {
3172  Read_BoldBiDiUsw(nId, pData, nLen);
3173  }
3174 }
3175 
3176 // Read_BoldUsw for BiDi Italic, Bold
3177 void SwWW8ImplReader::Read_BoldBiDiUsw(sal_uInt16 nId, const sal_uInt8* pData,
3178  short nLen)
3179 {
3180  static const sal_uInt16 nEndIds[2] =
3181  {
3183  };
3184 
3185  sal_uInt8 nI;
3186  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3187  if (eVersion <= ww::eWW2)
3188  nI = static_cast< sal_uInt8 >(nId - 80);
3189  else if (eVersion < ww::eWW8)
3190  nI = static_cast< sal_uInt8 >(nId - 111);
3191  else
3192  nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBoldBi::val);
3193 
3194  OSL_ENSURE(nI <= 1, "not happening");
3195  if (nI > 1)
3196  return;
3197 
3198  sal_uInt16 nMask = 1 << nI;
3199 
3200  if (nLen < 1)
3201  {
3202  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),nEndIds[nI]);
3203  m_xCtrlStck->SetToggleBiDiAttr(nI, false);
3204  return;
3205  }
3206  bool bOn = *pData & 1;
3208  if (m_xPlcxMan)
3209  {
3210  SprmResult aCharIstd =
3211  m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3212  if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3213  pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3214  }
3215 
3216  if (m_pCurrentColl && eVersion > ww::eWW2) // StyleDef -> remember flags
3217  {
3218  if (pSI)
3219  {
3220  if( pSI->m_nBase < m_vColl.size() // Style Based on
3221  && ( *pData & 0x80 ) // bit 7 set?
3222  && ( m_vColl[pSI->m_nBase].m_n81BiDiFlags & nMask ) ) // base mask?
3223  bOn = !bOn; // invert
3224 
3225  if( bOn )
3226  pSI->m_n81BiDiFlags |= nMask; // set flag
3227  else
3228  pSI->m_n81BiDiFlags &= ~nMask; // delete flag
3229  }
3230  }
3231  else
3232  {
3233 
3234  // in text -> look at flags
3235  if (*pData & 0x80) // Bit 7 set?
3236  {
3237  if (pSI && pSI->m_n81BiDiFlags & nMask) // and in StyleDef at ?
3238  bOn = !bOn; // then invert
3239  // remember on stack that this is a toggle-attribute
3240  m_xCtrlStck->SetToggleBiDiAttr(nI, true);
3241  }
3242  }
3243 
3244  SetToggleBiDiAttr(nI, bOn);
3245 }
3246 
3248 {
3249  switch (nAttrId)
3250  {
3251  case 0:
3252  {
3254  aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3255  NewAttr( aAttr );
3256  }
3257  break;
3258  case 1:
3259  {
3261  aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3262  NewAttr( aAttr );
3263  }
3264  break;
3265  default:
3266  OSL_ENSURE(false, "Unhandled unknown bidi toggle attribute");
3267  break;
3268 
3269  }
3270 }
3271 
3273 {
3274  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3275 
3276  switch (nAttrId)
3277  {
3278  case 0:
3279  {
3281  NewAttr( aAttr );
3282  aAttr.SetWhich( RES_CHRATR_CJK_WEIGHT );
3283  NewAttr( aAttr );
3284  if (eVersion <= ww::eWW6)
3285  {
3286  aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3287  NewAttr( aAttr );
3288  }
3289  }
3290  break;
3291  case 1:
3292  {
3294  NewAttr( aAttr );
3295  aAttr.SetWhich( RES_CHRATR_CJK_POSTURE );
3296  NewAttr( aAttr );
3297  if (eVersion <= ww::eWW6)
3298  {
3299  aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3300  NewAttr( aAttr );
3301  }
3302  }
3303  break;
3304  case 2:
3306  break;
3307  case 3:
3309  break;
3310  case 4:
3312  break;
3313  case 5:
3314  NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::SmallCaps
3315  : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3316  break;
3317  case 6:
3318  NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::Uppercase
3319  : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3320  break;
3321  case 7:
3323  break;
3324  case 8:
3326  : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ) );
3327  break;
3328  default:
3329  OSL_ENSURE(false, "Unhandled unknown toggle attribute");
3330  break;
3331  }
3332 }
3333 
3334 void SwWW8ImplReader::ChkToggleAttr_( sal_uInt16 nOldStyle81Mask,
3335  sal_uInt16 nNewStyle81Mask )
3336 {
3337  sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleAttrFlags();
3338  for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3339  {
3340  if (
3341  (i & nToggleAttrFlags) &&
3342  ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3343  )
3344  {
3345  SetToggleAttr(n, (i & nOldStyle81Mask));
3346  }
3347  }
3348 }
3349 
3350 void SwWW8ImplReader::ChkToggleBiDiAttr_( sal_uInt16 nOldStyle81Mask,
3351  sal_uInt16 nNewStyle81Mask )
3352 {
3353  sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleBiDiAttrFlags();
3354  for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3355  {
3356  if (
3357  (i & nToggleAttrFlags) &&
3358  ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3359  )
3360  {
3361  SetToggleBiDiAttr(n, (i & nOldStyle81Mask));
3362  }
3363  }
3364 }
3365 
3366 void SwWW8ImplReader::Read_SubSuper( sal_uInt16, const sal_uInt8* pData, short nLen )
3367 {
3368  if (nLen < 1)
3369  {
3371  return;
3372  }
3373 
3374  short nEs;
3375  sal_uInt8 nProp;
3376  switch( *pData )
3377  {
3378  case 1:
3379  nEs = DFLT_ESC_AUTO_SUPER;
3380  nProp = DFLT_ESC_PROP;
3381  break;
3382  case 2:
3383  nEs = DFLT_ESC_AUTO_SUB;
3384  nProp = DFLT_ESC_PROP;
3385  break;
3386  default:
3387  nEs = 0;
3388  nProp = 100;
3389  break;
3390  }
3392 }
3393 
3395 {
3396  /*
3397  For inline graphics and objects word has a hacked in feature to use
3398  subscripting to force the graphic into a centered position on the line, so
3399  we must check when applying sub/super to see if it the subscript range
3400  contains only a single graphic, and if that graphic is anchored as
3401  RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3402  */
3403  SwFrameFormat *pRet=nullptr;
3404  SwNodeIndex aBegin(rRegion.Start()->nNode);
3405  const sal_Int32 nBegin(rRegion.Start()->nContent.GetIndex());
3406  SwNodeIndex aEnd(rRegion.End()->nNode);
3407  const sal_Int32 nEnd(rRegion.End()->nContent.GetIndex());
3408  const SwTextNode* pTNd;
3409  const SwTextAttr* pTFlyAttr;
3410  if (
3411  aBegin == aEnd && nBegin == nEnd - 1 &&
3412  nullptr != (pTNd = aBegin.GetNode().GetTextNode()) &&
3413  nullptr != (pTFlyAttr = pTNd->GetTextAttrForCharAt(nBegin, RES_TXTATR_FLYCNT))
3414  )
3415  {
3416  const SwFormatFlyCnt& rFly = pTFlyAttr->GetFlyCnt();
3417  SwFrameFormat *pFlyFormat = rFly.GetFrameFormat();
3418  if (pFlyFormat &&
3419  (RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()))
3420  {
3421  pRet = pFlyFormat;
3422  }
3423  }
3424  return pRet;
3425 }
3426 
3428 {
3429  /*
3430  For inline graphics and objects word has a hacked in feature to use
3431  subscripting to force the graphic into a centered position on the line, so
3432  we must check when applying sub/super to see if it the subscript range
3433  contains only a single graphic, and if that graphic is anchored as
3434  RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3435  */
3436  bool bIsGraphicPlacementHack = false;
3437  sal_uInt16 nPos;
3438  if (m_xCtrlStck->GetFormatStackAttr(RES_CHRATR_ESCAPEMENT, &nPos))
3439  {
3440  SwPaM aRegion(*m_pPaM->GetPoint());
3441 
3442  SwFltPosition aMkPos((*m_xCtrlStck)[nPos].m_aMkPos);
3443  SwFltPosition aPtPos(*m_pPaM->GetPoint());
3444 
3445  SwFrameFormat *pFlyFormat = nullptr;
3447  && nullptr != (pFlyFormat = ContainsSingleInlineGraphic(aRegion)))
3448  {
3449  m_xCtrlStck->DeleteAndDestroy(nPos);
3450  pFlyFormat->SetFormatAttr(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER, text::RelOrientation::CHAR));
3451  bIsGraphicPlacementHack = true;
3452  }
3453  }
3454  return bIsGraphicPlacementHack;
3455 }
3456 
3457 void SwWW8ImplReader::Read_SubSuperProp( sal_uInt16, const sal_uInt8* pData, short nLen )
3458 {
3459  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3460 
3461  if (nLen < (eVersion <= ww::eWW2 ? 1 : 2))
3462  {
3465  return;
3466  }
3467 
3468  // if the fontsize for these characters is specified, make sure it is updated first
3469  if ( m_xPlcxMan )
3470  {
3471  const sal_uInt16 nFontsizeID = m_bVer67 ? NS_sprm::v6::sprmCHps : NS_sprm::CHps::val;
3472  const SprmResult aFontsize = m_xPlcxMan->GetChpPLCF()->HasSprm( nFontsizeID, /*bFindFirst=*/false );
3473  if ( aFontsize.pSprm && aFontsize.nRemainingData )
3474  Read_FontSize(nFontsizeID, aFontsize.pSprm, aFontsize.nRemainingData);
3475  }
3476 
3477  // font position in HalfPoints
3478  short nPos = eVersion <= ww::eWW2 ? static_cast< sal_Int8 >( *pData ) : SVBT16ToInt16( pData );
3479  sal_Int32 nPos2 = nPos * ( 10 * 100 ); // HalfPoints in 100 * tw
3480  const SvxFontHeightItem* pF
3481  = static_cast<const SvxFontHeightItem*>(GetFormatAttr(RES_CHRATR_FONTSIZE));
3482  OSL_ENSURE(pF, "Expected to have the fontheight available here");
3483 
3484  // #i59022: Check ensure nHeight != 0. Div by zero otherwise.
3485  sal_Int32 nHeight = 240;
3486  if (pF != nullptr && pF->GetHeight() != 0)
3487  nHeight = pF->GetHeight();
3488  nPos2 /= nHeight; // ... now in % (rounded)
3489  if( nPos2 > MAX_ESC_POS )
3490  nPos2 = MAX_ESC_POS;
3491  if( nPos2 < -MAX_ESC_POS )
3492  nPos2 = -MAX_ESC_POS;
3493  SvxEscapementItem aEs( static_cast<short>(nPos2), 100, RES_CHRATR_ESCAPEMENT );
3494  NewAttr( aEs );
3495 }
3496 
3497 void SwWW8ImplReader::Read_Underline( sal_uInt16, const sal_uInt8* pData, short nLen )
3498 {
3499  FontLineStyle eUnderline = LINESTYLE_NONE;
3500  bool bWordLine = false;
3501  if (pData && nLen)
3502  {
3503  // Parameter: 0 = none, 1 = single, 2 = by Word,
3504  // 3 = double, 4 = dotted, 5 = hidden
3505  // 6 = thick, 7 = dash, 8 = dot(not used)
3506  // 9 = dotdash 10 = dotdotdash 11 = wave
3507  switch( *pData )
3508  {
3509  case 2: bWordLine = true;
3510  [[fallthrough]];
3511  case 1: eUnderline = LINESTYLE_SINGLE; break;
3512  case 3: eUnderline = LINESTYLE_DOUBLE; break;
3513  case 4: eUnderline = LINESTYLE_DOTTED; break;
3514  case 7: eUnderline = LINESTYLE_DASH; break;
3515  case 9: eUnderline = LINESTYLE_DASHDOT; break;
3516  case 10:eUnderline = LINESTYLE_DASHDOTDOT; break;
3517  case 6: eUnderline = LINESTYLE_BOLD; break;
3518  case 11:eUnderline = LINESTYLE_WAVE; break;
3519  case 20:eUnderline = LINESTYLE_BOLDDOTTED; break;
3520  case 23:eUnderline = LINESTYLE_BOLDDASH; break;
3521  case 39:eUnderline = LINESTYLE_LONGDASH; break;
3522  case 55:eUnderline = LINESTYLE_BOLDLONGDASH; break;
3523  case 25:eUnderline = LINESTYLE_BOLDDASHDOT; break;
3524  case 26:eUnderline = LINESTYLE_BOLDDASHDOTDOT;break;
3525  case 27:eUnderline = LINESTYLE_BOLDWAVE; break;
3526  case 43:eUnderline = LINESTYLE_DOUBLEWAVE; break;
3527  }
3528  }
3529 
3530  // if necessary, mix up stack and exit!
3531  if (nLen < 1)
3532  {
3535  }
3536  else
3537  {
3539  if( bWordLine )
3541  }
3542 }
3543 
3544 /*
3545 //The last three vary, measurements, rotation ? ?
3546 NoBracket 78 CA 06 - 02 00 00 02 34 52
3547 () 78 CA 06 - 02 01 00 02 34 52
3548 [] 78 CA 06 - 02 02 00 02 34 52
3549 <> 78 CA 06 - 02 03 00 02 34 52
3550 {} 78 CA 06 - 02 04 00 02 34 52
3551 */
3553  short nLen )
3554 {
3555  if (nLen < 0) // close the tag
3556  {
3558  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ROTATE );
3559  }
3560  else if( pData && 6 == nLen )
3561  {
3562  switch( *pData )
3563  {
3564  case 2: // double line
3565  {
3566  sal_Unicode cStt = 0, cEnd = 0;
3567  switch( SVBT16ToUInt16( pData+1 ) )
3568  {
3569  case 1: cStt = '('; cEnd = ')'; break;
3570  case 2: cStt = '['; cEnd = ']'; break;
3571  case 3: cStt = '<'; cEnd = '>'; break;
3572  case 4: cStt = '{'; cEnd = '}'; break;
3573  }
3574  NewAttr( SvxTwoLinesItem( true, cStt, cEnd, RES_CHRATR_TWO_LINES ));
3575  }
3576  break;
3577 
3578  case 1: // rotated characters
3579  {
3580  bool bFitToLine = 0 != *(pData+1);
3581  NewAttr( SvxCharRotateItem( 900_deg10, bFitToLine, RES_CHRATR_ROTATE ));
3582  }
3583  break;
3584  }
3585  }
3586 }
3587 
3588 void SwWW8ImplReader::Read_TextColor( sal_uInt16, const sal_uInt8* pData, short nLen )
3589 {
3590  //Has newer colour variant, ignore this old variant
3591  if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CCv::val).pSprm)
3592  return;
3593 
3594  if (nLen < 1)
3595  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3596  else
3597  {
3598  sal_uInt8 b = *pData; // parameter: 0 = Auto, 1..16 colors
3599 
3600  if( b > 16 ) // unknown -> Black
3601  b = 0;
3602 
3604  if (m_pCurrentColl && m_xStyles)
3605  m_xStyles->mbTextColChanged = true;
3606  }
3607 }
3608 
3609 void SwWW8ImplReader::Read_TextForeColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3610 {
3611  if (nLen < 4)
3612  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3613  else
3614  {
3615  Color aColor = msfilter::util::BGRToRGB(SVBT32ToUInt32(pData));
3616 
3617  // At least when transparency is 0xff and the color is black, Word renders that as black.
3618  if (aColor.IsTransparent() && aColor != COL_AUTO)
3619  {
3620  aColor.SetAlpha(255);
3621  }
3622 
3624  if (m_pCurrentColl && m_xStyles)
3625  m_xStyles->mbTextColChanged = true;
3626  }
3627 }
3628 
3629 void SwWW8ImplReader::Read_UnderlineColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3630 {
3631  if (nLen < 0)
3632  {
3633  //because the UnderlineColor is not a standalone attribute in SW, it belongs to the underline attribute.
3634  //And, the .doc file stores attributes separately, this attribute ends here, the "underline"
3635  //attribute also terminates (if the character next owns underline, that will be a new underline attribute).
3636  //so nothing is left to be done here.
3637  return;
3638  }
3639  else
3640  {
3641  if ( m_pCurrentColl ) //importing style
3642  {
3643  if( SfxItemState::SET == m_pCurrentColl->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3644  {
3645  if (nLen >= 4)
3646  {
3647  const SwAttrSet& aSet = m_pCurrentColl->GetAttrSet();
3648  std::unique_ptr<SvxUnderlineItem> pUnderline(aSet.Get(RES_CHRATR_UNDERLINE, false).Clone());
3649  pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3650  m_pCurrentColl->SetFormatAttr( *pUnderline );
3651  }
3652  }
3653  }
3654  else if (m_xCurrentItemSet)
3655  {
3656  if ( SfxItemState::SET == m_xCurrentItemSet->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3657  {
3658  if (nLen >= 4)
3659  {
3660  std::unique_ptr<SvxUnderlineItem> pUnderline(m_xCurrentItemSet->Get(RES_CHRATR_UNDERLINE, false).Clone());
3661  pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3662  m_xCurrentItemSet->Put( std::move(pUnderline) );
3663  }
3664  }
3665  }
3666  else
3667  {
3668  SvxUnderlineItem* pUnderlineAttr = const_cast<SvxUnderlineItem*>(static_cast<const SvxUnderlineItem*>(m_xCtrlStck->GetOpenStackAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE )));
3669  if (pUnderlineAttr && nLen >= 4)
3670  pUnderlineAttr->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32( pData ) ));
3671  }
3672  }
3673 }
3674 bool SwWW8ImplReader::GetFontParams( sal_uInt16 nFCode, FontFamily& reFamily,
3675  OUString& rName, FontPitch& rePitch, rtl_TextEncoding& reCharSet )
3676 {
3677  // the definitions that are the base for these tables are in windows.h
3678  static const FontPitch ePitchA[] =
3679  {
3681  };
3682 
3683  static const FontFamily eFamilyA[] =
3684  {
3687  };
3688 
3689  const WW8_FFN* pF = m_xFonts->GetFont( nFCode ); // Info for it
3690  if( !pF ) // font number unknown ?
3691  return false; // then ignore
3692 
3693  rName = pF->sFontname;
3694 
3695  // pF->prg : Pitch
3696  rePitch = ePitchA[pF->aFFNBase.prg];
3697 
3698  // pF->chs: Charset
3699  if( 77 == pF->aFFNBase.chs ) // Mac font in Mac Charset or
3700  reCharSet = m_eTextCharSet; // translated to ANSI charset
3701  else
3702  {
3703  // #i52786#, for word 67 we'll assume that ANSI is basically invalid,
3704  // might be true for (above) mac as well, but would need a mac example
3705  // that exercises this to be sure
3706  if (m_bVer67 && pF->aFFNBase.chs == 0)
3707  reCharSet = RTL_TEXTENCODING_DONTKNOW;
3708  else
3709  reCharSet = rtl_getTextEncodingFromWindowsCharset(pF->aFFNBase.chs);
3710  }
3711 
3712  // make sure Font Family Code is set correctly
3713  // at least for the most important fonts
3714  // ( might be set wrong when Doc was not created by
3715  // Winword but by third party program like Applixware... )
3716  if (rName.startsWithIgnoreAsciiCase("Tms Rmn") ||
3717  rName.startsWithIgnoreAsciiCase("Timmons") ||
3718  rName.startsWithIgnoreAsciiCase("CG Times") ||
3719  rName.startsWithIgnoreAsciiCase("MS Serif") ||
3720  rName.startsWithIgnoreAsciiCase("Garamond") ||
3721  rName.startsWithIgnoreAsciiCase("Times Roman") ||
3722  rName.startsWithIgnoreAsciiCase("Times New Roman"))
3723  {
3724  reFamily = FAMILY_ROMAN;
3725  }
3726  else if (rName.startsWithIgnoreAsciiCase("Helv") ||
3727  rName.startsWithIgnoreAsciiCase("Arial") ||
3728  rName.startsWithIgnoreAsciiCase("Univers") ||
3729  rName.startsWithIgnoreAsciiCase("LinePrinter") ||
3730  rName.startsWithIgnoreAsciiCase("Lucida Sans") ||
3731  rName.startsWithIgnoreAsciiCase("Small Fonts") ||
3732  rName.startsWithIgnoreAsciiCase("MS Sans Serif"))
3733  {
3734  reFamily = FAMILY_SWISS;
3735  }
3736  else
3737  {
3738  reFamily = eFamilyA[pF->aFFNBase.ff];
3739  }
3740 
3741  return true;
3742 }
3743 
3744 bool SwWW8ImplReader::SetNewFontAttr(sal_uInt16 nFCode, bool bSetEnums,
3745  sal_uInt16 nWhich)
3746 {
3747  FontFamily eFamily;
3748  OUString aName;
3749  FontPitch ePitch;
3750  rtl_TextEncoding eSrcCharSet;
3751 
3752  if( !GetFontParams( nFCode, eFamily, aName, ePitch, eSrcCharSet ) )
3753  {
3754  //If we fail (and are not doing a style) then put something into the
3755  //character encodings stack anyway so that the property end that pops
3756  //off the stack will keep in sync
3757  if (!m_pCurrentColl && IsListOrDropcap())
3758  {
3759  if (nWhich == RES_CHRATR_CJK_FONT)
3760  {
3761  if (!m_aFontSrcCJKCharSets.empty())
3762  {
3763  eSrcCharSet = m_aFontSrcCJKCharSets.top();
3764  }
3765  else
3766  {
3767  eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3768  }
3769 
3770  m_aFontSrcCJKCharSets.push(eSrcCharSet);
3771  }
3772  else
3773  {
3774  if (!m_aFontSrcCharSets.empty())
3775  {
3776  eSrcCharSet = m_aFontSrcCharSets.top();
3777  }
3778  else
3779  {
3780  eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3781  }
3782 
3783  m_aFontSrcCharSets.push(eSrcCharSet);
3784  }
3785  }
3786  return false;
3787  }
3788 
3789  rtl_TextEncoding eDstCharSet = eSrcCharSet;
3790 
3791  SvxFontItem aFont( eFamily, aName, OUString(), ePitch, eDstCharSet, nWhich);
3792 
3793  if( bSetEnums )
3794  {
3795  if( m_pCurrentColl && m_nCurrentColl < m_vColl.size() ) // StyleDef
3796  {
3797  switch(nWhich)
3798  {
3799  default:
3800  case RES_CHRATR_FONT:
3801  m_vColl[m_nCurrentColl].m_eLTRFontSrcCharSet = eSrcCharSet;
3802  break;
3803  case RES_CHRATR_CTL_FONT:
3804  m_vColl[m_nCurrentColl].m_eRTLFontSrcCharSet = eSrcCharSet;
3805  break;
3806  case RES_CHRATR_CJK_FONT:
3807  m_vColl[m_nCurrentColl].m_eCJKFontSrcCharSet = eSrcCharSet;
3808  break;
3809  }
3810  }
3811  else if (IsListOrDropcap())
3812  {
3813  //Add character text encoding to stack
3814  if (nWhich == RES_CHRATR_CJK_FONT)
3815  m_aFontSrcCJKCharSets.push(eSrcCharSet);
3816  else
3817  m_aFontSrcCharSets.push(eSrcCharSet);
3818  }
3819  }
3820 
3821  NewAttr( aFont ); // ...and insert
3822 
3823  return true;
3824 }
3825 
3827 {
3828  OSL_ENSURE(!m_aFontSrcCharSets.empty(),"no charset to remove");
3829  if (!m_aFontSrcCharSets.empty())
3830  m_aFontSrcCharSets.pop();
3831 }
3832 
3834 {
3835  OSL_ENSURE(!m_aFontSrcCJKCharSets.empty(),"no charset to remove");
3836  if (!m_aFontSrcCJKCharSets.empty())
3837  m_aFontSrcCJKCharSets.pop();
3838 }
3839 
3840 void SwWW8ImplReader::openFont(sal_uInt16 nFCode, sal_uInt16 nId)
3841 {
3842  if (SetNewFontAttr(nFCode, true, nId) && m_pCurrentColl && m_xStyles)
3843  {
3844  // remember for simulating default font
3845  if (RES_CHRATR_CJK_FONT == nId)
3846  m_xStyles->mbCJKFontChanged = true;
3847  else if (RES_CHRATR_CTL_FONT == nId)
3848  m_xStyles->mbCTLFontChanged = true;
3849  else
3850  m_xStyles->mbFontChanged = true;
3851  }
3852 }
3853 
3854 void SwWW8ImplReader::closeFont(sal_uInt16 nId)
3855 {
3856  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3857  if (nId == RES_CHRATR_CJK_FONT)
3859  else
3860  ResetCharSetVars();
3861 }
3862 
3863 /*
3864  Turn font on or off:
3865 */
3866 void SwWW8ImplReader::Read_FontCode( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3867 {
3868  //Note: this function needs to be able to run multiple times on the same data.
3869  //It is called by Read_SubSuperProp to ensure that the current fontsize is known.
3870 
3871  if (m_bSymbol) // if bSymbol, the symbol's font
3872  return;
3873 
3874 // (see sprmCSymbol) is valid!
3875  switch( nId )
3876  {
3877  case 113: //WW7
3878  case NS_sprm::CRgFtc2::val: //"Other" font, override with BiDi if it exists
3879  case NS_sprm::CFtcBi::val: //BiDi Font
3880  nId = RES_CHRATR_CTL_FONT;
3881  break;
3882  case NS_sprm::v6::sprmCFtc: //WW6
3883  case 111: //WW7
3884  case NS_sprm::CRgFtc0::val:
3885  nId = RES_CHRATR_FONT;
3886  break;
3887  case 112: //WW7
3888  case NS_sprm::CRgFtc1::val:
3889  nId = RES_CHRATR_CJK_FONT;
3890  break;
3891  default:
3892  return ;
3893  }
3894 
3895  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3896 
3897  if (nLen < 2) // end of attribute
3898  {
3899  if (eVersion <= ww::eWW6)
3900  {
3903  }
3904  closeFont(nId);
3905  }
3906  else
3907  {
3908  sal_uInt16 nFCode = SVBT16ToUInt16( pData ); // font number
3909  openFont(nFCode, nId);
3910  if (eVersion <= ww::eWW6)
3911  {
3912  openFont(nFCode, RES_CHRATR_CJK_FONT);
3913  openFont(nFCode, RES_CHRATR_CTL_FONT);
3914  }
3915  }
3916 }
3917 
3918 void SwWW8ImplReader::Read_FontSize( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3919 {
3920  switch( nId )
3921  {
3922  case 74: // WW2
3923  case NS_sprm::v6::sprmCHps:
3924  case NS_sprm::CHps::val:
3925  nId = RES_CHRATR_FONTSIZE;
3926  break;
3927  case 85: //WW2
3928  case 116: //WW7
3929  case NS_sprm::CHpsBi::val:
3931  break;
3932  default:
3933  return ;
3934  }
3935 
3936  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3937 
3938  if (nLen < (eVersion <= ww::eWW2 ? 1 : 2)) // end of attribute
3939  {
3940  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3941  if (eVersion <= ww::eWW6) // reset additionally the CTL size
3943  if (RES_CHRATR_FONTSIZE == nId) // reset additionally the CJK size
3945  }
3946  else
3947  {
3948  // Font-Size in half points e.g. 10 = 1440 / ( 72 * 2 )
3949  sal_uLong nFSize = eVersion <= ww::eWW2 ? *pData : SVBT16ToUInt16(pData);
3950  nFSize*= 10;
3951 
3952  SvxFontHeightItem aSz( nFSize, 100, nId );
3953  NewAttr( aSz );
3954  if (RES_CHRATR_FONTSIZE == nId) // set additionally the CJK size
3955  {
3956  aSz.SetWhich( RES_CHRATR_CJK_FONTSIZE );
3957  NewAttr( aSz );
3958  }
3959  if (eVersion <= ww::eWW6) // set additionally the CTL size
3960  {
3961  aSz.SetWhich( RES_CHRATR_CTL_FONTSIZE );
3962  NewAttr( aSz );
3963  }
3964  if (m_pCurrentColl && m_xStyles) // Style-Def ?
3965  {
3966  // remember for simulating default font size
3967  if (nId == RES_CHRATR_CTL_FONTSIZE)
3968  m_xStyles->mbFCTLSizeChanged = true;
3969  else
3970  {
3971  m_xStyles->mbFSizeChanged = true;
3972  if (eVersion <= ww::eWW6)
3973  m_xStyles->mbFCTLSizeChanged= true;
3974  }
3975  }
3976  }
3977 }
3978 
3979 void SwWW8ImplReader::Read_CharSet(sal_uInt16 , const sal_uInt8* pData, short nLen)
3980 {
3981  if (nLen < 1)
3982  { // end of attribute
3983  m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
3984  return;
3985  }
3986  sal_uInt8 nfChsDiff = *pData;
3987 
3988  if (nfChsDiff && nLen >= 2)
3989  m_eHardCharSet = rtl_getTextEncodingFromWindowsCharset( *(pData + 1) );
3990  else
3991  m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
3992 }
3993 
3994 void SwWW8ImplReader::Read_Language( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3995 {
3996  switch( nId )
3997  {
3998  case NS_sprm::v6::sprmCLid:
4000  case NS_sprm::CRgLid0::val:
4001  nId = RES_CHRATR_LANGUAGE;
4002  break;
4004  case NS_sprm::CRgLid1::val:
4006  break;
4007  case 83: // WW2
4008  case 114: // WW7
4009  case NS_sprm::CLidBi::val:
4011  break;
4012  default:
4013  return;
4014  }
4015 
4016  if (nLen < 2) // end of attribute
4017  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4018  else
4019  {
4020  sal_uInt16 nLang = SVBT16ToUInt16( pData ); // Language-Id
4021  NewAttr(SvxLanguageItem(LanguageType(nLang), nId));
4022  }
4023 }
4024 
4025 /*
4026  Turn on character style:
4027 */
4028 void SwWW8ImplReader::Read_CColl( sal_uInt16, const sal_uInt8* pData, short nLen )
4029 {
4030  if (nLen < 2) // end of attribute
4031  {
4032  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_TXTATR_CHARFMT );
4033  m_nCharFormat = -1;
4034  return;
4035  }
4036  sal_uInt16 nId = SVBT16ToUInt16( pData ); // Style-Id (NOT Sprm-Id!)
4037 
4038  if( nId >= m_vColl.size() || !m_vColl[nId].m_pFormat // invalid Id?
4039  || m_vColl[nId].m_bColl ) // or paragraph style?
4040  return; // then ignore
4041 
4042  // if current on loading a TOX field, and current trying to apply a hyperlink character style,
4043  // just ignore. For the hyperlinks inside TOX in MS Word is not same with a common hyperlink
4044  // Character styles: without underline and blue font color. And such type style will be applied in others
4045  // processes.
4046  if (m_bLoadingTOXCache && m_vColl[nId].GetWWStyleId() == ww::stiHyperlink)
4047  {
4048  return;
4049  }
4050 
4051  NewAttr( SwFormatCharFormat( static_cast<SwCharFormat*>(m_vColl[nId].m_pFormat) ) );
4052  m_nCharFormat = static_cast<short>(nId);
4053 }
4054 
4055 /*
4056  Narrower or wider than normal:
4057 */
4058 void SwWW8ImplReader::Read_Kern( sal_uInt16, const sal_uInt8* pData, short nLen )
4059 {
4060  if (nLen < 2) // end of attribute
4061  {
4062  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_KERNING );
4063  return;
4064  }
4065  sal_Int16 nKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4067 }
4068 
4069 void SwWW8ImplReader::Read_FontKern( sal_uInt16, const sal_uInt8* pData, short nLen )
4070 {
4071  if (nLen < 2) // end of attribute
4072  {
4074  return;
4075  }
4076  sal_Int16 nAutoKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4077  NewAttr(SvxAutoKernItem(static_cast<bool>(nAutoKern), RES_CHRATR_AUTOKERN));
4078 }
4079 
4080 void SwWW8ImplReader::Read_CharShadow( sal_uInt16, const sal_uInt8* pData, short nLen )
4081 {
4082  //Has newer colour variant, ignore this old variant
4083  if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CShd::val).pSprm)
4084  return;
4085 
4086  if (nLen < 2)
4087  {
4089  }
4090  else
4091  {
4092  WW8_SHD aSHD;
4093  aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4094  SwWW8Shade aSh( m_bVer67, aSHD );
4095 
4097 
4098  // Add a marker to the grabbag indicating that character background was imported from MSO shading
4099  SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4100  std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4101  rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::makeAny(true)));
4102  NewAttr(aGrabBag);
4103  }
4104 }
4105 
4106 void SwWW8ImplReader::Read_TextBackColor(sal_uInt16, const sal_uInt8* pData, short nLen )
4107 {
4108  if (nLen <= 0)
4109  {
4111  }
4112  else
4113  {
4114  OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4115  if (nLen != 10)
4116  return;
4117  Color aColour(ExtractColour(pData, m_bVer67));
4119 
4120  // Add a marker to the grabbag indicating that character background was imported from MSO shading
4121  SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4122  std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4123  rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::makeAny(true)));
4124  NewAttr(aGrabBag);
4125  }
4126 }
4127 
4128 void SwWW8ImplReader::Read_CharHighlight(sal_uInt16, const sal_uInt8* pData, short nLen)
4129 {
4130  // MS Word completely ignores character highlighting in character styles.
4132  return;
4133 
4134  if (nLen < 1)
4135  {
4137  }
4138  else
4139  {
4140  sal_uInt8 b = *pData; // Parameter: 0 = Auto, 1..16 colors
4141 
4142  if( b > 16 ) // invalid -> Black
4143  b = 0; // Auto -> Black
4144 
4145  Color aCol(GetCol(b));
4147  }
4148 }
4149 
4150 void SwWW8ImplReader::Read_NoLineNumb(sal_uInt16 , const sal_uInt8* pData, short nLen)
4151 {
4152  if (nLen < 0) // end of attribute
4153  {
4154  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_LINENUMBER );
4155  return;
4156  }
4157  SwFormatLineNumber aLN;
4158  if (const SwFormatLineNumber* pLN
4159  = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
4160  {
4161  aLN.SetStartValue( pLN->GetStartValue() );
4162  }
4163 
4164  aLN.SetCountLines(pData && nLen >= 1 && (0 == *pData));
4165  NewAttr( aLN );
4166 }
4167 
4168 static bool lcl_HasExplicitLeft(const WW8PLCFMan *pPlcxMan, bool bVer67)
4169 {
4170  WW8PLCFx_Cp_FKP *pPap = pPlcxMan ? pPlcxMan->GetPapPLCF() : nullptr;
4171  if (pPap)
4172  {
4173  if (bVer67)
4174  return pPap->HasSprm(NS_sprm::v6::sprmPDxaLeft).pSprm;
4175  else
4177  }
4178  return false;
4179 }
4180 
4181 // Sprm 16, 17
4182 void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4183 {
4184  if (nLen < 2) // end of attribute
4185  {
4186  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LR_SPACE);
4187  return;
4188  }
4189 
4190  short nPara = SVBT16ToUInt16( pData );
4191 
4192  std::shared_ptr<SvxLRSpaceItem> aLR(std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE));
4193  const SfxPoolItem* pLR = GetFormatAttr(RES_LR_SPACE);
4194  if( pLR )
4195  aLR.reset(static_cast<SvxLRSpaceItem*>(pLR->Clone()));
4196 
4197  // Fix the regression issue: #i99822#: Discussion?
4198  // Since the list level formatting doesn't apply into paragraph style
4199  // for list levels of mode LABEL_ALIGNMENT.(see ww8par3.cxx
4200  // W8ImplReader::RegisterNumFormatOnTextNode).
4201  // Need to apply the list format to the paragraph here.
4202  SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode();
4203  if( pTextNode && pTextNode->AreListLevelIndentsApplicable() )
4204  {
4205  SwNumRule * pNumRule = pTextNode->GetNumRule();
4206  if( pNumRule )
4207  {
4208  sal_uInt8 nLvl = static_cast< sal_uInt8 >(pTextNode->GetActualListLevel());
4209  const SwNumFormat* pFormat = pNumRule->GetNumFormat( nLvl );
4210  if ( pFormat && pFormat->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
4211  {
4212  aLR->SetTextLeft( pFormat->GetIndentAt() );
4213  aLR->SetTextFirstLineOffset( static_cast<short>(pFormat->GetFirstLineIndent()) );
4214  // make paragraph have hard-set indent attributes
4215  pTextNode->SetAttr( *aLR );
4216  }
4217  }
4218  }
4219 
4220  /*
4221  The older word sprms mean left/right, while the new ones mean before/after.
4222  Writer now also works with before after, so when we see old left/right and
4223  we're RTL. We swap them
4224  */
4225  if (IsRightToLeft())
4226  {
4227  switch (nId)
4228  {
4229  //Left becomes after;
4232  break;
4235  break;
4236  //Right becomes before;
4239  break;
4242  break;
4243  }
4244  }
4245 
4246  bool bFirstLinOfstSet( false ); // #i103711#
4247  bool bLeftIndentSet( false ); // #i105414#
4248 
4249  switch (nId)
4250  {
4251  //sprmPDxaLeft
4255  aLR->SetTextLeft( nPara );
4256  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4257  {
4258  m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4259  }
4260  bLeftIndentSet = true; // #i105414#
4261  break;
4262  //sprmPDxaLeft1
4266  /*
4267  As part of an attempt to break my spirit ww 8+ formats can contain
4268  ww 7- lists. If they do and the list is part of the style, then
4269  when removing the list from a paragraph of that style there
4270  appears to be a bug where the hanging indent value which the list
4271  set is still factored into the left indent of the paragraph. Its
4272  not listed in the winword dialogs, but it is clearly there. So if
4273  our style has a broken ww 7- list and we know that the list has
4274  been removed then we will factor the original list applied hanging
4275  into our calculation.
4276  */
4277  if (m_xPlcxMan && m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_bHasBrokenWW6List)
4278  {
4279  SprmResult aIsZeroed = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PIlfo::val);
4280  if (aIsZeroed.pSprm && aIsZeroed.nRemainingData >= 1 && *aIsZeroed.pSprm == 0)
4281  {
4282  const SvxLRSpaceItem &rLR =
4283  ItemGet<SvxLRSpaceItem>(*(m_vColl[m_nCurrentColl].m_pFormat),
4284  RES_LR_SPACE);
4285  nPara = nPara - rLR.GetTextFirstLineOffset();
4286  }
4287  }
4288 
4289  aLR->SetTextFirstLineOffset(nPara);
4290 
4291  if (!m_pCurrentColl)
4292  {
4293  if (const SwTextNode* pNode = m_pPaM->GetNode().GetTextNode())
4294  {
4295  if ( const SwNumFormat *pNumFormat = GetNumFormatFromTextNode(*pNode) )
4296  {
4298  {
4299  aLR->SetTextLeft(pNumFormat->GetIndentAt());
4300 
4301  // If have not explicit left, set number format list tab position is doc default tab
4303  if ( pDefaultStopItem && pDefaultStopItem->Count() > 0 )
4304  const_cast<SwNumFormat*>(pNumFormat)->SetListtabPos( const_cast<SvxTabStop&>((*pDefaultStopItem)[0]).GetTabPos() );
4305  }
4306  }
4307  }
4308  }
4309  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4310  {
4311  m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4312  }
4313  bFirstLinOfstSet = true; // #i103711#
4314  break;
4315  //sprmPDxaRight
4319  aLR->SetRight( nPara );
4320  break;
4321  default:
4322  return;
4323  }
4324 
4325  NewAttr( *aLR, bFirstLinOfstSet, bLeftIndentSet ); // #i103711#, #i105414#
4326 }
4327 
4328 // Sprm 20
4329 void SwWW8ImplReader::Read_LineSpace( sal_uInt16, const sal_uInt8* pData, short nLen )
4330 {
4331 // comment see Read_UL()
4333  return;
4334 
4335  ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
4336 
4337  if (nLen < (eVersion <= ww::eWW2 ? 3 : 4))
4338  {
4340  if( !( m_nIniFlags & WW8FL_NO_IMPLPASP ) )
4341  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4342  return;
4343  }
4344 
4345  short nSpace = SVBT16ToUInt16( pData );
4346  short nMulti = (eVersion <= ww::eWW2) ? 1 : SVBT16ToUInt16( pData + 2 );
4347 
4348  SvxLineSpaceRule eLnSpc;
4349  if( 0 > nSpace )
4350  {
4351  nSpace = -nSpace;
4352  eLnSpc = SvxLineSpaceRule::Fix;
4353  }
4354  else
4355  eLnSpc = SvxLineSpaceRule::Min;
4356 
4357  // WW has implicit additional paragraph spacing depending on
4358  // the line spacing. It is, for "exactly", 0.8 * line spacing "before"
4359  // and 0.2 * line spacing "after".
4360  // For "at least", it is 1 * line spacing "before" and 0 * line spacing "after".
4361  // For "multiple", it is 0 "before" and min(0cm, FontSize*(nFach-1)) "after".
4362 
4363  // SW also has implicit line spacing. It is, for "at least"
4364  // 1 * line spacing "before" and 0 "after".
4365  // For proportional, it is min(0cm, FontSize*(nFach-1)) both "before" and "after".
4366 
4367  sal_uInt16 nSpaceTw = 0;
4368 
4370 
4371  if( 1 == nMulti ) // MultilineSpace ( proportional )
4372  {
4373  tools::Long n = nSpace * 10 / 24; // WW: 240 = 100%, SW: 100 = 100%
4374 
4375  // here n is in [0..13653]
4376  aLSpc.SetPropLineSpace( static_cast<sal_uInt16>(n) );
4377  const SvxFontHeightItem* pH = static_cast<const SvxFontHeightItem*>(
4379  nSpaceTw = static_cast<sal_uInt16>( n * pH->GetHeight() / 100 );
4380  }
4381  else // Fixed / Minimum
4382  {
4383  // for negative space, the distance is "exact", otherwise "at least"
4384  nSpaceTw = static_cast<sal_uInt16>(nSpace);
4385  aLSpc.SetLineHeight( nSpaceTw );
4386  aLSpc.SetLineSpaceRule( eLnSpc);
4387  }
4388  NewAttr( aLSpc );
4389  if (m_xSFlyPara)
4390  m_xSFlyPara->nLineSpace = nSpaceTw; // linespace for graphics APOs
4391 }
4392 
4393 //#i18519# AutoSpace value depends on Dop fDontUseHTMLAutoSpacing setting
4394 sal_uInt16 SwWW8ImplReader::GetParagraphAutoSpace(bool fDontUseHTMLAutoSpacing)
4395 {
4396  if (fDontUseHTMLAutoSpacing)
4397  return 100; //Seems to be always 5points in this case
4398  else
4399  return 280; //Seems to be always 14points in this case
4400 }
4401 
4402 void SwWW8ImplReader::Read_ParaAutoBefore(sal_uInt16, const sal_uInt8 *pData, short nLen)
4403 {
4404  if (nLen < 1)
4405  {
4406  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4407  return;
4408  }
4409 
4410  if (*pData)
4411  {
4412  SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4413  aUL.SetUpper(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4414  NewAttr(aUL);
4415  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4417  else
4418  m_bParaAutoBefore = true;
4419  }
4420  else
4421  {
4422  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4424  else
4425  m_bParaAutoBefore = false;
4426  }
4427 }
4428 
4429 void SwWW8ImplReader::Read_ParaAutoAfter(sal_uInt16, const sal_uInt8 *pData, short nLen)
4430 {
4431  if (nLen < 1)
4432  {
4433  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4434  return;
4435  }
4436 
4437  if (*pData)
4438  {
4439  SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4440  aUL.SetLower(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4441  NewAttr(aUL);
4442  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4444  else
4445  m_bParaAutoAfter = true;
4446  }
4447  else
4448  {
4449  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4451  else
4452  m_bParaAutoAfter = false;
4453  }
4454 }
4455 
4456 // Sprm 21, 22
4457 void SwWW8ImplReader::Read_UL( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4458 {
4459  // A workaround for an error in WW: For nProduct == 0c03d, usually
4460  // DyaAfter 240 (delta y distance after, comment of the translator)
4461  // is incorrectly inserted into style "Normal", even though it isn't there.
4462  // Using the ini flag WW8FL_NO_STY_DYA you can force this behavior for other
4463  // WW versions as well.
4464  // OSL_ENSURE( !bStyNormal || bWWBugNormal, "+This Document may point to a bug
4465  // in the WW version used for creating it. If the Styles <Standard> resp.
4466  // <Normal> differentiate between WW and SW in paragraph or line spacing,
4467  // then please send this Document to SH.");
4468  // bWWBugNormal is not a sufficient criterion for this distance being wrong.
4469 
4470  if (nLen < 2)
4471  {
4472  // end of attribute
4473  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4474  return;
4475  }
4476  short nPara = SVBT16ToUInt16( pData );
4477  if( nPara < 0 )
4478  nPara = -nPara;
4479 
4480  SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4481 
4482  switch( nId )
4483  {
4484  //sprmPDyaBefore
4487  aUL.SetUpper( nPara );
4488  break;
4489  //sprmPDyaAfter
4492  aUL.SetLower( nPara );
4493  break;
4494  default:
4495  return;
4496  }
4497 
4498  NewAttr( aUL );
4499 }
4500 
4501 void SwWW8ImplReader::Read_ParaContextualSpacing( sal_uInt16, const sal_uInt8* pData, short nLen )
4502 {
4503  if (nLen < 1)
4504  {
4505  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4506  return;
4507  }
4508  SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4509  aUL.SetContextValue(*pData != 0);
4510  NewAttr( aUL );
4511 }
4512 
4513 void SwWW8ImplReader::Read_IdctHint( sal_uInt16, const sal_uInt8* pData, short nLen )
4514 {
4515  // sprmcidcthint (opcode 0x286f) specifies a script bias for the text in the run.
4516  // for unicode characters that are shared between far east and non-far east scripts,
4517  // this property determines what font and language the character will use.
4518  // when this value is 0, text properties bias towards non-far east properties.
4519  // when this value is 1, text properties bias towards far east properties.
4520  // when this value is 2, text properties bias towards complex properties.
4521  if (nLen < 1) //Property end
4522  {
4524  }
4525  else //Property start
4526  {
4528  }
4529 }
4530 
4531 void SwWW8ImplReader::Read_Justify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4532 {
4533  if (nLen < 1)
4534  {
4535  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4536  return;
4537  }
4538 
4539  SvxAdjust eAdjust(SvxAdjust::Left);
4540  bool bDistributed = false;
4541  switch (*pData)
4542  {
4543  default:
4544  case 0:
4545  break;
4546  case 1:
4547  eAdjust = SvxAdjust::Center;
4548  break;
4549  case 2:
4550  eAdjust = SvxAdjust::Right;
4551  break;
4552  case 3:
4553  eAdjust = SvxAdjust::Block;
4554  break;
4555  case 4:
4556  eAdjust = SvxAdjust::Block;
4557  bDistributed = true;
4558  break;
4559  }
4560  SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4561  if (bDistributed)
4562  aAdjust.SetLastBlock(SvxAdjust::Block);
4563 
4564  NewAttr(aAdjust);
4566 }
4567 
4569 {
4570  bool bRTL = false;
4571  SprmResult aDir;
4572  if (m_xPlcxMan)
4573  aDir = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PFBiDi::val);
4574  if (aDir.pSprm && aDir.nRemainingData >= 1)
4575  bRTL = *aDir.pSprm != 0;
4576  else
4577  {
4578  const SvxFrameDirectionItem* pItem=
4579  static_cast<const SvxFrameDirectionItem*>(GetFormatAttr(RES_FRAMEDIR));
4580  if (pItem && (pItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4581  bRTL = true;
4582  }
4583  return bRTL;
4584 }
4585 
4586 void SwWW8ImplReader::Read_RTLJustify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4587 {
4588  if (nLen < 1)
4589  {
4590  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4591  return;
4592  }
4593 
4594  //If we are in a ltr paragraph this is the same as normal Justify,
4595  //If we are in a rtl paragraph the meaning is reversed.
4596  if (!IsRightToLeft())
4597  Read_Justify(nId, pData, nLen);
4598  else
4599  {
4600  SvxAdjust eAdjust(SvxAdjust::Right);
4601  bool bDistributed = false;
4602  switch (*pData)
4603  {
4604  default:
4605  case 0:
4606  break;
4607  case 1:
4608  eAdjust = SvxAdjust::Center;
4609  break;
4610  case 2:
4611  eAdjust = SvxAdjust::Left;
4612  break;
4613  case 3:
4614  eAdjust = SvxAdjust::Block;
4615  break;
4616  case 4:
4617  eAdjust = SvxAdjust::Block;
4618  bDistributed = true;
4619  break;
4620  }
4621  SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4622  if (bDistributed)
4623  aAdjust.SetLastBlock(SvxAdjust::Block);
4624 
4625  NewAttr(aAdjust);
4626  SetRelativeJustify( true );
4627  }
4628 }
4629 
4630 void SwWW8ImplReader::Read_BoolItem( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4631 {
4632  switch( nId )
4633  {
4636  break;
4639  break;
4641  nId = RES_PARATR_SCRIPTSPACE;
4642  break;
4643  default:
4644  OSL_ENSURE( false, "wrong Id" );
4645  return ;
4646  }
4647 
4648  if (nLen < 1)
4649  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4650  else
4651  {
4652  std::unique_ptr<SfxBoolItem> pI(static_cast<SfxBoolItem*>(GetDfltAttr( nId )->Clone()));
4653  pI->SetValue( 0 != *pData );
4654  NewAttr( *pI );
4655  }
4656 }
4657 
4658 void SwWW8ImplReader::Read_Emphasis( sal_uInt16, const sal_uInt8* pData, short nLen )
4659 {
4660  if (nLen < 1)
4662  else
4663  {
4665  //Check to see if there is an up and coming cjk language property. If
4666  //there is use it, if there is not fall back to the currently set one.
4667  //Only the cjk language setting seems to matter to word, the western
4668  //one is ignored
4669  SprmResult aLang;
4670  if (m_xPlcxMan)
4671  aLang = m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CRgLid1_80::val);
4672 
4673  if (aLang.pSprm && aLang.nRemainingData >= 2)
4674  nLang = LanguageType(SVBT16ToUInt16(aLang.pSprm));
4675  else
4676  {
4677  nLang = static_cast<const SvxLanguageItem *>(
4679  }
4680 
4681  FontEmphasisMark nVal;
4682  switch( *pData )
4683  {
4684  case 0:
4685  nVal = FontEmphasisMark::NONE;
4686  break;
4687  case 2:
4689  nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4690  else if (nLang == LANGUAGE_JAPANESE)
4691  nVal = (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove);
4692  else
4693  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4694  break;
4695  case 3:
4696  nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4697  break;
4698  case 4:
4699  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4700  break;
4701  case 1:
4702  if (MsLangId::isSimplifiedChinese(nLang))
4703  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4704  else
4705  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4706  break;
4707  default:
4708  nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4709  break;
4710  }
4711 
4713  }
4714 }
4715 
4716 void SwWW8ImplReader::Read_ScaleWidth( sal_uInt16, const sal_uInt8* pData, short nLen )
4717 {
4718  if (nLen < 2)
4719  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SCALEW );
4720  else
4721  {
4722  sal_uInt16 nVal = SVBT16ToUInt16( pData );
4723  //The number must be between 1 and 600
4724  if (nVal < 1 || nVal > 600)
4725  nVal = 100;
4727  }
4728 }
4729 
4730 void SwWW8ImplReader::Read_Relief( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4731 {
4732  if (nLen < 1)
4733  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_RELIEF );
4734  else
4735  {
4736  if( *pData )
4737  {
4738 // not so easy because this is also a toggle attribute!
4739 // 2 x emboss on -> no emboss !!!
4740 // the actual value must be searched over the stack / template
4741 
4742  const SvxCharReliefItem* pOld = static_cast<const SvxCharReliefItem*>(
4744  FontRelief nNewValue = NS_sprm::CFImprint::val == nId ? FontRelief::Engraved
4745  : ( NS_sprm::CFEmboss::val == nId ? FontRelief::Embossed
4746  : FontRelief::NONE );
4747  if( pOld->GetValue() == nNewValue )
4748  {
4749  if( FontRelief::NONE != nNewValue )
4750  nNewValue = FontRelief::NONE;
4751  }
4753  }
4754  }
4755 }
4756 
4757 void SwWW8ImplReader::Read_TextAnim(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
4758 {
4759  if (nLen < 1)
4761  else
4762  {
4763  if (*pData)
4764  {
4765  bool bBlink;
4766 
4767  // The 7 animated text effects available in word all get
4768  // mapped to a blinking text effect in LibreOffice
4769  // 0 no animation 1 Las Vegas lights
4770  // 2 background blink 3 sparkle text
4771  // 4 marching ants 5 marching red ants
4772  // 6 shimmer
4773  bBlink = *pData > 0 && *pData < 7;
4774 
4776  }
4777  }
4778 }
4779 
4780 SwWW8Shade::SwWW8Shade(bool bVer67, const WW8_SHD& rSHD)
4781 {
4782  sal_uInt8 b = rSHD.GetFore();
4783  OSL_ENSURE(b < 17, "ww8: colour out of range");
4784  if (b >= 17)
4785  b = 0;
4786 
4787  Color nFore(SwWW8ImplReader::GetCol(b));
4788 
4789  b = rSHD.GetBack();
4790  OSL_ENSURE(b < 17, "ww8: colour out of range");
4791  if( b >= 17 )
4792  b = 0;
4793 
4794  Color nBack(SwWW8ImplReader::GetCol(b));
4795 
4796  b = rSHD.GetStyle(bVer67);
4797 
4798  SetShade(nFore, nBack, b);
4799 }
4800 
4801 void SwWW8Shade::SetShade(Color nFore, Color nBack, sal_uInt16 nIndex)
4802 {
4803  static const sal_uLong eMSGrayScale[] =
4804  {
4805  // Clear-Brush
4806  0, // 0 clear
4807  // Solid-Brush
4808  1000, // 1 solid
4809  // Percent values
4810  50, // 2 pct5
4811  100, // 3 pct10
4812  200, // 4 pct20
4813  250, // 5 pct25
4814  300, // 6 pct30
4815  400, // 7 pct40
4816  500, // 8 pct50
4817  600, // 9 pct60
4818  700, // 10 pct70
4819  750, // 11 pct75
4820  800, // 12 pct80
4821  900, // 13 pct90
4822  // Special cases
4823  333, // 14 Dark Horizontal
4824  333, // 15 Dark Vertical
4825  333, // 16 Dark Forward Diagonal
4826  333, // 17 Dark Backward Diagonal
4827  333, // 18 Dark Cross
4828  333, // 19 Dark Diagonal Cross
4829  333, // 20 Horizontal
4830  333, // 21 Vertical
4831  333, // 22 Forward Diagonal
4832  333, // 23 Backward Diagonal
4833  333, // 24 Cross
4834  333, // 25 Diagonal Cross
4835  // Undefined values in DOC spec-sheet
4836  500, // 26
4837  500, // 27
4838  500, // 28
4839  500, // 29
4840  500, // 30
4841  500, // 31
4842  500, // 32
4843  500, // 33
4844  500, // 34
4845  // Different shading types
4846  25, // 35 [available in DOC, not available in DOCX]
4847  75, // 36 [available in DOC, not available in DOCX]
4848  125, // 37 pct12
4849  150, // 38 pct15
4850  175, // 39 [available in DOC, not available in DOCX]
4851  225, // 40 [available in DOC, not available in DOCX]
4852  275, // 41 [available in DOC, not available in DOCX]
4853  325, // 42 [available in DOC, not available in DOCX]
4854  350, // 43 pct35
4855  375, // 44 pct37
4856  425, // 45 [available in DOC, not available in DOCX]
4857  450, // 46 pct45
4858  475, // 47 [available in DOC, not available in DOCX]
4859  525, // 48 [available in DOC, not available in DOCX]
4860  550, // 49 pct55
4861  575, // 50 [available in DOC, not available in DOCX]
4862  625, // 51 pct62
4863  650, // 52 pct65
4864  675, // 53 [available in DOC, not available in DOCX]
4865  725, // 54 [available in DOC, not available in DOCX]
4866  775, // 55 [available in DOC, not available in DOCX]
4867  825, // 56 [available in DOC, not available in DOCX]
4868  850, // 57 pct85
4869  875, // 58 pct87
4870  925, // 59 [available in DOC, not available in DOCX]
4871  950, // 60 pct95
4872  975 // 61 [available in DOC, not available in DOCX]
4873  };// 62
4874 
4875  //NO auto for shading so Foreground: Auto = Black
4876  if (nFore == COL_AUTO)
4877  nFore = COL_BLACK;
4878 
4879  //NO auto for shading so background: Auto = White
4880  Color nUseBack = nBack;
4881  if (nUseBack == COL_AUTO)
4882  nUseBack = COL_WHITE;
4883 
4884  if( nIndex >= SAL_N_ELEMENTS( eMSGrayScale ) )
4885  nIndex = 0;
4886 
4887  sal_uLong nWW8BrushStyle = eMSGrayScale[nIndex];
4888 
4889  switch (nWW8BrushStyle)
4890  {
4891  case 0: // Null-Brush
4892  aColor = nBack;
4893  break;
4894  default:
4895  {
4896  Color aForeColor(nFore);
4897  Color aBackColor(nUseBack);
4898 
4899  sal_uInt32 nRed = aForeColor.GetRed() * nWW8BrushStyle;
4900  sal_uInt32 nGreen = aForeColor.GetGreen() * nWW8BrushStyle;
4901  sal_uInt32 nBlue = aForeColor.GetBlue() * nWW8BrushStyle;
4902  nRed += aBackColor.GetRed() * (1000 - nWW8BrushStyle);
4903  nGreen += aBackColor.GetGreen()* (1000 - nWW8BrushStyle);
4904  nBlue += aBackColor.GetBlue() * (1000 - nWW8BrushStyle);
4905 
4906  aColor = Color( nRed/1000, nGreen/1000, nBlue/1000 );
4907  }
4908  break;
4909  }
4910 }
4911 
4912 void SwWW8ImplReader::Read_Shade( sal_uInt16, const sal_uInt8* pData, short nLen )
4913 {
4914  if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PShd::val).pSprm)
4915  return;
4916 
4917  if (nLen < 2)
4918  {
4919  // end of attribute
4920  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
4921  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
4922  }
4923  else
4924  {
4925  WW8_SHD aSHD;
4926  aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4927  SwWW8Shade aSh( m_bVer67, aSHD );
4928 
4929  NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
4930  NewAttr( XFillColorItem(OUString(), aSh.aColor) );
4931  }
4932 }
4933 
4934 void SwWW8ImplReader::Read_ParaBackColor(sal_uInt16, const sal_uInt8* pData, short nLen)
4935 {
4936  if (nLen <= 0)
4937  {
4938  // end of attribute
4939  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
4940  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
4941  }
4942  else
4943  {
4944  OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4945  if (nLen != 10)
4946  return;
4947 
4948  const Color aColor = ExtractColour(pData, m_bVer67);
4949  NewAttr( XFillColorItem(OUString(), aColor) );
4950  if ( aColor == COL_AUTO )
4951  NewAttr( XFillStyleItem(drawing::FillStyle_NONE) );
4952  else
4953  NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
4954  }
4955 }
4956 
4957 Color SwWW8ImplReader::ExtractColour(const sal_uInt8* &rpData, bool bVer67)
4958 {
4959  OSL_ENSURE(!bVer67, "Impossible");
4960  Color nFore = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
4961  rpData+=4;
4962  Color nBack = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
4963  rpData+=4;
4964  sal_uInt16 nIndex = SVBT16ToUInt16(rpData);
4965  rpData+=2;
4966  //Being a transparent background colour doesn't actually show the page
4967  //background through, it merely acts like white
4968  if (nBack == Color(ColorTransparency, 0xFF000000))
4969  nBack = COL_AUTO;
4970  OSL_ENSURE(nBack == COL_AUTO || !nBack.IsTransparent(),
4971  "ww8: don't know what to do with such a transparent bg colour, report");
4972  SwWW8Shade aShade(nFore, nBack, nIndex);
4973  return aShade.aColor;
4974 }
4975 
4976 void SwWW8ImplReader::Read_TextVerticalAdjustment( sal_uInt16, const sal_uInt8* pData, short nLen )
4977 {
4978  if( nLen <= 0 )
4979  return;
4980 
4981  drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
4982  switch( *pData )
4983  {
4984  case 1:
4985  nVA = drawing::TextVerticalAdjust_CENTER;
4986  break;
4987  case 2: //justify
4988  nVA = drawing::TextVerticalAdjust_BLOCK;
4989  break;
4990  case 3:
4991  nVA = drawing::TextVerticalAdjust_BOTTOM;
4992  break;
4993  default:
4994  break;
4995  }
4997 }
4998 
4999 void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
5000 {
5001  if (nLen < 0)
5002  {
5003  if( m_bHasBorder )
5004  {
5005  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BOX );
5006  m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_SHADOW );
5007  m_bHasBorder = false;
5008  }
5009  }
5010  else if( !m_bHasBorder )
5011  {
5012  // the borders on all four sides are bundled. That
5013  // simplifies the administration, i.e., the box does not have
5014  // to be put on and removed from CtrlStack 4 times.
5015  m_bHasBorder = true;
5016 
5017  WW8_BRCVer9_5 aBrcs; // Top, Left, Bottom, Right, Between
5019 
5020  if( m_pCurrentColl )
5021  nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, nullptr, m_xStyles.get());
5022  else
5023  nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, m_xPlcxMan ?