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