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