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