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