android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / ww8 / ww8par6.cxx
blobea153f46d0c645871f544900f49a07ea40370322
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <stdlib.h>
21 #include <o3tl/safeint.hxx>
22 #include <o3tl/unit_conversion.hxx>
23 #include <svl/itemiter.hxx>
24 #include <svl/grabbagitem.hxx>
25 #include <rtl/tencinfo.h>
26 #include <sal/log.hxx>
28 #include <hintids.hxx>
29 #include <editeng/lspcitem.hxx>
30 #include <editeng/wrlmitem.hxx>
31 #include <editeng/udlnitem.hxx>
32 #include <editeng/kernitem.hxx>
33 #include <editeng/langitem.hxx>
34 #include <editeng/cmapitem.hxx>
35 #include <editeng/shdditem.hxx>
36 #include <editeng/contouritem.hxx>
37 #include <editeng/crossedoutitem.hxx>
38 #include <editeng/postitem.hxx>
39 #include <editeng/wghtitem.hxx>
40 #include <editeng/colritem.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/spltitem.hxx>
43 #include <editeng/keepitem.hxx>
44 #include <editeng/orphitem.hxx>
45 #include <editeng/widwitem.hxx>
46 #include <editeng/adjustitem.hxx>
47 #include <editeng/escapementitem.hxx>
48 #include <editeng/fhgtitem.hxx>
49 #include <editeng/fontitem.hxx>
50 #include <editeng/shaditem.hxx>
51 #include <editeng/boxitem.hxx>
52 #include <editeng/ulspitem.hxx>
53 #include <editeng/lrspitem.hxx>
54 #include <editeng/tstpitem.hxx>
55 #include <editeng/autokernitem.hxx>
56 #include <editeng/paperinf.hxx>
57 #include <editeng/emphasismarkitem.hxx>
58 #include <editeng/twolinesitem.hxx>
59 #include <editeng/charscaleitem.hxx>
60 #include <editeng/charrotateitem.hxx>
61 #include <editeng/charreliefitem.hxx>
62 #include <editeng/blinkitem.hxx>
63 #include <editeng/hyphenzoneitem.hxx>
64 #include <editeng/paravertalignitem.hxx>
65 #include <editeng/pgrditem.hxx>
66 #include <editeng/frmdiritem.hxx>
67 #include <editeng/charhiddenitem.hxx>
68 #include <i18nlangtag/mslangid.hxx>
69 #include <svx/xfillit0.hxx>
70 #include <svx/xflclit.hxx>
71 #include <officecfg/Office/Writer.hxx>
72 #include "sortedarray.hxx"
73 #include "sprmids.hxx"
74 #include <node.hxx>
75 #include <ndtxt.hxx>
76 #include <pam.hxx>
77 #include <doc.hxx>
78 #include <IDocumentSettingAccess.hxx>
79 #include <pagedesc.hxx>
80 #include <fmtanchr.hxx>
81 #include <fmtcntnt.hxx>
82 #include <fchrfmt.hxx>
83 #include <fmthdft.hxx>
84 #include <fmtclds.hxx>
85 #include <fmtftntx.hxx>
86 #include <frmatr.hxx>
87 #include <section.hxx>
88 #include <lineinfo.hxx>
89 #include <fmtline.hxx>
90 #include <txatbase.hxx>
91 #include <fmtflcnt.hxx>
92 #include <tgrditem.hxx>
93 #include <hfspacingitem.hxx>
94 #include <swtable.hxx>
95 #include <fltini.hxx>
96 #include "writerhelper.hxx"
97 #include "writerwordglue.hxx"
98 #include "ww8scan.hxx"
99 #include "ww8par2.hxx"
100 #include "ww8graf.hxx"
102 #include <fmtwrapinfluenceonobjpos.hxx>
103 #include <formatflysplit.hxx>
105 using namespace sw::util;
106 using namespace sw::types;
107 using namespace ::com::sun::star;
108 using namespace nsHdFtFlags;
110 // various
112 // WW default for horizontal borders: 2.5 cm
113 constexpr auto MM_250 = o3tl::convert(25, o3tl::Length::mm, o3tl::Length::twip); // 1417
114 // WW default for lower border: 2.0 cm
115 constexpr auto MM_200 = o3tl::convert(20, o3tl::Length::mm, o3tl::Length::twip); // 1134
118 static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
119 const WW8RStyle* pSty = nullptr, const WW8PLCFx_SEPX* pSep = nullptr);
121 Color SwWW8ImplReader::GetCol(sal_uInt8 nIco)
123 static const Color eSwWW8ColA[] =
125 COL_AUTO, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
126 COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
127 COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
128 COL_LIGHTGRAY
130 SAL_WARN_IF(
131 nIco >= SAL_N_ELEMENTS(eSwWW8ColA), "sw.ww8",
132 "ico " << sal_uInt32(nIco) << " >= " << SAL_N_ELEMENTS(eSwWW8ColA));
133 return nIco < SAL_N_ELEMENTS(eSwWW8ColA) ? eSwWW8ColA[nIco] : COL_AUTO;
136 static sal_uInt32 MSRoundTweak(sal_uInt32 x)
138 return x;
141 // page attribute which are not handled via the attribute management but
142 // using ...->HasSprm
143 // (except OLST which stays a normal attribute)
144 static short ReadSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
146 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
147 const sal_uInt8* pS = aRes.pSprm;
148 short nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToInt16(pS) : nDefaultVal;
149 return nVal;
152 static sal_uInt16 ReadUSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
154 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
155 const sal_uInt8* pS = aRes.pSprm;
156 sal_uInt16 nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToUInt16(pS) : nDefaultVal;
157 return nVal;
160 static sal_uInt8 ReadBSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, sal_uInt8 nDefaultVal )
162 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
163 const sal_uInt8* pS = aRes.pSprm;
164 sal_uInt8 nVal = (pS && aRes.nRemainingData >= 1) ? *pS : nDefaultVal;
165 return nVal;
168 void wwSection::SetDirection()
170 //sprmSTextFlow
171 switch (maSep.wTextFlow)
173 default:
174 OSL_ENSURE(false, "Unknown layout type");
175 [[fallthrough]];
176 case 0:
177 meDir=SvxFrameDirection::Horizontal_LR_TB;
178 break;
179 case 1:
180 meDir=SvxFrameDirection::Vertical_RL_TB;
181 break;
182 case 2:
183 //asian letters are not rotated, western are. We can't import
184 //bottom to top going left to right, we can't do this in
185 //pages, (in drawboxes we could partly hack it with a rotated
186 //drawing box, though not frame)
187 meDir=SvxFrameDirection::Vertical_RL_TB;
188 break;
189 case 3:
190 //asian letters are not rotated, western are. We can't import
191 meDir=SvxFrameDirection::Vertical_RL_TB;
192 break;
193 case 4:
194 //asian letters are rotated, western not. We can't import
195 meDir=SvxFrameDirection::Horizontal_LR_TB;
196 break;
199 sal_uInt8 bRTLPgn = maSep.fBiDi;
200 if ((meDir == SvxFrameDirection::Horizontal_LR_TB) && bRTLPgn)
201 meDir = SvxFrameDirection::Horizontal_RL_TB;
204 bool wwSection::IsVertical() const
206 return meDir == SvxFrameDirection::Vertical_RL_TB || meDir == SvxFrameDirection::Vertical_LR_TB;
210 This is something of festering mapping, I'm open to better ways of doing it,
211 but primarily the grid in writer is different to that in word. In writer the
212 grid elements are squares with ruby rows inbetween. While in word there is no
213 ruby stuff, and the elements are rectangles. By misusing the ruby row I can
214 handle distortions in one direction, but its all a bit of a mess:
216 void SwWW8ImplReader::SetDocumentGrid(SwFrameFormat &rFormat, const wwSection &rSection)
218 if (m_bVer67)
219 return;
221 rFormat.SetFormatAttr(SvxFrameDirectionItem(rSection.meDir, RES_FRAMEDIR));
223 SwTwips nTextareaHeight = rFormat.GetFrameSize().GetHeight();
224 const SvxULSpaceItem &rUL = rFormat.GetFormatAttr(RES_UL_SPACE);
225 nTextareaHeight -= rUL.GetUpper();
226 nTextareaHeight -= rUL.GetLower();
228 SwTwips nTextareaWidth = rFormat.GetFrameSize().GetWidth();
229 const SvxLRSpaceItem &rLR = rFormat.GetFormatAttr(RES_LR_SPACE);
230 nTextareaWidth -= rLR.GetLeft();
231 nTextareaWidth -= rLR.GetRight();
233 if (rSection.IsVertical())
234 std::swap(nTextareaHeight, nTextareaWidth);
236 SwTextGridItem aGrid;
237 aGrid.SetDisplayGrid(false);
238 aGrid.SetPrintGrid(false);
239 SwTextGrid eType=GRID_NONE;
241 switch (rSection.maSep.clm)
243 case 0:
244 eType = GRID_NONE;
245 break;
246 default:
247 OSL_ENSURE(false, "Unknown grid type");
248 [[fallthrough]];
249 case 3:
250 eType = GRID_LINES_CHARS;
251 aGrid.SetSnapToChars(true);
252 break;
253 case 1:
254 eType = GRID_LINES_CHARS;
255 aGrid.SetSnapToChars(false);
256 break;
257 case 2:
258 eType = GRID_LINES_ONLY;
259 break;
262 aGrid.SetGridType(eType);
264 // seem to not add external leading in word, or the character would run across
265 // two line in some cases.
266 if (eType != GRID_NONE)
267 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, false);
269 //force to set document as standard page mode
270 bool bSquaredMode = false;
271 m_rDoc.SetDefaultPageMode( bSquaredMode );
272 aGrid.SetSquaredMode( bSquaredMode );
274 //Get the size of word's default styles font
275 sal_uInt32 nCharWidth=240;
276 for (sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); ++nI)
278 if (m_vColl[nI].m_bValid && m_vColl[nI].m_pFormat &&
279 m_vColl[nI].IsWW8BuiltInDefaultStyle())
281 const SvxFontHeightItem& rFontHeightItem =
282 m_vColl[nI].m_pFormat->GetFormatAttr(RES_CHRATR_CJK_FONTSIZE);
283 nCharWidth = rFontHeightItem.GetHeight();
284 break;
288 //dxtCharSpace
289 if (rSection.maSep.dxtCharSpace)
291 sal_uInt32 nCharSpace = rSection.maSep.dxtCharSpace;
292 //main lives in top 20 bits, and is signed.
293 sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
294 nMain/=0x1000;
295 nCharWidth += nMain*20;
297 int nFraction = (nCharSpace & 0x00000FFF);
298 nFraction = (nFraction*20)/0xFFF;
299 nCharWidth += nFraction;
302 aGrid.SetBaseWidth( writer_cast<sal_uInt16>(nCharWidth));
304 //sep.dyaLinePitch
305 sal_Int32 nLinePitch = rSection.maSep.dyaLinePitch;
306 if (nLinePitch >= 1 && nLinePitch <= 31680)
308 aGrid.SetLines(writer_cast<sal_uInt16>(nTextareaHeight/nLinePitch));
309 aGrid.SetBaseHeight(writer_cast<sal_uInt16>(nLinePitch));
312 aGrid.SetRubyHeight(0);
314 rFormat.SetFormatAttr(aGrid);
317 void SwWW8ImplReader::SetRelativeJustify( bool bRel )
319 if ( m_pCurrentColl && StyleExists(m_nCurrentColl) ) // importing style
320 m_vColl[m_nCurrentColl].m_nRelativeJustify = bRel ? 1 : 0;
321 else if ( m_xPlcxMan && m_xPlcxMan->GetPap() ) // importing paragraph
322 m_xPlcxMan->GetPap()->nRelativeJustify = bRel ? 1 : 0;
325 bool SwWW8ImplReader::IsRelativeJustify()
327 bool bRet = m_xWwFib->GetFIBVersion() >= ww::eWW8;
328 if ( bRet )
330 // if relativeJustify is undefined (-1), then check the parent style.
331 if ( m_pCurrentColl && StyleExists(m_nCurrentColl) )
333 sal_Int16 nRelative = m_vColl[m_nCurrentColl].m_nRelativeJustify;
334 if ( nRelative < 0 && m_nCurrentColl )
336 o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
337 bRet = IsRelativeJustify(m_vColl[m_nCurrentColl].m_nBase, aVisitedStyles);
339 else
340 bRet = nRelative > 0;
342 else if ( m_xPlcxMan && m_xPlcxMan->GetPap() )
344 sal_Int16 nRelative = m_xPlcxMan->GetPap()->nRelativeJustify;
345 if ( nRelative < 0 )
347 o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
348 bRet = IsRelativeJustify(m_nCurrentColl, aVisitedStyles);
350 else
351 bRet = nRelative > 0;
355 return bRet;
358 bool SwWW8ImplReader::IsRelativeJustify(sal_uInt16 nColl, o3tl::sorted_vector<sal_uInt16>& rVisitedStyles)
360 assert( m_xWwFib->GetFIBVersion() >= ww::eWW8
361 && "pointless to search styles if relative justify is impossible");
362 bool bRet = true;
363 if ( StyleExists(nColl) )
365 rVisitedStyles.insert(nColl);
366 // if relativeJustify is undefined (-1), then check the parent style.
367 sal_Int16 nRelative = m_vColl[nColl].m_nRelativeJustify;
368 if ( nColl == 0 || nRelative >= 0 )
369 bRet = nRelative > 0;
370 else if (rVisitedStyles.find(m_vColl[nColl].m_nBase) == rVisitedStyles.end()) // detect loop in chain
371 bRet = IsRelativeJustify(m_vColl[nColl].m_nBase, rVisitedStyles);
374 return bRet;
377 void SwWW8ImplReader::Read_ParaBiDi(sal_uInt16, const sal_uInt8* pData, short nLen)
379 if (nLen < 1)
380 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FRAMEDIR);
381 else
383 SvxFrameDirection eDir =
384 *pData ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB;
386 // In eWW8+, justify can be absolute, or relative to BiDi
387 bool bBiDiSwap = IsRelativeJustify();
388 if ( bBiDiSwap )
390 // Only change if ParaBiDi doesn't match previous setting.
391 const bool bParentRTL = IsRightToLeft();
392 bBiDiSwap = (eDir == SvxFrameDirection::Horizontal_RL_TB && !bParentRTL)
393 || (eDir == SvxFrameDirection::Horizontal_LR_TB && bParentRTL);
396 if ( bBiDiSwap )
398 const SvxAdjustItem* pItem = static_cast<const SvxAdjustItem*>(GetFormatAttr(RES_PARATR_ADJUST));
399 if ( !pItem )
401 // no previous adjust: set appropriate default
402 if ( eDir == SvxFrameDirection::Horizontal_LR_TB )
403 NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
404 else
405 NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
407 else
409 // previous adjust and bidi has changed: swap Left/Right
410 const SvxAdjust eJustify = pItem->GetAdjust();
411 if ( eJustify == SvxAdjust::Left )
412 NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
413 else if ( eJustify == SvxAdjust::Right )
414 NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
418 NewAttr(SvxFrameDirectionItem(eDir, RES_FRAMEDIR));
420 if ( m_pCurrentColl && m_xStyles ) // in style definition
421 m_xStyles->mbBidiChanged = true;
425 bool wwSectionManager::SetCols(SwFrameFormat &rFormat, const wwSection &rSection,
426 sal_uInt32 nNetWidth)
428 //sprmSCcolumns - number of columns - 1
429 const sal_Int16 nCols = rSection.NoCols();
431 if (nCols < 2) //check for no columns or other weird state
432 return false;
434 const sal_uInt16 nNetWriterWidth = writer_cast<sal_uInt16>(nNetWidth);
435 if (nNetWriterWidth == 0)
436 return false;
438 SwFormatCol aCol; // Create SwFormatCol
440 //sprmSDxaColumns - Default distance is 1.25 cm
441 sal_Int32 nColSpace = rSection.StandardColSeparation();
443 const SEPr& rSep = rSection.maSep;
445 // sprmSLBetween
446 if (rSep.fLBetween)
448 aCol.SetLineAdj(COLADJ_TOP); // Line
449 aCol.SetLineHeight(100);
450 aCol.SetLineColor(COL_BLACK);
451 aCol.SetLineWidth(1);
454 aCol.Init(nCols, writer_cast<sal_uInt16>(nColSpace), nNetWriterWidth);
456 // sprmSFEvenlySpaced
457 if (!rSep.fEvenlySpaced)
459 aCol.SetOrtho_(false);
460 const sal_uInt16 maxIdx = SAL_N_ELEMENTS(rSep.rgdxaColumnWidthSpacing);
461 for (sal_uInt16 i = 0, nIdx = 1; i < nCols && nIdx < maxIdx; i++, nIdx+=2 )
463 SwColumn* pCol = &aCol.GetColumns()[i];
464 const sal_Int32 nLeft = rSep.rgdxaColumnWidthSpacing[nIdx-1]/2;
465 const sal_Int32 nRight = rSep.rgdxaColumnWidthSpacing[nIdx+1]/2;
466 const sal_Int32 nWishWidth = rSep.rgdxaColumnWidthSpacing[nIdx]
467 + nLeft + nRight;
468 pCol->SetWishWidth(writer_cast<sal_uInt16>(nWishWidth));
469 pCol->SetLeft(writer_cast<sal_uInt16>(nLeft));
470 pCol->SetRight(writer_cast<sal_uInt16>(nRight));
472 aCol.SetWishWidth(nNetWriterWidth);
474 rFormat.SetFormatAttr(aCol);
475 return true;
478 void wwSectionManager::SetLeftRight(wwSection &rSection)
480 // 3. LR-Margin
481 sal_uInt32 nWWLe = MSRoundTweak(rSection.maSep.dxaLeft);
482 sal_uInt32 nWWRi = MSRoundTweak(rSection.maSep.dxaRight);
483 sal_uInt32 nWWGu = rSection.maSep.dzaGutter;
486 fRTLGutter is set if the gutter is on the right, the gutter is otherwise
487 placed on the left unless the global dop options are to put it on top, that
488 case is handled in GetPageULData.
490 if (rSection.maSep.fRTLGutter)
492 rSection.m_bRtlGutter = true;
495 // Left / Right
496 if ((rSection.m_nPgWidth - nWWLe - nWWRi) < MINLAY)
499 There are some label templates which are "broken", they specify
500 margins which make no sense e.g. Left 16.10cm, Right 16.10cm. So the
501 space left between the margins is less than 0 In word the left margin
502 is honoured and if the right margin would be past the left margin is
503 left at the left margin position.
505 Now this will work fine for importing, layout and exporting, *but* the
506 page layout dialog has a hardcoded minimum page width of 0.5cm so it
507 will report a different value than what is actually being used. i.e.
508 it will add up the values to give a wider page than is actually being
509 used.
511 nWWRi = rSection.m_nPgWidth - nWWLe - MINLAY;
514 rSection.m_nPgLeft = nWWLe;
515 rSection.m_nPgRight = nWWRi;
516 rSection.m_nPgGutter = nWWGu;
519 void wwSectionManager::SetPage(SwPageDesc &rInPageDesc, SwFrameFormat &rFormat,
520 const wwSection &rSection, bool bIgnoreCols)
522 // 1. orientation
523 rInPageDesc.SetLandscape(rSection.IsLandScape());
525 // 2. paper size
526 SwFormatFrameSize aSz( rFormat.GetFrameSize() );
527 aSz.SetWidth(rSection.GetPageWidth());
528 aSz.SetHeight(SvxPaperInfo::GetSloppyPaperDimension(rSection.GetPageHeight()));
529 rFormat.SetFormatAttr(aSz);
531 SvxLRSpaceItem aLR(rSection.GetPageLeft(), rSection.GetPageRight(), 0, RES_LR_SPACE);
532 aLR.SetGutterMargin(rSection.m_nPgGutter);
533 rFormat.SetFormatAttr(aLR);
535 SfxBoolItem aRtlGutter(RES_RTL_GUTTER, rSection.m_bRtlGutter);
536 rFormat.SetFormatAttr(aRtlGutter);
538 if (!bIgnoreCols)
539 SetCols(rFormat, rSection, rSection.GetTextAreaWidth());
542 namespace {
543 // Returns corrected (ODF) margin size
544 tools::Long SetBorderDistance(bool bFromEdge, SvxBoxItem& aBox, SvxBoxItemLine eLine, tools::Long nMSMargin)
546 const editeng::SvxBorderLine* pLine = aBox.GetLine(eLine);
547 if (!pLine)
548 return nMSMargin;
549 sal_Int32 nNewMargin = nMSMargin;
550 sal_Int32 nNewDist = aBox.GetDistance(eLine);
551 sal_Int32 nLineWidth = pLine->GetScaledWidth();
553 editeng::BorderDistanceFromWord(bFromEdge, nNewMargin, nNewDist, nLineWidth);
554 aBox.SetDistance(nNewDist, eLine);
556 return nNewMargin;
560 void SwWW8ImplReader::SetPageBorder(SwFrameFormat &rFormat, const wwSection &rSection)
562 if (!IsBorder(rSection.m_brc))
563 return;
565 SfxItemSet aSet(rFormat.GetAttrSet());
566 short aSizeArray[5]={0};
567 SetFlyBordersShadow(aSet, rSection.m_brc, &aSizeArray[0]);
568 SvxLRSpaceItem aLR(aSet.Get(RES_LR_SPACE));
569 SvxULSpaceItem aUL(aSet.Get(RES_UL_SPACE));
570 SvxBoxItem aBox(aSet.Get(RES_BOX));
571 bool bFromEdge = rSection.maSep.pgbOffsetFrom == 1;
573 aLR.SetLeft(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::LEFT, aLR.GetLeft()));
574 aLR.SetRight(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::RIGHT, aLR.GetRight()));
575 aUL.SetUpper(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::TOP, aUL.GetUpper()));
576 aUL.SetLower(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::BOTTOM, aUL.GetLower()));
578 aSet.Put(aBox);
579 aSet.Put(aLR);
580 aSet.Put(aUL);
581 rFormat.SetFormatAttr(aSet);
584 void wwSectionManager::GetPageULData(const wwSection &rSection,
585 wwSectionManager::wwULSpaceData& rData) const
587 sal_Int32 nWWUp = rSection.maSep.dyaTop;
588 sal_Int32 nWWLo = rSection.maSep.dyaBottom;
589 sal_uInt32 nWWHTop = rSection.maSep.dyaHdrTop;
590 sal_uInt32 nWWFBot = rSection.maSep.dyaHdrBottom;
593 If there is gutter in 97+ and the dop says put it on top then get the
594 gutter distance and set it to the top margin. When we are "two pages
595 in one" the gutter is put at the top of odd pages, and bottom of
596 even pages, something we cannot do. So we will put it on top of all
597 pages, that way the pages are at least the right size.
599 if (!mrReader.m_bVer67 && mrReader.m_xWDop->iGutterPos &&
600 rSection.maSep.fRTLGutter)
602 nWWUp += rSection.maSep.dzaGutter;
605 /* Check whether this section has headers / footers */
606 sal_uInt16 nHeaderMask = WW8_HEADER_EVEN | WW8_HEADER_ODD;
607 sal_uInt16 nFooterMask = WW8_FOOTER_EVEN | WW8_FOOTER_ODD;
608 /* Ignore the presence of a first-page header/footer unless it is enabled */
609 if( rSection.HasTitlePage() )
611 nHeaderMask |= WW8_HEADER_FIRST;
612 nFooterMask |= WW8_FOOTER_FIRST;
614 rData.bHasHeader = (rSection.maSep.grpfIhdt & nHeaderMask) != 0;
615 rData.bHasFooter = (rSection.maSep.grpfIhdt & nFooterMask) != 0;
617 if( rData.bHasHeader )
619 rData.nSwUp = nWWHTop; // Header -> convert
620 // #i19922# - correction:
621 // consider that <nWWUp> can be negative, compare only if it's positive
622 if ( nWWUp > 0 &&
623 o3tl::make_unsigned(nWWUp) >= nWWHTop )
624 rData.nSwHLo = nWWUp - nWWHTop;
625 else
626 rData.nSwHLo = 0;
628 // #i19922# - minimum page header height is now 1mm
629 // use new constant <cMinHdFtHeight>
630 if (rData.nSwHLo < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
631 rData.nSwHLo = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
633 else // no header -> just use Up as-is
634 rData.nSwUp = std::abs(nWWUp);
636 if( rData.bHasFooter )
638 rData.nSwLo = nWWFBot; // footer -> convert
639 // #i19922# - correction: consider that <nWWLo> can be negative, compare only if it's positive
640 if ( nWWLo > 0 &&
641 o3tl::make_unsigned(nWWLo) >= nWWFBot )
642 rData.nSwFUp = nWWLo - nWWFBot;
643 else
644 rData.nSwFUp = 0;
646 // #i19922# - minimum page header height is now 1mm
647 // use new constant <cMinHdFtHeight>
648 if (rData.nSwFUp < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
649 rData.nSwFUp = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
651 else // no footer -> just use Lo as-is
652 rData.nSwLo = std::abs(nWWLo);
655 void wwSectionManager::SetPageULSpaceItems(SwFrameFormat &rFormat,
656 wwSectionManager::wwULSpaceData const & rData, const wwSection &rSection)
658 if (rData.bHasHeader) // ... and set Header-Lower
660 // set header height to minimum
661 if (SwFrameFormat* pHdFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat()))
663 SvxULSpaceItem aHdUL(pHdFormat->GetULSpace());
664 if (!rSection.IsFixedHeightHeader()) //normal
666 pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwHLo));
667 // #i19922# - minimum page header height is now 1mm
668 // use new constant <cMinHdFtHeight>
669 aHdUL.SetLower( writer_cast<sal_uInt16>(rData.nSwHLo - cMinHdFtHeight) );
670 pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
671 RES_HEADER_FOOTER_EAT_SPACING, true));
673 else
675 // Hack alert: these calculations are based on
676 // #112727# import negative height headers/footers as floating frames inside fixed height headers/footer
677 // #i48832# - set correct spacing between header and body.
678 const sal_Int32 nHdLowerSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaTop) - rData.nSwUp - rData.nSwHLo));
679 pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwHLo + nHdLowerSpace));
680 aHdUL.SetLower( static_cast< sal_uInt16 >(nHdLowerSpace) );
681 pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
682 RES_HEADER_FOOTER_EAT_SPACING, false));
684 pHdFormat->SetFormatAttr(aHdUL);
688 if (rData.bHasFooter) // ... and set footer-upper
690 if (SwFrameFormat* pFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat()))
692 SvxULSpaceItem aFtUL(pFtFormat->GetULSpace());
693 if (!rSection.IsFixedHeightFooter()) //normal
695 pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwFUp));
696 // #i19922# - minimum page header height is now 1mm
697 // use new constant <cMinHdFtHeight>
698 aFtUL.SetUpper( writer_cast<sal_uInt16>(rData.nSwFUp - cMinHdFtHeight) );
699 pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
700 RES_HEADER_FOOTER_EAT_SPACING, true));
702 else
704 // #i48832# - set correct spacing between footer and body.
705 const sal_Int32 nFtUpperSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaBottom) - rData.nSwLo - rData.nSwFUp));
706 pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwFUp + nFtUpperSpace));
707 aFtUL.SetUpper( static_cast< sal_uInt16 >(nFtUpperSpace) );
708 pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
709 RES_HEADER_FOOTER_EAT_SPACING, false));
711 pFtFormat->SetFormatAttr(aFtUL);
715 SvxULSpaceItem aUL(writer_cast<sal_uInt16>(rData.nSwUp),
716 writer_cast<sal_uInt16>(rData.nSwLo), RES_UL_SPACE);
717 rFormat.SetFormatAttr(aUL);
720 SwSectionFormat *wwSectionManager::InsertSection(
721 SwPaM const & rMyPaM, wwSection &rSection)
723 SwSectionData aSection( SectionType::Content,
724 mrReader.m_rDoc.GetUniqueSectionName() );
726 SfxItemSet aSet( mrReader.m_rDoc.GetAttrPool(), aFrameFormatSetRange );
728 bool bRTLPgn = !maSegments.empty() && maSegments.back().IsBiDi();
729 aSet.Put(SvxFrameDirectionItem(
730 bRTLPgn ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
732 if (2 == mrReader.m_xWDop->fpc)
733 aSet.Put( SwFormatFootnoteAtTextEnd(FTNEND_ATTXTEND));
734 if (0 == mrReader.m_xWDop->epc)
735 aSet.Put( SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
737 aSection.SetProtectFlag(SectionIsProtected(rSection));
739 rSection.mpSection =
740 mrReader.m_rDoc.InsertSwSection( rMyPaM, aSection, nullptr, & aSet );
741 OSL_ENSURE(rSection.mpSection, "section not inserted!");
742 if (!rSection.mpSection)
743 return nullptr;
745 SwPageDesc *pPage = nullptr;
746 auto aIter = std::find_if(maSegments.rbegin(), maSegments.rend(),
747 [](const wwSection& rSegment) { return rSegment.mpPage != nullptr; });
748 if (aIter != maSegments.rend())
749 pPage = aIter->mpPage;
751 OSL_ENSURE(pPage, "no page outside this section!");
753 if (!pPage)
754 pPage = &mrReader.m_rDoc.GetPageDesc(0);
756 SwSectionFormat *pFormat = rSection.mpSection->GetFormat();
757 OSL_ENSURE(pFormat, "impossible");
758 if (!pFormat)
759 return nullptr;
761 SwFrameFormat& rFormat = pPage->GetMaster();
762 const SvxLRSpaceItem& rLR = rFormat.GetLRSpace();
763 tools::Long nPageLeft = rLR.GetLeft();
764 tools::Long nPageRight = rLR.GetRight();
765 tools::Long nSectionLeft = rSection.GetPageLeft() - nPageLeft;
766 tools::Long nSectionRight = rSection.GetPageRight() - nPageRight;
767 if ((nSectionLeft != 0) || (nSectionRight != 0))
769 SvxLRSpaceItem aLR(nSectionLeft, nSectionRight, 0, RES_LR_SPACE);
770 pFormat->SetFormatAttr(aLR);
773 SetCols(*pFormat, rSection, rSection.GetTextAreaWidth());
774 return pFormat;
777 void SwWW8ImplReader::HandleLineNumbering(const wwSection &rSection)
779 // check if Line Numbering must be activated or reset
780 if (!(m_bNewDoc && rSection.maSep.nLnnMod))
781 return;
783 // restart-numbering-mode: 0 per page, 1 per section, 2 never restart
784 bool bRestartLnNumPerSection = (1 == rSection.maSep.lnc);
786 if (m_bNoLnNumYet)
788 SwLineNumberInfo aInfo( m_rDoc.GetLineNumberInfo() );
790 aInfo.SetPaintLineNumbers(true);
792 aInfo.SetRestartEachPage(rSection.maSep.lnc == 0);
794 // A value of 0 (auto) indicates that the application MUST automatically determine positioning.
795 if ( rSection.maSep.dxaLnn )
796 aInfo.SetPosFromLeft(writer_cast<sal_uInt16>(rSection.maSep.dxaLnn));
798 //Paint only for every n line
799 aInfo.SetCountBy(rSection.maSep.nLnnMod);
801 // to be defaulted features ( HARDCODED in MS Word 6,7,8,9 )
802 aInfo.SetCountBlankLines(true);
803 aInfo.SetCountInFlys(false);
804 aInfo.SetPos( LINENUMBER_POS_LEFT );
805 SvxNumberType aNumType; // this sets SVX_NUM_ARABIC per default
806 aInfo.SetNumType( aNumType );
808 m_rDoc.SetLineNumberInfo( aInfo );
809 m_bNoLnNumYet = false;
812 if ((0 < rSection.maSep.lnnMin) || bRestartLnNumPerSection)
814 SwFormatLineNumber aLN;
815 if (const SwFormatLineNumber* pLN
816 = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
818 aLN.SetCountLines( pLN->IsCount() );
820 aLN.SetStartValue(1 + rSection.maSep.lnnMin);
821 NewAttr(aLN);
822 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LINENUMBER);
826 wwSection::wwSection(const SwPosition &rPos) : maStart(rPos.GetNode())
827 , mpSection(nullptr)
828 , mpPage(nullptr)
829 , meDir(SvxFrameDirection::Horizontal_LR_TB)
830 , m_nPgWidth(SvxPaperInfo::GetPaperSize(PAPER_A4).Width())
831 , m_nPgLeft(MM_250)
832 , m_nPgRight(MM_250)
833 , m_nPgGutter(0)
834 , mnVerticalAdjustment(drawing::TextVerticalAdjust_TOP)
835 , mnBorders(0)
836 , mbHasFootnote(false)
840 void wwSectionManager::SetNumberingType(const wwSection &rNewSection,
841 SwPageDesc &rPageDesc)
843 // save page number format
844 static const SvxNumType aNumTyp[5] =
846 SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
847 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N
850 SvxNumberType aType;
851 aType.SetNumberingType( aNumTyp[rNewSection.maSep.nfcPgn] );
852 rPageDesc.SetNumType(aType);
855 // CreateSep is called for every section change (even at the start of
856 // the document. CreateSep also creates the pagedesc(s) and
857 // fills it/them with attributes and KF texts.
858 // This has become necessary because the translation of the various
859 // page attributes is interconnected too much.
860 void wwSectionManager::CreateSep(const tools::Long nTextPos)
863 #i1909# section/page breaks should not occur in tables or subpage
864 elements like frames. Word itself ignores them in this case. The bug is
865 more likely that this filter created such documents in the past!
867 if (mrReader.m_nInTable || mrReader.m_bTxbxFlySection || mrReader.InLocalApo())
868 return;
870 WW8PLCFx_SEPX* pSep = mrReader.m_xPlcxMan->GetSepPLCF();
871 OSL_ENSURE(pSep, "impossible!");
872 if (!pSep)
873 return;
875 if (!maSegments.empty() && mrReader.m_oLastAnchorPos && *mrReader.m_oLastAnchorPos == *mrReader.m_pPaM->GetPoint())
877 bool insert = true;
878 SwPaM pam( *mrReader.m_oLastAnchorPos );
879 if( pam.Move(fnMoveBackward, GoInNode))
880 if( SwTextNode* txtNode = pam.GetPoint()->GetNode().GetTextNode())
881 if( txtNode->Len() == 0 )
882 insert = false;
883 if( insert )
884 mrReader.AppendTextNode(*mrReader.m_pPaM->GetPoint());
887 ww::WordVersion eVer = mrReader.GetFib().GetFIBVersion();
889 // M.M. Create a linked section if the WkbPLCF
890 // has an entry for one at this cp
891 WW8PLCFspecial* pWkb = mrReader.m_xPlcxMan->GetWkbPLCF();
892 if (pWkb && pWkb->SeekPosExact(nTextPos) &&
893 pWkb->Where() == nTextPos)
895 void* pData;
896 WW8_CP nTest;
897 bool bSuccess = pWkb->Get(nTest, pData);
898 if (!bSuccess)
899 return;
900 OUString sSectionName = mrReader.m_aLinkStringMap[SVBT16ToUInt16( static_cast<WW8_WKB*>(pData)->nLinkId) ];
901 sSectionName = mrReader.ConvertFFileName(sSectionName);
902 SwSectionData aSection(SectionType::FileLink, sSectionName);
903 aSection.SetLinkFileName( sSectionName );
904 aSection.SetProtectFlag(true);
905 // #i19922# - improvement: return value of method <Insert> not used.
906 mrReader.m_rDoc.InsertSwSection(*mrReader.m_pPaM, aSection, nullptr, nullptr, false);
909 wwSection aLastSection(*mrReader.m_pPaM->GetPoint());
910 if (!maSegments.empty())
911 aLastSection = maSegments.back();
913 //Here
914 sal_uInt16 nLIdx = ( ( static_cast<sal_uInt16>(mrReader.m_xWwFib->m_lid) & 0xff ) == 0x9 ) ? 1 : 0;
916 //BEGIN read section values
917 wwSection aNewSection(*mrReader.m_pPaM->GetPoint());
919 static const sal_uInt16 aVer2Ids0[] =
921 /*sprmSBkc*/ 117,
922 /*sprmSFTitlePage*/ 118,
923 /*sprmSNfcPgn*/ 122,
924 /*sprmSCcolumns*/ 119,
925 /*sprmSDxaColumns*/ 120,
926 /*sprmSLBetween*/ 133
929 static const sal_uInt16 aVer67Ids0[] =
931 NS_sprm::v6::sprmSBkc,
932 NS_sprm::v6::sprmSFTitlePage,
933 NS_sprm::v6::sprmSNfcPgn,
934 NS_sprm::v6::sprmSCcolumns,
935 NS_sprm::v6::sprmSDxaColumns,
936 NS_sprm::v6::sprmSLBetween
939 static const sal_uInt16 aVer8Ids0[] =
941 NS_sprm::SBkc::val,
942 NS_sprm::SFTitlePage::val,
943 NS_sprm::SNfcPgn::val,
944 NS_sprm::SCcolumns::val,
945 NS_sprm::SDxaColumns::val,
946 NS_sprm::SLBetween::val
949 const sal_uInt16* pIds = eVer <= ww::eWW2 ? aVer2Ids0 : eVer <= ww::eWW7 ? aVer67Ids0 : aVer8Ids0;
951 SprmResult aRes = pSep->HasSprm(pIds[0]);
952 const sal_uInt8* pSprmBkc = aRes.pSprm;
953 if (!maSegments.empty())
955 // Type of break: break codes are:
956 // 0 No break
957 // 1 New column
958 // 2 New page
959 // 3 Even page
960 // 4 Odd page
961 if (pSprmBkc && aRes.nRemainingData >= 1)
962 aNewSection.maSep.bkc = *pSprmBkc;
965 // Has a table page
966 aNewSection.maSep.fTitlePage =
967 sal_uInt8(0 != ReadBSprm( pSep, pIds[1], 0 ));
969 // sprmSNfcPgn
970 aNewSection.maSep.nfcPgn = ReadBSprm( pSep, pIds[2], 0 );
971 if (aNewSection.maSep.nfcPgn > 4)
972 aNewSection.maSep.nfcPgn = 0;
974 aNewSection.maSep.fUnlocked = eVer > ww::eWW2 ? ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFProtected : NS_sprm::SFProtected::val), 0 ) : 0;
976 // sprmSFBiDi
977 aNewSection.maSep.fBiDi = eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFBiDi::val, 0) : 0;
979 // Reading section property sprmSCcolumns - one less than the number of columns in the section.
980 // It must be less than MAX_NO_OF_SEP_COLUMNS according the WW8 specification.
981 aNewSection.maSep.ccolM1 = ReadSprm(pSep, pIds[3], 0 );
982 if ( aNewSection.maSep.ccolM1 >= MAX_NO_OF_SEP_COLUMNS )
984 // clip to max
985 aNewSection.maSep.ccolM1 = MAX_NO_OF_SEP_COLUMNS-1;
988 //sprmSDxaColumns - default distance 1.25 cm
989 aNewSection.maSep.dxaColumns = ReadUSprm( pSep, pIds[4], 708 );
991 // sprmSLBetween
992 aNewSection.maSep.fLBetween = ReadBSprm(pSep, pIds[5], 0 );
994 if (eVer >= ww::eWW6)
996 // sprmSFEvenlySpaced
997 aNewSection.maSep.fEvenlySpaced =
998 sal_uInt8(ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFEvenlySpaced : NS_sprm::SFEvenlySpaced::val), 1) != 0);
1000 if (aNewSection.maSep.ccolM1 > 0 && !aNewSection.maSep.fEvenlySpaced)
1002 int nColumnDataIdx = 0;
1003 aNewSection.maSep.rgdxaColumnWidthSpacing[nColumnDataIdx] = 0;
1005 const sal_uInt16 nColumnWidthSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColWidth : NS_sprm::SDxaColWidth::val);
1006 const sal_uInt16 nColumnSpacingSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColSpacing : NS_sprm::SDxaColSpacing::val);
1007 const sal_uInt8 nColumnCount = static_cast< sal_uInt8 >(aNewSection.maSep.ccolM1 + 1);
1008 for ( sal_uInt8 nColumn = 0; nColumn < nColumnCount; ++nColumn )
1010 //sprmSDxaColWidth
1011 SprmResult aSWRes = pSep->HasSprm(nColumnWidthSprmId, nColumn);
1012 const sal_uInt8* pSW = aSWRes.pSprm;
1014 OSL_ENSURE( pSW, "+Sprm 136 (resp. 0xF203) (ColWidth) missing" );
1015 sal_uInt16 nWidth = (pSW && aSWRes.nRemainingData >= 3) ? SVBT16ToUInt16(pSW + 1) : 1440;
1017 aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
1019 if ( nColumn < nColumnCount - 1 )
1021 //sprmSDxaColSpacing
1022 SprmResult aSDRes = pSep->HasSprm(nColumnSpacingSprmId, nColumn);
1023 const sal_uInt8* pSD = aSDRes.pSprm;
1025 OSL_ENSURE( pSD, "+Sprm 137 (resp. 0xF204) (Colspacing) missing" );
1026 if (pSD && aSDRes.nRemainingData >= 3)
1028 nWidth = SVBT16ToUInt16(pSD + 1);
1029 aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
1036 static const sal_uInt16 aVer2Ids1[] =
1038 /*sprmSBOrientation*/ 137,
1039 /*sprmSXaPage*/ 139,
1040 /*sprmSYaPage*/ 140,
1041 /*sprmSDxaLeft*/ 141,
1042 /*sprmSDxaRight*/ 142,
1043 /*sprmSDzaGutter*/ 145,
1044 /*sprmSFPgnRestart*/ 125,
1045 /*sprmSPgnStart*/ 136,
1046 /*sprmSDmBinFirst*/ 115,
1047 /*sprmSDmBinOther*/ 116
1050 static const sal_uInt16 aVer67Ids1[] =
1052 NS_sprm::v6::sprmSBOrientation,
1053 NS_sprm::v6::sprmSXaPage,
1054 NS_sprm::v6::sprmSYaPage,
1055 NS_sprm::v6::sprmSDxaLeft,
1056 NS_sprm::v6::sprmSDxaRight,
1057 NS_sprm::v6::sprmSDzaGutter,
1058 NS_sprm::v6::sprmSFPgnRestart,
1059 NS_sprm::v6::sprmSPgnStart,
1060 NS_sprm::v6::sprmSDmBinFirst,
1061 NS_sprm::v6::sprmSDmBinOther
1064 static const sal_uInt16 aVer8Ids1[] =
1066 NS_sprm::SBOrientation::val,
1067 NS_sprm::SXaPage::val,
1068 NS_sprm::SYaPage::val,
1069 NS_sprm::SDxaLeft::val,
1070 NS_sprm::SDxaRight::val,
1071 NS_sprm::SDzaGutter::val,
1072 NS_sprm::SFPgnRestart::val,
1073 NS_sprm::SPgnStart97::val,
1074 NS_sprm::SDmBinFirst::val,
1075 NS_sprm::SDmBinOther::val
1078 pIds = eVer <= ww::eWW2 ? aVer2Ids1 : eVer <= ww::eWW7 ? aVer67Ids1 : aVer8Ids1;
1080 // 1. orientation
1081 aNewSection.maSep.dmOrientPage = ReadBSprm(pSep, pIds[0], 0);
1083 // 2. paper size
1084 aNewSection.maSep.xaPage = ReadUSprm(pSep, pIds[1], lLetterWidth);
1085 aNewSection.m_nPgWidth = SvxPaperInfo::GetSloppyPaperDimension(aNewSection.maSep.xaPage);
1087 aNewSection.maSep.yaPage = ReadUSprm(pSep, pIds[2], lLetterHeight);
1089 // 3. LR borders
1090 static const sal_uInt16 nLef[] = { MM_250, 1800 };
1091 static const sal_uInt16 nRig[] = { MM_250, 1800 };
1093 aNewSection.maSep.dxaLeft = ReadUSprm( pSep, pIds[3], nLef[nLIdx]);
1094 aNewSection.maSep.dxaRight = ReadUSprm( pSep, pIds[4], nRig[nLIdx]);
1096 // 2pages in 1sheet hackery ?
1097 // #i31806# but only swap if 2page in 1sheet is enabled.
1098 // it's not clear if dmOrientPage is the correct member to
1099 // decide on this.
1100 if(mrReader.m_xWDop->doptypography.m_f2on1 &&
1101 aNewSection.maSep.dmOrientPage == 2)
1102 std::swap(aNewSection.maSep.dxaLeft, aNewSection.maSep.dxaRight);
1104 aNewSection.maSep.dzaGutter = ReadUSprm( pSep, pIds[5], 0);
1106 aNewSection.maSep.fRTLGutter = static_cast<sal_uInt8>(
1107 eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFRTLGutter::val, 0) : 0);
1109 // Page Number Restarts - sprmSFPgnRestart
1110 aNewSection.maSep.fPgnRestart = ReadBSprm(pSep, pIds[6], 0);
1112 aNewSection.maSep.pgnStart = ReadUSprm( pSep, pIds[7], 0 );
1114 // if the document's first page number is unspecified, but it starts with an even page break,
1115 // then set the first page number to two
1116 if ( maSegments.empty() && !aNewSection.maSep.fPgnRestart && pSprmBkc && *pSprmBkc == 3 )
1118 aNewSection.maSep.pgnStart = 2;
1119 aNewSection.maSep.fPgnRestart = 1;
1122 if (eVer >= ww::eWW6)
1124 aRes = pSep->HasSprm(eVer <= ww::eWW7 ? NS_sprm::v6::sprmSiHeadingPgn : NS_sprm::SiHeadingPgn::val);
1125 if (aRes.pSprm && aRes.nRemainingData >= 1)
1126 aNewSection.maSep.iHeadingPgn = *aRes.pSprm;
1128 aRes = pSep->HasSprm(eVer <= ww::eWW7 ? NS_sprm::v6::sprmSScnsPgn : NS_sprm::ScnsPgn::val);
1129 if (aRes.pSprm && aRes.nRemainingData >= 1)
1130 aNewSection.maSep.cnsPgn = *aRes.pSprm;
1133 aRes = pSep->HasSprm(pIds[8]);
1134 const sal_uInt8* pSprmSDmBinFirst = aRes.pSprm;
1135 if (pSprmSDmBinFirst && aRes.nRemainingData >= 1)
1136 aNewSection.maSep.dmBinFirst = *pSprmSDmBinFirst;
1138 aRes = pSep->HasSprm(pIds[9]);
1139 const sal_uInt8* pSprmSDmBinOther = aRes.pSprm;
1140 if (pSprmSDmBinOther && aRes.nRemainingData >= 1)
1141 aNewSection.maSep.dmBinOther = *pSprmSDmBinOther;
1143 static const sal_uInt16 nTop[] = { MM_250, 1440 };
1144 static const sal_uInt16 nBot[] = { MM_200, 1440 };
1146 static const sal_uInt16 aVer2Ids2[] =
1148 /*sprmSDyaTop*/ 143,
1149 /*sprmSDyaBottom*/ 144,
1150 /*sprmSDyaHdrTop*/ 131,
1151 /*sprmSDyaHdrBottom*/ 132,
1152 /*sprmSNLnnMod*/ 129,
1153 /*sprmSLnc*/ 127,
1154 /*sprmSDxaLnn*/ 130,
1155 /*sprmSLnnMin*/ 135
1158 static const sal_uInt16 aVer67Ids2[] =
1160 NS_sprm::v6::sprmSDyaTop,
1161 NS_sprm::v6::sprmSDyaBottom,
1162 NS_sprm::v6::sprmSDyaHdrTop,
1163 NS_sprm::v6::sprmSDyaHdrBottom,
1164 NS_sprm::v6::sprmSNLnnMod,
1165 NS_sprm::v6::sprmSLnc,
1166 NS_sprm::v6::sprmSDxaLnn,
1167 NS_sprm::v6::sprmSLnnMin
1169 static const sal_uInt16 aVer8Ids2[] =
1171 NS_sprm::SDyaTop::val,
1172 NS_sprm::SDyaBottom::val,
1173 NS_sprm::SDyaHdrTop::val,
1174 NS_sprm::SDyaHdrBottom::val,
1175 NS_sprm::SNLnnMod::val,
1176 NS_sprm::SLnc::val,
1177 NS_sprm::SDxaLnn::val,
1178 NS_sprm::SLnnMin::val
1181 pIds = eVer <= ww::eWW2 ? aVer2Ids2 : eVer <= ww::eWW7 ? aVer67Ids2 : aVer8Ids2;
1183 aNewSection.maSep.dyaTop = ReadSprm( pSep, pIds[0], nTop[nLIdx] );
1184 aNewSection.maSep.dyaBottom = ReadSprm( pSep, pIds[1], nBot[nLIdx] );
1185 aNewSection.maSep.dyaHdrTop = ReadUSprm( pSep, pIds[2], 720 );
1186 aNewSection.maSep.dyaHdrBottom = ReadUSprm( pSep, pIds[3], 720 );
1188 if (eVer >= ww::eWW8)
1190 aNewSection.maSep.wTextFlow = ReadUSprm(pSep, NS_sprm::STextFlow::val, 0);
1191 aNewSection.maSep.clm = ReadUSprm( pSep, NS_sprm::SClm::val, 0 );
1192 aNewSection.maSep.dyaLinePitch = ReadUSprm(pSep, NS_sprm::SDyaLinePitch::val, 360);
1193 aRes = pSep->HasSprm(NS_sprm::SDxtCharSpace::val);
1194 if (aRes.pSprm && aRes.nRemainingData >= 4)
1195 aNewSection.maSep.dxtCharSpace = SVBT32ToUInt32(aRes.pSprm);
1197 //sprmSPgbProp
1198 sal_uInt16 pgbProp = ReadSprm( pSep, NS_sprm::SPgbProp::val, 0 );
1199 aNewSection.maSep.pgbApplyTo = pgbProp & 0x0007;
1200 aNewSection.maSep.pgbPageDepth = (pgbProp & 0x0018) >> 3;
1201 aNewSection.maSep.pgbOffsetFrom = (pgbProp & 0x00E0) >> 5;
1203 aNewSection.mnBorders = ::lcl_ReadBorders(false, aNewSection.m_brc, nullptr, nullptr, pSep);
1206 // check if Line Numbering must be activated or reset
1207 SprmResult aSprmSNLnnMod = pSep->HasSprm(pIds[4]);
1208 if (aSprmSNLnnMod.pSprm && aSprmSNLnnMod.nRemainingData >= 1)
1209 aNewSection.maSep.nLnnMod = *aSprmSNLnnMod.pSprm;
1211 SprmResult aSprmSLnc = pSep->HasSprm(pIds[5]);
1212 if (aSprmSLnc.pSprm && aSprmSLnc.nRemainingData >= 1)
1213 aNewSection.maSep.lnc = *aSprmSLnc.pSprm;
1215 SprmResult aSprmSDxaLnn = pSep->HasSprm(pIds[6]);
1216 if (aSprmSDxaLnn.pSprm && aSprmSDxaLnn.nRemainingData >= 2)
1217 aNewSection.maSep.dxaLnn = SVBT16ToUInt16(aSprmSDxaLnn.pSprm);
1219 SprmResult aSprmSLnnMin = pSep->HasSprm(pIds[7]);
1220 if (aSprmSLnnMin.pSprm && aSprmSLnnMin.nRemainingData >= 1)
1221 aNewSection.maSep.lnnMin = *aSprmSLnnMin.pSprm;
1223 if (eVer <= ww::eWW7)
1224 aNewSection.maSep.grpfIhdt = ReadBSprm(pSep, eVer <= ww::eWW2 ? 128 : 153, 0);
1225 else if (mrReader.m_xHdFt)
1227 aNewSection.maSep.grpfIhdt = WW8_HEADER_ODD | WW8_FOOTER_ODD
1228 | WW8_HEADER_FIRST | WW8_FOOTER_FIRST;
1230 // It is possible for a first page header to be provided
1231 // for this section, but not actually shown in this section. In this
1232 // case (aNewSection.maSep.grpfIhdt & WW8_HEADER_FIRST) will be nonzero
1233 // but aNewSection.HasTitlePage() will be false.
1234 // Likewise for first page footer.
1236 if (mrReader.m_xWDop->fFacingPages)
1237 aNewSection.maSep.grpfIhdt |= WW8_HEADER_EVEN | WW8_FOOTER_EVEN;
1239 //See if we have a header or footer for each enabled possibility
1240 //if we do not then we inherit the previous sections header/footer,
1241 for (int nI = 0, nMask = 1; nI < 6; ++nI, nMask <<= 1)
1243 if (aNewSection.maSep.grpfIhdt & nMask)
1245 WW8_CP nStart, nLen;
1246 mrReader.m_xHdFt->GetTextPosExact( static_cast< short >(nI + ( maSegments.size() + 1) * 6), nStart, nLen);
1247 //No header or footer, inherit previous one, or set to zero
1248 //if no previous one
1249 if (!nLen)
1251 if (
1252 maSegments.empty() ||
1253 !(maSegments.back().maSep.grpfIhdt & nMask)
1256 aNewSection.maSep.grpfIhdt &= ~nMask;
1263 SetLeftRight(aNewSection);
1264 //END read section values
1266 if (eVer >= ww::eWW8)
1267 aNewSection.SetDirection();
1269 mrReader.HandleLineNumbering(aNewSection);
1270 maSegments.push_back(aNewSection);
1273 void SwWW8ImplReader::CopyPageDescHdFt(const SwPageDesc* pOrgPageDesc,
1274 SwPageDesc* pNewPageDesc, sal_uInt8 nCode )
1276 // copy odd header content section
1277 if( nCode & WW8_HEADER_ODD )
1279 m_rDoc.CopyHeader(pOrgPageDesc->GetMaster(),
1280 pNewPageDesc->GetMaster() );
1282 // copy odd footer content section
1283 if( nCode & WW8_FOOTER_ODD )
1285 m_rDoc.CopyFooter(pOrgPageDesc->GetMaster(),
1286 pNewPageDesc->GetMaster());
1288 // copy even header content section
1289 if( nCode & WW8_HEADER_EVEN )
1291 m_rDoc.CopyHeader(pOrgPageDesc->GetLeft(),
1292 pNewPageDesc->GetLeft());
1294 // copy even footer content section
1295 if( nCode & WW8_FOOTER_EVEN )
1297 m_rDoc.CopyFooter(pOrgPageDesc->GetLeft(),
1298 pNewPageDesc->GetLeft());
1300 // copy first page header content section
1301 if( nCode & WW8_HEADER_FIRST )
1303 m_rDoc.CopyHeader(pOrgPageDesc->GetFirstMaster(),
1304 pNewPageDesc->GetFirstMaster());
1306 // copy first page footer content section
1307 if( nCode & WW8_FOOTER_FIRST )
1309 m_rDoc.CopyFooter(pOrgPageDesc->GetFirstMaster(),
1310 pNewPageDesc->GetFirstMaster());
1314 // helper functions for graphics, Apos and tables
1316 // Read BoRder Control structure
1317 // nBrcVer should be set to the version of the BRC record being read (6, 8 or 9)
1318 // This will be converted to the latest format (9).
1319 static bool SetWW8_BRC(int nBrcVer, WW8_BRCVer9& rVar, const sal_uInt8* pS, size_t nLen)
1322 if( pS )
1324 if (nBrcVer == 9 && nLen >= sizeof(WW8_BRCVer9))
1325 rVar = *reinterpret_cast<const WW8_BRCVer9*>(pS);
1326 else if (nBrcVer == 8 && nLen >= sizeof(WW8_BRC))
1327 rVar = WW8_BRCVer9(*reinterpret_cast<const WW8_BRC*>(pS));
1328 else if (nLen >= sizeof(WW8_BRCVer6)) // nBrcVer == 6
1329 rVar = WW8_BRCVer9(WW8_BRC(*reinterpret_cast<const WW8_BRCVer6*>(pS)));
1332 return nullptr != pS;
1335 static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
1336 const WW8RStyle* pSty, const WW8PLCFx_SEPX* pSep)
1339 //returns a sal_uInt8 filled with a bit for each position that had a sprm
1340 //setting that border
1342 sal_uInt8 nBorder = 0;
1343 if( pSep )
1345 if( !bVer67 )
1347 SprmResult a8Sprm[4];
1348 if (pSep->Find4Sprms(
1349 NS_sprm::SBrcTop80::val, NS_sprm::SBrcLeft80::val,
1350 NS_sprm::SBrcBottom80::val, NS_sprm::SBrcRight80::val,
1351 a8Sprm[0], a8Sprm[1], a8Sprm[2], a8Sprm[3]))
1353 for( int i = 0; i < 4; ++i )
1354 nBorder |= int(SetWW8_BRC(8, brc[i], a8Sprm[i].pSprm, a8Sprm[i].nRemainingData))<<i;
1357 // Version 9 BRCs if present will override version 8
1358 SprmResult a9Sprm[4];
1359 if (pSep->Find4Sprms(
1360 NS_sprm::SBrcTop::val, NS_sprm::SBrcLeft::val,
1361 NS_sprm::SBrcBottom::val, NS_sprm::SBrcRight::val,
1362 a9Sprm[0], a9Sprm[1], a9Sprm[2], a9Sprm[3]))
1364 for( int i = 0; i < 4; ++i )
1365 nBorder |= int(SetWW8_BRC(9, brc[i], a9Sprm[i].pSprm, a9Sprm[i].nRemainingData))<<i;
1369 else
1372 static const sal_uInt16 aVer67Ids[5] = {
1373 NS_sprm::v6::sprmPBrcTop,
1374 NS_sprm::v6::sprmPBrcLeft,
1375 NS_sprm::v6::sprmPBrcBottom,
1376 NS_sprm::v6::sprmPBrcRight,
1377 NS_sprm::v6::sprmPBrcBetween
1380 static const sal_uInt16 aVer8Ids[5] = {
1381 NS_sprm::PBrcTop80::val,
1382 NS_sprm::PBrcLeft80::val,
1383 NS_sprm::PBrcBottom80::val,
1384 NS_sprm::PBrcRight80::val,
1385 NS_sprm::PBrcBetween80::val
1388 static const sal_uInt16 aVer9Ids[5] = {
1389 NS_sprm::PBrcTop::val,
1390 NS_sprm::PBrcLeft::val,
1391 NS_sprm::PBrcBottom::val,
1392 NS_sprm::PBrcRight::val,
1393 NS_sprm::PBrcBetween::val
1396 if( pPap )
1398 if (bVer67)
1400 for( int i = 0; i < 5; ++i )
1402 SprmResult aRes(pPap->HasSprm(aVer67Ids[i]));
1403 nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1406 else
1408 for( int i = 0; i < 5; ++i )
1410 SprmResult aRes(pPap->HasSprm(aVer8Ids[i]));
1411 nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1413 // Version 9 BRCs if present will override version 8
1414 for( int i = 0; i < 5; ++i )
1416 SprmResult aRes(pPap->HasSprm(aVer9Ids[i]));
1417 nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1421 else if( pSty )
1423 if (bVer67)
1425 for( int i = 0; i < 5; ++i )
1427 SprmResult aRes(pSty->HasParaSprm(aVer67Ids[i]));
1428 nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1431 else
1433 for( int i = 0; i < 5; ++i )
1435 SprmResult aRes(pSty->HasParaSprm(aVer8Ids[i]));
1436 nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1438 // Version 9 BRCs if present will override version 8
1439 for( int i = 0; i < 5; ++i )
1441 SprmResult aRes(pSty->HasParaSprm(aVer9Ids[i]));
1442 nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1446 else {
1447 OSL_ENSURE( pSty || pPap, "WW8PLCFx_Cp_FKP and WW8RStyle "
1448 "and WW8PLCFx_SEPX is 0" );
1452 return nBorder;
1455 static void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace,
1456 sal_uInt32 cv, short nIdx, SvxBoxItemLine nOOIndex, sal_uInt16 nWWIndex,
1457 short *pSize)
1459 // LO cannot handle outset/inset (new in WW9 BRC) so fall back same as WW8
1460 if ( nIdx == 0x1A || nIdx == 0x1B )
1462 nIdx = (nIdx == 0x1A) ? 0x12 : 0x11;
1463 cv = 0xc0c0c0;
1466 SvxBorderLineStyle const eStyle(
1467 ::editeng::ConvertBorderStyleFromWord(nIdx));
1469 ::editeng::SvxBorderLine aLine;
1470 aLine.SetBorderLineStyle( eStyle );
1471 double const fConverted( (SvxBorderLineStyle::NONE == eStyle) ? 0.0 :
1472 ::editeng::ConvertBorderWidthFromWord(eStyle, nLineThickness, nIdx));
1473 aLine.SetWidth(fConverted);
1475 //No AUTO for borders as yet, so if AUTO, use BLACK
1476 Color col = (cv==0xff000000) ? COL_BLACK : msfilter::util::BGRToRGB(cv);
1478 aLine.SetColor(col);
1480 if (pSize)
1481 pSize[nWWIndex] = fConverted + nSpace;
1483 rBox.SetLine(&aLine, nOOIndex);
1484 rBox.SetDistance(nSpace, nOOIndex);
1488 static void Set1Border(SvxBoxItem &rBox, const WW8_BRCVer9& rBor, SvxBoxItemLine nOOIndex,
1489 sal_uInt16 nWWIndex, short *pSize, const bool bIgnoreSpace)
1491 short nSpace;
1492 short nLineThickness = rBor.DetermineBorderProperties(&nSpace);
1494 GetLineIndex(rBox, nLineThickness, bIgnoreSpace ? 0 : nSpace,
1495 rBor.cv(), rBor.brcType(), nOOIndex, nWWIndex, pSize );
1499 static bool lcl_IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn = false)
1501 return pbrc[WW8_TOP ].brcType() || // brcType != 0
1502 pbrc[WW8_LEFT ].brcType() ||
1503 pbrc[WW8_BOT ].brcType() ||
1504 pbrc[WW8_RIGHT].brcType() ||
1505 (bChkBtwn && pbrc[WW8_BETW ].brcType());
1508 bool SwWW8ImplReader::IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn)
1510 return lcl_IsBorder(pbrc, bChkBtwn);
1513 bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRCVer9* pbrc,
1514 short *pSizeArray, sal_uInt8 nSetBorders)
1516 bool bChange = false;
1517 static const std::pair<sal_uInt16, SvxBoxItemLine> aIdArr[] =
1519 { WW8_TOP, SvxBoxItemLine::TOP },
1520 { WW8_LEFT, SvxBoxItemLine::LEFT },
1521 { WW8_RIGHT, SvxBoxItemLine::RIGHT },
1522 { WW8_BOT, SvxBoxItemLine::BOTTOM },
1523 { WW8_BETW, SvxBoxItemLine::BOTTOM }
1526 for( int i = 0; i < 4; ++i )
1528 // filter out the invalid borders
1529 const WW8_BRCVer9& rB = pbrc[ aIdArr[ i ].first ];
1530 if( !rB.isNil() && rB.brcType() )
1532 Set1Border(rBox, rB, aIdArr[i].second, aIdArr[i].first, pSizeArray, false);
1533 bChange = true;
1535 else if ( nSetBorders & (1 << aIdArr[i].first) )
1538 ##826##, ##653##
1540 If a style has borders set,and the para attributes attempt remove
1541 the borders, then this is perfectly acceptable, so we shouldn't
1542 ignore this blank entry
1544 nSetBorders has a bit set for each location that a sprm set a
1545 border, so with a sprm set, but no border, then disable the
1546 appropriate border
1548 rBox.SetLine( nullptr, aIdArr[ i ].second );
1551 return bChange;
1554 bool SwWW8ImplReader::SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
1555 const WW8_BRCVer9& aRightBrc)
1557 bool bRet = aRightBrc.fShadow() && pSizeArray && pSizeArray[WW8_RIGHT];
1558 if (bRet)
1560 rShadow.SetColor(COL_BLACK);
1561 //i120718
1562 short nVal = aRightBrc.DetermineBorderProperties();
1563 //End
1564 if (nVal < 0x10)
1565 nVal = 0x10;
1566 rShadow.SetWidth(nVal);
1567 rShadow.SetLocation(SvxShadowLocation::BottomRight);
1568 bRet = true;
1570 return bRet;
1573 void SwWW8ImplReader::GetBorderDistance(const WW8_BRCVer9* pbrc,
1574 tools::Rectangle& rInnerDist)
1576 rInnerDist = tools::Rectangle( pbrc[ 1 ].dptSpace() * 20,
1577 pbrc[ 0 ].dptSpace() * 20,
1578 pbrc[ 3 ].dptSpace() * 20,
1579 pbrc[ 2 ].dptSpace() * 20 );
1582 bool SwWW8ImplReader::SetFlyBordersShadow(SfxItemSet& rFlySet,
1583 const WW8_BRCVer9 *pbrc, short *pSizeArray)
1585 bool bShadowed = false;
1586 if (IsBorder(pbrc))
1588 SvxBoxItem aBox( RES_BOX );
1589 SetBorder(aBox, pbrc, pSizeArray);
1591 rFlySet.Put( aBox );
1593 // fShadow
1594 SvxShadowItem aShadow( RES_SHADOW );
1595 if( SetShadow( aShadow, pSizeArray, pbrc[WW8_RIGHT] ))
1597 bShadowed = true;
1598 rFlySet.Put( aShadow );
1601 return bShadowed;
1604 // APOs
1606 // for computing the minimal FrameSize
1607 #define MAX_BORDER_SIZE 210 // max. size of border
1608 #define MAX_EMPTY_BORDER 10 // for off-by-one errors, at least 1
1610 static void FlySecur1(short& rSize, const bool bBorder)
1612 short nMin = MINFLY +
1613 (bBorder ? MAX_BORDER_SIZE : MAX_EMPTY_BORDER);
1615 if ( rSize < nMin )
1616 rSize = nMin;
1619 static bool SetValSprm( sal_Int16* pVar, WW8PLCFx_Cp_FKP* pPap, sal_uInt16 nId )
1621 SprmResult aS = pPap->HasSprm(nId);
1622 if (aS.pSprm && aS.nRemainingData >= 2)
1623 *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
1624 return aS.pSprm != nullptr;
1627 static bool SetValSprm( sal_Int16* pVar, const WW8RStyle* pStyle, sal_uInt16 nId )
1629 SprmResult aS = pStyle->HasParaSprm(nId);
1630 if (aS.pSprm && aS.nRemainingData >= 2)
1631 *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
1632 return aS.pSprm != nullptr;
1636 #i1930 revealed that sprm 0x360D (sprmTPc) as used in tables can affect the frame
1637 around the table. Its full structure is not fully understood as yet.
1639 void WW8FlyPara::ApplyTabPos(const WW8_TablePos *pTabPos)
1641 if (pTabPos)
1643 nTDxaAbs = pTabPos->nTDxaAbs;
1644 nTDyaAbs = pTabPos->nTDyaAbs;
1645 nTPc = pTabPos->nTPc;
1646 nLeftMargin = pTabPos->nLeftMargin;
1647 nRightMargin = pTabPos->nRightMargin;
1648 nUpperMargin = pTabPos->nUpperMargin;
1649 nLowerMargin = pTabPos->nLowerMargin;
1650 nPWr = pTabPos->nPWr;
1654 WW8FlyPara::WW8FlyPara(bool bIsVer67, const WW8FlyPara* pSrc /* = 0 */)
1656 if ( pSrc )
1657 memcpy( this, pSrc, sizeof( WW8FlyPara ) ); // Copy-Ctor
1658 else
1660 nTDxaAbs = 0;
1661 nTDyaAbs = 0;
1662 nSp45 = 0;
1663 nSp28 = 0;
1664 nLeftMargin = 0;
1665 nRightMargin = 0;
1666 nUpperMargin = 0;
1667 nLowerMargin = 0;
1668 nTPc = 0;
1669 nPWr = 2; // Default: wrapping
1670 bBorderLines = false;
1671 bGrafApo = false;
1672 mbVertSet = false;
1674 bVer67 = bIsVer67;
1677 bool WW8FlyPara::operator==(const WW8FlyPara& rSrc) const
1680 Compare the parts that word seems to compare for equivalence.
1681 Interestingly being autoheight or absolute height (the & 0x7fff) doesn't
1682 matter to word
1684 return
1686 (nTDxaAbs == rSrc.nTDxaAbs) &&
1687 (nTDyaAbs == rSrc.nTDyaAbs) &&
1688 ((nSp45 & 0x7fff) == (rSrc.nSp45 & 0x7fff)) &&
1689 (nSp28 == rSrc.nSp28) &&
1690 (nLeftMargin == rSrc.nLeftMargin) &&
1691 (nRightMargin == rSrc.nRightMargin) &&
1692 (nUpperMargin == rSrc.nUpperMargin) &&
1693 (nLowerMargin == rSrc.nLowerMargin) &&
1694 (nTPc == rSrc.nTPc) &&
1695 (nPWr == rSrc.nPWr)
1699 // Read for normal text
1700 void WW8FlyPara::Read(sal_uInt8 nOrigSprmTPc, WW8PLCFx_Cp_FKP* pPap)
1702 if( bVer67 )
1704 SetValSprm( &nTDxaAbs, pPap, 26 ); // X-position //sprmPDxaAbs
1705 //set in me or in parent style
1706 mbVertSet |= SetValSprm( &nTDyaAbs, pPap, 27 ); // Y-position //sprmPDyaAbs
1707 SetValSprm( &nSp45, pPap, 45 ); // height //sprmPWHeightAbs
1708 SetValSprm( &nSp28, pPap, 28 ); // width //sprmPDxaWidth
1709 SetValSprm( &nLeftMargin, pPap, 49 ); // L-border //sprmPDxaFromText
1710 SetValSprm( &nRightMargin, pPap, 49 ); // R-border //sprmPDxaFromText
1711 SetValSprm( &nUpperMargin, pPap, 48 ); // U-border //sprmPDyaFromText
1712 SetValSprm( &nLowerMargin, pPap, 48 ); // D-border //sprmPDyaFromText
1714 SprmResult aS = pPap->HasSprm(NS_sprm::v6::sprmPWr);
1715 if (aS.pSprm && aS.nRemainingData >= 1)
1716 nPWr = *aS.pSprm;
1718 else
1720 SetValSprm( &nTDxaAbs, pPap, NS_sprm::PDxaAbs::val ); // X-position
1721 //set in me or in parent style
1722 mbVertSet |= SetValSprm( &nTDyaAbs, pPap, NS_sprm::PDyaAbs::val ); // Y-position
1723 SetValSprm( &nSp45, pPap, NS_sprm::PWHeightAbs::val ); // height
1724 SetValSprm( &nSp28, pPap, NS_sprm::PDxaWidth::val ); // width
1725 SetValSprm( &nLeftMargin, pPap, NS_sprm::PDxaFromText::val ); // L-border
1726 SetValSprm( &nRightMargin, pPap, NS_sprm::PDxaFromText::val ); // R-border
1727 SetValSprm( &nUpperMargin, pPap, NS_sprm::PDyaFromText::val ); // U-border
1728 SetValSprm( &nLowerMargin, pPap, NS_sprm::PDyaFromText::val ); // D-border
1730 SprmResult aS = pPap->HasSprm(NS_sprm::PWr::val); // wrapping
1731 if (aS.pSprm && aS.nRemainingData >= 1)
1732 nPWr = *aS.pSprm;
1735 if( ::lcl_ReadBorders( bVer67, brc, pPap )) // borders
1736 bBorderLines = ::lcl_IsBorder( brc );
1739 #i8798#
1740 Appears that with no dyaAbs set then the actual vert anchoring set is
1741 ignored and we remain relative to text, so if that is the case we are 0
1742 from para anchor, so we update the frame to have explicitly this type of
1743 anchoring
1745 if (!mbVertSet)
1746 nTPc = (nOrigSprmTPc & 0xCF) | 0x20;
1747 else
1748 nTPc = nOrigSprmTPc;
1751 void WW8FlyPara::ReadFull(sal_uInt8 nOrigSprmTPc, SwWW8ImplReader* pIo)
1753 std::shared_ptr<WW8PLCFMan> xPlcxMan = pIo->m_xPlcxMan;
1754 WW8PLCFx_Cp_FKP* pPap = xPlcxMan->GetPapPLCF();
1756 Read(nOrigSprmTPc, pPap); // read Apo parameter
1758 do{ // block for quick exit
1759 if( nSp45 != 0 /* || nSp28 != 0 */ )
1760 break; // bGrafApo only automatic for height
1761 if( pIo->m_xWwFib->m_fComplex )
1762 break; // (*pPap)++ does not work for FastSave
1763 // -> for FastSave, no test for graphics APO
1764 SvStream* pIoStrm = pIo->m_pStrm;
1765 sal_uInt64 nPos = pIoStrm->Tell();
1766 WW8PLCFxSave1 aSave;
1767 xPlcxMan->GetPap()->Save( aSave );
1768 bGrafApo = false;
1770 do{ // block for quick exit
1771 sal_uInt8 nText[2];
1773 if (!checkRead(*pIoStrm, nText, 2)) // read text
1774 break;
1776 if( nText[0] != 0x01 || nText[1] != 0x0d )// only graphics + CR?
1777 break; // no
1779 pPap->advance(); // next line
1781 // in APO ?
1782 //sprmPPc
1783 SprmResult aS = pPap->HasSprm( bVer67 ? NS_sprm::v6::sprmPPc : NS_sprm::PPc::val);
1785 // no -> graphics Apo
1786 if (!aS.pSprm || aS.nRemainingData < 1)
1788 bGrafApo = true;
1789 break; // end of APO
1792 ww::WordVersion eVer = pIo->GetFib().GetFIBVersion();
1793 WW8FlyPara *pNowStyleApo=nullptr;
1794 sal_uInt16 nColl = pPap->GetIstd();
1796 o3tl::sorted_vector<sal_uInt16> aSeenStyles;
1797 ww::sti eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc(nColl) : static_cast<ww::sti>(nColl);
1798 while (eSti != ww::stiNil && static_cast<size_t>(nColl) < pIo->m_vColl.size() && nullptr == (pNowStyleApo = pIo->m_vColl[nColl].m_xWWFly.get()))
1800 aSeenStyles.insert(nColl);
1802 nColl = pIo->m_vColl[nColl].m_nBase;
1804 if (aSeenStyles.find(nColl) != aSeenStyles.end())
1806 SAL_WARN("sw.ww8", "loop in style chain");
1807 break;
1810 eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc(nColl) : static_cast<ww::sti>(nColl);
1813 WW8FlyPara aF(bVer67, pNowStyleApo);
1814 // new FlaPara for comparison
1815 aF.Read(*aS.pSprm, pPap); // WWPara for new Para
1816 if( !( aF == *this ) ) // same APO? (or a new one?)
1817 bGrafApo = true; // no -> 1-line APO
1818 // -> graphics APO
1820 while( false ); // block for quick exit
1822 xPlcxMan->GetPap()->Restore( aSave );
1823 pIoStrm->Seek( nPos );
1824 }while( false ); // block for quick exit
1827 // read for Apo definitions in Styledefs
1828 void WW8FlyPara::Read(sal_uInt8 nOrigSprmTPc, WW8RStyle const * pStyle)
1830 if (bVer67)
1832 SetValSprm( &nTDxaAbs, pStyle, NS_sprm::v6::sprmPDxaAbs ); // X-position
1833 //set in me or in parent style
1834 mbVertSet |= SetValSprm(&nTDyaAbs, pStyle, NS_sprm::v6::sprmPDyaAbs); // Y-position
1835 SetValSprm( &nSp45, pStyle, NS_sprm::v6::sprmPWHeightAbs ); // height
1836 SetValSprm( &nSp28, pStyle, NS_sprm::v6::sprmPDxaWidth ); // width
1837 SetValSprm( &nLeftMargin, pStyle, NS_sprm::v6::sprmPDxaFromText ); // L-border
1838 SetValSprm( &nRightMargin, pStyle, NS_sprm::v6::sprmPDxaFromText ); // R-border
1839 SetValSprm( &nUpperMargin, pStyle, NS_sprm::v6::sprmPDyaFromText ); // U-border
1840 SetValSprm( &nLowerMargin, pStyle, NS_sprm::v6::sprmPDyaFromText ); // D-border
1842 SprmResult aS = pStyle->HasParaSprm( NS_sprm::v6::sprmPWr ); // wrapping
1843 if (aS.pSprm && aS.nRemainingData >= 1)
1844 nPWr = *aS.pSprm;
1846 else
1848 SetValSprm( &nTDxaAbs, pStyle, NS_sprm::PDxaAbs::val ); // X-position
1849 //set in me or in parent style
1850 mbVertSet |= SetValSprm(&nTDyaAbs, pStyle, NS_sprm::PDyaAbs::val); // Y-position
1851 SetValSprm( &nSp45, pStyle, NS_sprm::PWHeightAbs::val ); // height
1852 SetValSprm( &nSp28, pStyle, NS_sprm::PDxaWidth::val ); // width
1853 SetValSprm( &nLeftMargin, pStyle, NS_sprm::PDxaFromText::val ); // L-border
1854 SetValSprm( &nRightMargin, pStyle, NS_sprm::PDxaFromText::val ); // R-border
1855 SetValSprm( &nUpperMargin, pStyle, NS_sprm::PDyaFromText::val ); // U-border
1856 SetValSprm( &nLowerMargin, pStyle, NS_sprm::PDyaFromText::val ); // D-border
1858 SprmResult aS = pStyle->HasParaSprm( NS_sprm::PWr::val ); // wrapping
1859 if (aS.pSprm && aS.nRemainingData >= 1)
1860 nPWr = *aS.pSprm;
1863 if (::lcl_ReadBorders(bVer67, brc, nullptr, pStyle)) // border
1864 bBorderLines = ::lcl_IsBorder(brc);
1867 #i8798#
1868 Appears that with no dyaAbs set then the actual vert anchoring set is
1869 ignored and we remain relative to text, so if that is the case we are 0
1870 from para anchor, so we update the frame to have explicitly this type of
1871 anchoring
1873 if (!mbVertSet)
1874 nTPc = (nOrigSprmTPc & 0xCF) | 0x20;
1875 else
1876 nTPc = nOrigSprmTPc;
1879 bool WW8FlyPara::IsEmpty() const
1881 WW8FlyPara aEmpty(bVer67);
1883 wr of 0 like 2 appears to me to be equivalent for checking here. See
1884 #107103# if wrong, so given that the empty is 2, if we are 0 then set
1885 empty to 0 to make 0 equiv to 2 for empty checking
1887 OSL_ENSURE(aEmpty.nPWr == 2, "this is not what we expect for nPWr");
1888 if (this->nPWr == 0)
1889 aEmpty.nPWr = 0;
1890 return aEmpty == *this;
1893 // #i18732# - changes made on behalf of CMC
1894 WW8SwFlyPara::WW8SwFlyPara( SwPaM& rPaM,
1895 SwWW8ImplReader& rIo,
1896 WW8FlyPara& rWW,
1897 const sal_uInt32 nWWPgTop,
1898 const sal_uInt32 nPgWidth,
1899 const sal_Int32 nIniFlyDx,
1900 const sal_Int32 nIniFlyDy ):
1901 nXPos(0),
1902 nYPos(0),
1903 nLeftMargin(rWW.nLeftMargin),
1904 nRightMargin(rWW.nRightMargin),
1905 nUpperMargin(rWW.nUpperMargin),
1906 nLowerMargin(rWW.nLowerMargin),
1907 nWidth(rWW.nSp28),
1908 nHeight(rWW.nSp45),
1909 nNetWidth(rWW.nSp28),
1910 eHeightFix(SwFrameSize::Fixed),
1911 eHRel(text::RelOrientation::PAGE_FRAME),
1912 eVRel(text::RelOrientation::FRAME),
1913 eVAlign(text::VertOrientation::NONE),
1914 eHAlign(text::HoriOrientation::NONE),
1915 nXBind(( rWW.nTPc & 0xc0 ) >> 6),
1916 nYBind(( rWW.nTPc & 0x30 ) >> 4),
1917 nNewNetWidth(MINFLY),
1918 nLineSpace(0),
1919 bAutoWidth(false),
1920 bTogglePos(false)
1922 switch(rWW.nPWr)
1924 case 0: // ST_Wrap: auto
1925 eSurround = css::text::WrapTextMode_DYNAMIC;
1926 break;
1927 case 1: // ST_Wrap: notBeside
1928 case 3: // ST_Wrap: none
1929 eSurround = css::text::WrapTextMode_NONE;
1930 break;
1931 case 2: // ST_Wrap: around
1932 case 4: // ST_Wrap: tight
1933 eSurround = css::text::WrapTextMode_PARALLEL;
1934 break;
1935 case 5: // St_Wrap: through
1936 eSurround = css::text::WrapTextMode_THROUGH;
1937 break;
1938 default:
1939 eSurround = css::text::WrapTextMode_DYNAMIC;
1943 #95905#, #83307# seems to have gone away now, so re-enable parallel
1944 wrapping support for frames in headers/footers. I don't know if we truly
1945 have an explicitly specified behaviour for these circumstances.
1948 if( nHeight & 0x8000 )
1950 nHeight &= 0x7fff;
1951 eHeightFix = SwFrameSize::Minimum;
1954 if( nHeight <= MINFLY )
1955 { // no data, or bad data
1956 eHeightFix = SwFrameSize::Minimum;
1957 nHeight = MINFLY;
1960 if( nWidth <= 10 ) // auto width
1962 bAutoWidth = true;
1963 nWidth = nNetWidth =
1964 msword_cast<sal_Int16>(nPgWidth ? nPgWidth : 2268); // 4 cm
1966 if( nWidth <= MINFLY )
1967 nWidth = nNetWidth = MINFLY; // minimum width
1970 See issue #i9178# for the 9 anchoring options, and make sure they stay
1971 working if you modify the anchoring logic here.
1974 // If the Fly is aligned left, right, up, or down,
1975 // the outer text distance will be ignored, because otherwise
1976 // the Fly will end up in the wrong position.
1977 // The only problem is with inside/outside.
1979 //#i53725# - absolute positioned objects have to be
1980 // anchored at-paragraph to assure its correct anchor position.
1981 rIo.m_oLastAnchorPos.emplace(*rPaM.GetPoint());
1983 switch (nYBind)
1985 case 0: //relative to margin
1986 eVRel = text::RelOrientation::PAGE_PRINT_AREA;
1987 break;
1988 case 1: //relative to page
1989 eVRel = text::RelOrientation::PAGE_FRAME;
1990 break;
1991 default: //relative to text
1992 // put in initialization part eVRel = text::RelOrientation::FRAME;
1993 break;
1996 // #i18732#
1997 switch( rWW.nTDyaAbs ) // particular Y-positions ?
1999 case 0: // inline
2000 // Specifies that the parent object shall be vertically aligned in line
2001 // with the surrounding text (i.e. shall not allow any text wrapping around it)
2002 eVRel = text::RelOrientation::FRAME;
2003 break;
2004 case -4:
2005 eVAlign = text::VertOrientation::TOP;
2006 if (nYBind < 2)
2007 nUpperMargin = 0;
2008 break; // up
2009 case -8:
2010 eVAlign = text::VertOrientation::CENTER;
2011 break; // centered
2012 case -12:
2013 eVAlign = text::VertOrientation::BOTTOM;
2014 if (nYBind < 2)
2015 nLowerMargin = 0;
2016 break; // down
2017 default:
2018 nYPos = rWW.nTDyaAbs + static_cast<short>(nIniFlyDy);
2019 break; // corrections from ini file
2022 switch( rWW.nTDxaAbs ) // particular X-positions ?
2024 case 0:
2025 eHAlign = text::HoriOrientation::LEFT;
2026 nLeftMargin = 0;
2027 break; // left
2028 case -4:
2029 eHAlign = text::HoriOrientation::CENTER;
2030 break; // centered
2031 case -8:
2032 eHAlign = text::HoriOrientation::RIGHT;
2033 nRightMargin = 0;
2034 break; // right
2035 case -12:
2036 eHAlign = text::HoriOrientation::LEFT;
2037 bTogglePos = true;
2038 break; // inside
2039 case -16:
2040 eHAlign = text::HoriOrientation::RIGHT;
2041 bTogglePos = true;
2042 break; // outside
2043 default:
2044 nXPos = rWW.nTDxaAbs + static_cast<short>(nIniFlyDx);
2045 break; // corrections from ini file
2048 // #i18732#
2049 switch (nXBind) // X - binding -> transform coordinates
2051 case 0: //relative to column
2052 eHRel = text::RelOrientation::FRAME;
2053 break;
2054 case 1: //relative to margin
2055 eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2056 break;
2057 default: //relative to page
2058 // put in initialization part eHRel= text::RelOrientation::PAGE_FRAME;
2059 break;
2062 // #i36649# - adjustments for certain horizontal alignments
2063 // Note: These special adjustments found by an investigation of documents
2064 // containing frames with different left/right border distances and
2065 // distances to text. The outcome is somehow strange.
2066 // Note: These adjustments causes wrong horizontal positions for frames,
2067 // which are aligned inside|outside to page|margin on even pages,
2068 // the left and right border distances are different.
2069 // no adjustments possible, if frame has automatic width.
2070 // determine left border distance
2071 sal_Int16 nLeBorderMgn( 0 );
2072 if ( !bAutoWidth )
2074 WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2075 sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeBorderMgn);
2076 nLeBorderMgn = nLeBorderMgn + nTemp;
2078 // determine right border distance
2079 sal_Int16 nRiBorderMgn( 0 );
2080 if ( !bAutoWidth )
2082 WW8_BRCVer9 &rBrc = rWW.brc[WW8_RIGHT];
2083 sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nRiBorderMgn);
2084 nRiBorderMgn = nRiBorderMgn + nTemp;
2086 if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_FRAME )
2088 // convert 'left to page' to
2089 // 'from left -<width>-<2*left border distance>-<right wrap distance>
2090 // to page text area'
2091 eHAlign = text::HoriOrientation::NONE;
2092 eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2093 nXPos = -nWidth - (2*nLeBorderMgn) - rWW.nRightMargin;
2094 // re-set left wrap distance
2095 nLeftMargin = rWW.nLeftMargin;
2097 else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_FRAME )
2099 // convert 'right to page' to
2100 // 'from left <right border distance-left border distance>+<left wrap distance>
2101 // to right page border'
2102 eHAlign = text::HoriOrientation::NONE;
2103 eHRel = text::RelOrientation::PAGE_RIGHT;
2104 nXPos = ( nRiBorderMgn - nLeBorderMgn ) + rWW.nLeftMargin;
2105 // re-set right wrap distance
2106 nRightMargin = rWW.nRightMargin;
2108 else if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2110 // convert 'left to margin' to
2111 // 'from left -<left border distance> to page text area'
2112 eHAlign = text::HoriOrientation::NONE;
2113 eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2114 nXPos = -nLeBorderMgn;
2115 // re-set left wrap distance
2116 nLeftMargin = rWW.nLeftMargin;
2118 else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2120 // convert 'right to margin' to
2121 // 'from left -<width>-<left border distance> to right page border'
2122 eHAlign = text::HoriOrientation::NONE;
2123 eHRel = text::RelOrientation::PAGE_RIGHT;
2124 nXPos = -nWidth - nLeBorderMgn;
2125 // re-set right wrap distance
2126 nRightMargin = rWW.nRightMargin;
2128 else if (rWW.bBorderLines)
2131 #i582#
2132 Word has a curious bug where the offset stored do not take into
2133 account the internal distance from the corner both
2135 WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2136 sal_Int16 nLeLMgn = 0;
2137 sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeLMgn);
2138 nLeLMgn = nLeLMgn + nTemp;
2140 if (nLeLMgn)
2142 if (eHAlign == text::HoriOrientation::LEFT)
2143 eHAlign = text::HoriOrientation::NONE;
2144 nXPos = nXPos - nLeLMgn;
2148 // adjustments for certain vertical alignments
2149 if ( eVAlign == text::VertOrientation::NONE && eVRel == text::RelOrientation::PAGE_PRINT_AREA )
2151 // convert "<X> from top page text area" to
2152 // "<X + page top margin> from page"
2153 eVRel = text::RelOrientation::PAGE_FRAME;
2154 nYPos = static_cast< sal_Int16 >( nYPos + nWWPgTop );
2157 FlySecur1( nWidth, rWW.bBorderLines ); // Do the borders match ?
2158 FlySecur1( nHeight, rWW.bBorderLines );
2162 // If a Fly in WW has automatic width, this has to be simulated
2163 // by modifying the Fly width (fixed in SW) afterwards.
2164 // This can increase or decrease the Fly width, because the default value
2165 // is set without knowledge of the contents.
2166 void WW8SwFlyPara::BoxUpWidth( tools::Long nInWidth )
2168 if( bAutoWidth && nInWidth > nNewNetWidth )
2169 nNewNetWidth = nInWidth;
2172 SwFlyFrameFormat* WW8SwFlyPara::GetFlyFormat() const
2174 if (!m_xFlyFormat)
2175 return nullptr;
2176 return static_cast<SwFlyFrameFormat*>(m_xFlyFormat->GetFormat());
2179 void WW8SwFlyPara::SetFlyFormat(SwFlyFrameFormat* pNewFlyFormat)
2181 if (pNewFlyFormat)
2182 m_xFlyFormat.reset(new FrameDeleteWatch(pNewFlyFormat));
2183 else
2184 m_xFlyFormat.reset();
2187 // The class WW8FlySet is derived from SfxItemSetFixed and does not
2188 // provide more, but is easier to handle for me.
2189 // WW8FlySet-ctor for Apos and graphics Apos
2190 WW8FlySet::WW8FlySet(SwWW8ImplReader& rReader, const WW8FlyPara* pFW,
2191 const WW8SwFlyPara* pFS, bool bGraf)
2192 : SfxItemSetFixed(rReader.m_rDoc.GetAttrPool())
2194 Reader::ResetFrameFormatAttrs(*this); // remove distance/border
2195 // position
2196 Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2198 /*Below can all go when we have from left in rtl mode*/
2199 SwTwips nXPos = pFS->nXPos;
2200 sal_Int16 eHRel = pFS->eHRel;
2201 rReader.MiserableRTLGraphicsHack(nXPos, pFS->nWidth, pFS->eHAlign, eHRel);
2202 /*Above can all go when we have from left in rtl mode*/
2203 Put( SwFormatHoriOrient(nXPos, pFS->eHAlign, pFS->eHRel, pFS->bTogglePos ));
2204 Put( SwFormatVertOrient( pFS->nYPos, pFS->eVAlign, pFS->eVRel ) );
2206 if (pFS->nLeftMargin || pFS->nRightMargin) // set borders
2207 Put(SvxLRSpaceItem(pFS->nLeftMargin, pFS->nRightMargin, 0, RES_LR_SPACE));
2209 if (pFS->nUpperMargin || pFS->nLowerMargin)
2210 Put(SvxULSpaceItem(pFS->nUpperMargin, pFS->nLowerMargin, RES_UL_SPACE));
2212 //we no longer need to hack around the header/footer problems
2213 SwFormatSurround aSurround(pFS->eSurround);
2214 if ( pFS->eSurround == css::text::WrapTextMode_DYNAMIC )
2215 aSurround.SetAnchorOnly( true );
2216 Put( aSurround );
2218 short aSizeArray[5]={0};
2219 SwWW8ImplReader::SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
2221 // the 5th parameter is always 0, thus we lose nothing due to the cast
2223 // #i27767#
2224 // #i35017# - constant name has changed
2225 Put( SwFormatWrapInfluenceOnObjPos(
2226 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) );
2228 if( bGraf )
2229 return;
2231 Put( SwFormatAnchor(WW8SwFlyPara::eAnchor) );
2232 // adjust size
2234 //Ordinarily with frames, the border width and spacing is
2235 //placed outside the frame, making it larger. With these
2236 //types of frames, the left right thickness and space makes
2237 //it wider, but the top bottom spacing and border thickness
2238 //is placed inside.
2239 Put( SwFormatFrameSize( pFS->eHeightFix, pFS->nWidth +
2240 aSizeArray[WW8_LEFT] + aSizeArray[WW8_RIGHT],
2241 pFS->nHeight));
2244 // WW8FlySet-ctor for character bound graphics
2245 WW8FlySet::WW8FlySet( SwWW8ImplReader& rReader, const SwPaM* pPaM,
2246 const WW8_PIC& rPic, tools::Long nWidth, tools::Long nHeight )
2247 : SfxItemSetFixed<RES_FRMATR_BEGIN,RES_FRMATR_END-1>(rReader.m_rDoc.GetAttrPool())
2249 Init(rReader, pPaM);
2251 Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2253 short aSizeArray[5]={0};
2255 If we have set borders then in word the graphic is displaced from the left
2256 and top the width of the borders of those sides, and then the shadow
2257 itself is drawn to the bottom and right of the displaced graphic. In word
2258 the total size is that of the graphic plus the borders, plus the total
2259 shadow around all edges, for this translation the top and left shadow
2260 region is translated spacing around the graphic to those sides, and the
2261 bottom and right shadow size is added to the graphic size.
2263 WW8_BRCVer9 brcVer9[4];
2264 for (int i = 0; i < 4; i++)
2265 brcVer9[i] = WW8_BRCVer9(rPic.rgbrc[i]);
2266 if (SwWW8ImplReader::SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
2268 Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, RES_LR_SPACE ) );
2269 Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
2270 aSizeArray[WW8_RIGHT]*=2;
2271 aSizeArray[WW8_BOT]*=2;
2274 Put( SwFormatFrameSize( SwFrameSize::Fixed, nWidth+aSizeArray[WW8_LEFT]+
2275 aSizeArray[WW8_RIGHT], nHeight+aSizeArray[WW8_TOP]
2276 + aSizeArray[WW8_BOT]) );
2279 void WW8FlySet::Init(const SwWW8ImplReader& rReader, const SwPaM* pPaM)
2281 Reader::ResetFrameFormatAttrs(*this); // remove distance/borders
2283 Put(SvxLRSpaceItem(RES_LR_SPACE)); //inline writer ole2 objects start with 0.2cm l/r
2284 SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
2286 aAnchor.SetAnchor(pPaM->GetPoint());
2287 Put(aAnchor);
2289 //The horizontal default is on the baseline, the vertical is centered
2290 //around the character center it appears
2291 if (rReader.m_aSectionManager.CurrentSectionIsVertical())
2292 Put(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER,text::RelOrientation::CHAR));
2293 else
2294 Put(SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME));
2297 WW8DupProperties::WW8DupProperties(SwDoc &rDoc, SwWW8FltControlStack *pStack)
2298 : m_pCtrlStck(pStack),
2299 m_aChrSet(rDoc.GetAttrPool()),
2300 m_aParSet(rDoc.GetAttrPool())
2302 //Close any open character properties and duplicate them inside the
2303 //first table cell
2304 size_t nCnt = m_pCtrlStck->size();
2305 for (size_t i=0; i < nCnt; ++i)
2307 const SwFltStackEntry& rEntry = (*m_pCtrlStck)[ i ];
2308 if (rEntry.m_bOpen)
2310 if (isCHRATR(rEntry.m_pAttr->Which()))
2312 m_aChrSet.Put( *rEntry.m_pAttr );
2315 else if (isPARATR(rEntry.m_pAttr->Which()))
2317 m_aParSet.Put( *rEntry.m_pAttr );
2323 void WW8DupProperties::Insert(const SwPosition &rPos)
2325 for (const SfxItemSet* pSet : {&m_aChrSet, &m_aParSet})
2327 if( pSet->Count() )
2329 SfxItemIter aIter( *pSet );
2330 const SfxPoolItem* pItem = aIter.GetCurItem();
2333 m_pCtrlStck->NewAttr(rPos, *pItem);
2334 } while ((pItem = aIter.NextItem()));
2339 void SwWW8ImplReader::MoveInsideFly(const SwFrameFormat *pFlyFormat)
2341 WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2343 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2345 // set Pam in FlyFrame
2346 const SwFormatContent& rContent = pFlyFormat->GetContent();
2347 OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
2348 m_pPaM->GetPoint()->Assign( rContent.GetContentIdx()->GetIndex() + 1 );
2350 aDup.Insert(*m_pPaM->GetPoint());
2353 SwTwips SwWW8ImplReader::MoveOutsideFly(SwFrameFormat *pFlyFormat,
2354 const SwPosition &rPos, bool bTableJoin)
2356 SwTwips nRetWidth = 0;
2357 if (!pFlyFormat)
2358 return nRetWidth;
2359 // Close all attributes, because otherwise attributes can appear
2360 // that extend out of Flys
2361 WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2362 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2365 #i1291
2366 If this fly frame consists entirely of one table inside a frame
2367 followed by an empty paragraph then we want to delete the empty
2368 paragraph so as to get the frame to autoshrink to the size of the
2369 table to emulate words behaviour closer.
2371 if (bTableJoin)
2373 const SwNodeIndex* pNodeIndex = pFlyFormat->GetContent().
2374 GetContentIdx();
2375 if (pNodeIndex)
2377 SwNodeIndex aIdx( *pNodeIndex, 1 ),
2378 aEnd( *pNodeIndex->GetNode().EndOfSectionNode() );
2380 if (aIdx < aEnd)
2382 if(aIdx.GetNode().IsTableNode())
2384 SwTableNode *pTable = aIdx.GetNode().GetTableNode();
2385 aIdx = *aIdx.GetNode().EndOfSectionNode();
2386 ++aIdx;
2387 if ( (aIdx < aEnd) && aIdx.GetNode().IsTextNode() )
2389 SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2390 ++aIdx;
2391 if (aIdx == aEnd && pNd && pNd->GetText().isEmpty())
2393 //An extra pre-created by writer unused paragraph
2395 //delete after import is complete rather than now
2396 //to avoid the complication of managing uncommitted
2397 //ctrlstack properties that refer to it.
2398 m_aExtraneousParas.insert(pNd);
2400 SwTable& rTable = pTable->GetTable();
2401 SwFrameFormat* pTableFormat = rTable.GetFrameFormat();
2403 if (pTableFormat)
2405 SwFormatFrameSize aSize = pTableFormat->GetFrameSize();
2406 aSize.SetHeightSizeType(SwFrameSize::Minimum);
2407 aSize.SetHeight(MINLAY);
2408 pFlyFormat->SetFormatAttr(aSize);
2409 SwFormatHoriOrient aHori = pTableFormat->GetHoriOrient();
2410 // passing the table orientation of
2411 // LEFT_AND_WIDTH to the frame seems to
2412 // work better than FULL, especially if the
2413 // table width exceeds the page width, however
2414 // I am not brave enough to set it in all
2415 // instances
2416 pTableFormat->SetFormatAttr( SwFormatHoriOrient(0, ( aHori.GetHoriOrient() == text::HoriOrientation::LEFT_AND_WIDTH ) ? ::text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::FULL ) );
2417 nRetWidth = aSize.GetWidth();
2426 *m_pPaM->GetPoint() = rPos;
2427 aDup.Insert(*m_pPaM->GetPoint());
2428 return nRetWidth;
2431 std::unique_ptr<WW8FlyPara> SwWW8ImplReader::ConstructApo(const ApoTestResults &rApo,
2432 const WW8_TablePos *pTabPos)
2434 OSL_ENSURE(rApo.HasFrame() || pTabPos,
2435 "If no frame found, *MUST* be in a table");
2437 std::unique_ptr<WW8FlyPara> pRet(new WW8FlyPara(m_bVer67, rApo.mpStyleApo));
2439 // find APO parameter and test for bGrafApo
2440 if (rApo.HasFrame())
2441 pRet->ReadFull(rApo.m_nSprm29, this);
2443 pRet->ApplyTabPos(pTabPos);
2445 if (pRet->IsEmpty())
2447 pRet.reset();
2449 return pRet;
2452 bool SwWW8ImplReader::IsDropCap() const
2454 // Find the DCS (Drop Cap Specifier) for the paragraph
2455 // if does not exist or if the first three bits are 0
2456 // then there is no dropcap on the paragraph
2457 WW8PLCFx_Cp_FKP *pPap = m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr;
2458 if (pPap)
2460 SprmResult aDCS;
2461 if (m_bVer67)
2462 aDCS = pPap->HasSprm(NS_sprm::v6::sprmPDcs);
2463 else
2464 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PDcs::val);
2465 if (aDCS.pSprm && aDCS.nRemainingData >= 2)
2468 fdct short :3 0007 drop cap type
2469 0 no drop cap
2470 1 normal drop cap
2471 2 drop cap in margin
2473 short nDCS = SVBT16ToUInt16(aDCS.pSprm);
2474 if (nDCS & 7)
2475 return true;
2478 return false;
2481 bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *pTabPos)
2483 m_xWFlyPara = ConstructApo(rApo, pTabPos);
2484 if (!m_xWFlyPara)
2485 return false;
2487 // <WW8SwFlyPara> constructor has changed - new 4th parameter
2488 // containing WW8 page top margin.
2489 m_xSFlyPara.reset(new WW8SwFlyPara( *m_pPaM, *this, *m_xWFlyPara,
2490 m_aSectionManager.GetWWPageTopMargin(),
2491 m_aSectionManager.GetTextAreaWidth(),
2492 m_nIniFlyDx, m_nIniFlyDy));
2494 // If this paragraph is a Dropcap set the flag and we will deal with it later
2495 if (IsDropCap())
2497 m_bDropCap = true;
2498 m_xCurrentItemSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), svl::Items<RES_CHRATR_BEGIN, RES_PARATR_END - 1>));
2499 return false;
2502 if (!m_xWFlyPara->bGrafApo)
2505 // Within the GrafApo text attributes have to be ignored, because
2506 // they would apply to the following lines. The frame is only inserted
2507 // if it is not merely positioning a single image. If it is an image
2508 // frame, pWFlyPara and pSFlyPara are retained and the resulting
2509 // attributes applied to the image when inserting the image.
2511 WW8FlySet aFlySet(*this, m_xWFlyPara.get(), m_xSFlyPara.get(), false);
2513 // ofz#34749 we shouldn't anchor anything into an 'extra' paragraph scheduled for
2514 // removal at end of import, but check if that scenario is happening
2515 m_aExtraneousParas.remove_if_present(m_pPaM->GetPointNode().GetTextNode());
2517 if (pTabPos)
2519 if (m_xFormatOfJustInsertedApo)
2521 // We just inserted a floating table and we'll insert a next one.
2522 SwFrameFormat* pFormat = m_xFormatOfJustInsertedApo->GetFormat();
2523 if (pFormat)
2525 const SwNode* pAnchorNode = pFormat->GetAnchor().GetAnchorNode();
2526 SwPosition* pPoint = m_pPaM->GetPoint();
2527 if (pAnchorNode && *pAnchorNode == pPoint->GetNode())
2529 // The two fly frames would have the same anchor position, leading to
2530 // potentially overlapping text, prevent that.
2531 AppendTextNode(*pPoint);
2536 // Map a positioned table to a split fly.
2537 aFlySet.Put(SwFormatFlySplit(true));
2539 if (pTabPos->nTFNoAllowOverlap)
2541 // text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE is not the default and is set in
2542 // the WW8FlySet ctor already, keep that unchanged.
2543 SwFormatWrapInfluenceOnObjPos aInfluence(aFlySet.Get(RES_WRAP_INFLUENCE_ON_OBJPOS));
2544 aInfluence.SetAllowOverlap(false);
2545 aFlySet.Put(aInfluence);
2549 m_xSFlyPara->SetFlyFormat(m_rDoc.MakeFlySection(WW8SwFlyPara::eAnchor,
2550 m_pPaM->GetPoint(), &aFlySet));
2551 OSL_ENSURE(m_xSFlyPara->GetFlyFormat()->GetAnchor().GetAnchorId() ==
2552 WW8SwFlyPara::eAnchor, "Not the anchor type requested!");
2554 if (SwFlyFrameFormat* pFlyFormat = m_xSFlyPara->GetFlyFormat())
2556 if (!m_pDrawModel)
2557 GraphicCtor();
2559 SdrObject* pOurNewObject = CreateContactObject(pFlyFormat);
2560 m_xWWZOrder->InsertTextLayerObject(pOurNewObject);
2563 if (RndStdIds::FLY_AS_CHAR != WW8SwFlyPara::eAnchor && m_xSFlyPara->GetFlyFormat())
2565 m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), m_xSFlyPara->GetFlyFormat());
2568 // remember Pos in body text
2569 m_xSFlyPara->xMainTextPos = m_rDoc.CreateUnoCursor(*m_pPaM->GetPoint());
2571 //remove fltanchors, otherwise they will be closed inside the
2572 //frame, which makes no sense, restore them after the frame is
2573 //closed
2574 m_xSFlyPara->xOldAnchorStck = std::move(m_xAnchorStck);
2575 m_xAnchorStck.reset(new SwWW8FltAnchorStack(m_rDoc, m_nFieldFlags));
2577 if (SwFlyFrameFormat* pFlyFormat = m_xSFlyPara->GetFlyFormat())
2578 MoveInsideFly(pFlyFormat);
2580 // 1) ReadText() is not called recursively because the length of
2581 // the Apo is unknown at that time, and ReadText() needs it.
2582 // 2) the CtrlStck is not re-created.
2583 // the Char attributes continue (trouble with Sw-attributes)
2584 // Para attributes must be reset at the end of every paragraph,
2585 // i.e. at the end of a paragraph there must not be para attributes
2586 // on the stack
2588 return true;
2591 void wwSectionManager::JoinNode(const SwPosition &rPos, const SwNode &rNode)
2593 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.GetNode()))
2594 maSegments.back().maStart.Assign(rNode);
2597 bool SwWW8ImplReader::JoinNode(SwPaM &rPam, bool bStealAttr)
2599 bool bRet = false;
2600 rPam.GetPoint()->SetContent(0); // go to start of paragraph
2602 SwNodeIndex aPref(rPam.GetPoint()->GetNode(), -1);
2604 if (SwTextNode* pNode = aPref.GetNode().GetTextNode())
2606 m_aSectionManager.JoinNode(*rPam.GetPoint(), aPref.GetNode());
2607 rPam.GetPoint()->Assign(*pNode, pNode->GetText().getLength());
2608 if (bStealAttr)
2609 m_xCtrlStck->StealAttr(rPam.GetPoint()->GetNode());
2611 if (m_oLastAnchorPos || m_xPreviousNode || (m_xSFlyPara && m_xSFlyPara->xMainTextPos))
2613 SwNodeIndex aToBeJoined(aPref, 1);
2615 if (m_oLastAnchorPos)
2617 //If the last anchor pos is here, then clear the anchor pos.
2618 //This "last anchor pos" is only used for fixing up the
2619 //positions of things anchored to page breaks and here
2620 //we are removing the last paragraph of a frame, so there
2621 //cannot be a page break at this point so we can
2622 //safely reset m_pLastAnchorPos to avoid any dangling
2623 //SwContentIndex's pointing into the deleted paragraph
2624 SwNodeIndex aLastAnchorPos(m_oLastAnchorPos->GetNode());
2625 if (aLastAnchorPos == aToBeJoined)
2626 m_oLastAnchorPos.reset();
2629 if (m_xPreviousNode)
2631 //If the drop character start pos is here, then clear it.
2632 SwNodeIndex aDropCharPos(*m_xPreviousNode->GetTextNode());
2633 if (aDropCharPos == aToBeJoined)
2634 m_xPreviousNode.reset();
2637 if (m_xSFlyPara && m_xSFlyPara->xMainTextPos)
2639 // If an open apo pos is here, then clear it before
2640 // JoinNext destroys it
2641 SwNodeIndex aOpenApoPos(m_xSFlyPara->xMainTextPos->GetPoint()->GetNode());
2642 if (aOpenApoPos == aToBeJoined)
2643 m_xSFlyPara->xMainTextPos.reset();
2647 pNode->JoinNext();
2649 bRet = true;
2651 return bRet;
2654 //In auto-width word frames negative after-indent values are ignored
2655 void SwWW8ImplReader::StripNegativeAfterIndent(SwFrameFormat const *pFlyFormat)
2657 const SwNodeIndex* pSttNd = pFlyFormat->GetContent().GetContentIdx();
2658 if (!pSttNd)
2659 return;
2661 SwNodeIndex aIdx(*pSttNd, 1);
2662 SwNodeIndex aEnd(*pSttNd->GetNode().EndOfSectionNode());
2663 while (aIdx < aEnd)
2665 SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2666 if (pNd)
2668 const SvxRightMarginItem & rRightMargin(pNd->GetAttr(RES_MARGIN_RIGHT));
2669 if (rRightMargin.GetRight() < 0)
2671 SvxRightMarginItem rightMargin(rRightMargin);
2672 rightMargin.SetRight(0);
2673 pNd->SetAttr(rightMargin);
2676 ++aIdx;
2680 void SwWW8ImplReader::StopApo()
2682 OSL_ENSURE(m_xWFlyPara, "no pWFlyPara to close");
2683 if (!m_xWFlyPara)
2684 return;
2685 if (m_xWFlyPara->bGrafApo)
2687 // image frame that has not been inserted: delete empty paragraph + attr
2688 JoinNode(*m_pPaM, true);
2691 else
2693 if (!m_xSFlyPara->xMainTextPos)
2695 OSL_ENSURE(m_xSFlyPara->xMainTextPos, "StopApo: xMainTextPos is nullptr");
2696 return;
2700 What we are doing with this temporary nodeindex is as follows: The
2701 stack of attributes normally only places them into the document when
2702 the current insertion point has passed them by. Otherwise the end
2703 point of the attribute gets pushed along with the insertion point. The
2704 insertion point is moved and the properties committed during
2705 MoveOutsideFly. We also may want to remove the final paragraph in the
2706 frame, but we need to wait until the properties for that frame text
2707 have been committed otherwise they will be lost. So we first get a
2708 handle to the last the filter inserted. After the attributes are
2709 committed, if that paragraph exists we join it with the para after it
2710 that comes with the frame by default so that as normal we don't end up
2711 with one more paragraph than we wanted.
2713 SwNodeIndex aPref(m_pPaM->GetPoint()->GetNode(), -1);
2715 SwTwips nNewWidth =
2716 MoveOutsideFly(m_xSFlyPara->GetFlyFormat(), *m_xSFlyPara->xMainTextPos->GetPoint());
2717 if (nNewWidth)
2718 m_xSFlyPara->BoxUpWidth(nNewWidth);
2720 Color aBg(ColorTransparency, 0xFE, 0xFF, 0xFF, 0xFF); //Transparent by default
2722 SwTextNode* pNd = aPref.GetNode().GetTextNode();
2723 SwTextNode* pJoinNext = nullptr;
2724 if (pNd && m_xSFlyPara->GetFlyFormat())
2727 #i582#
2728 Take the last paragraph background colour and fill the frame with
2729 it. Otherwise, make it transparent, this appears to be how MSWord
2730 works
2732 const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_BACKGROUND);
2733 const SvxBrushItem &rBrush = static_cast<const SvxBrushItem&>(rItm);
2734 if (rBrush.GetColor() != COL_AUTO)
2735 aBg = rBrush.GetColor();
2737 if (m_oLastAnchorPos)
2739 //If the last anchor pos is here, then clear the anchor pos.
2740 //This "last anchor pos" is only used for fixing up the
2741 //positions of things anchored to page breaks and here
2742 //we are removing the last paragraph of a frame, so there
2743 //cannot be a page break at this point so we can
2744 //safely reset m_pLastAnchorPos to avoid any dangling
2745 //SwContentIndex's pointing into the deleted paragraph
2746 SwNodeIndex aLastAnchorPos(m_oLastAnchorPos->GetNode());
2747 SwNodeIndex aToBeJoined(aPref, 1);
2748 if (aLastAnchorPos == aToBeJoined)
2749 m_oLastAnchorPos.reset();
2752 //Get rid of extra empty paragraph
2753 pJoinNext = pNd;
2756 if (SwFlyFrameFormat* pFlyFormat = m_xSFlyPara->GetFlyFormat())
2757 pFlyFormat->SetFormatAttr(SvxBrushItem(aBg, RES_BACKGROUND));
2759 DeleteAnchorStack();
2760 if (pJoinNext)
2761 pJoinNext->JoinNext();
2763 m_xAnchorStck = std::move(m_xSFlyPara->xOldAnchorStck);
2765 // When inserting a graphic into the fly frame using the auto
2766 // function, the extension of the SW-fly has to be set
2767 // manually as the SW fly has no auto function to adjust the
2768 // frame´s size.
2769 if (m_xSFlyPara->nNewNetWidth > MINFLY && m_xSFlyPara->GetFlyFormat()) // BoxUpWidth ?
2771 tools::Long nW = m_xSFlyPara->nNewNetWidth;
2772 nW += m_xSFlyPara->nWidth - m_xSFlyPara->nNetWidth; // border for it
2773 m_xSFlyPara->GetFlyFormat()->SetFormatAttr(
2774 SwFormatFrameSize(m_xSFlyPara->eHeightFix, nW, m_xSFlyPara->nHeight));
2777 Word set *no* width meaning it's an automatic width. The
2778 SwFlyPara reader will have already set a fallback width of the
2779 printable regions width, so we should reuse it. Despite the related
2780 problems with layout addressed with a hack in WW8FlyPara's constructor
2781 #i27204# Added AutoWidth setting. Left the old CalculateFlySize in place
2782 so that if the user unselects autowidth, the width doesn't max out
2784 else if (!m_xWFlyPara->nSp28 && m_xSFlyPara->GetFlyFormat())
2786 using namespace sw::util;
2787 SfxItemSet aFlySet( m_xSFlyPara->GetFlyFormat()->GetAttrSet() );
2789 SwFormatFrameSize aSize(aFlySet.Get(RES_FRM_SIZE));
2791 aFlySet.ClearItem(RES_FRM_SIZE);
2793 if (!m_bFuzzing)
2795 CalculateFlySize(aFlySet, m_xSFlyPara->xMainTextPos->GetPoint()->GetNode(),
2796 m_xSFlyPara->nWidth);
2799 nNewWidth = aFlySet.Get(RES_FRM_SIZE).GetWidth();
2801 aSize.SetWidth(nNewWidth);
2802 aSize.SetWidthSizeType(SwFrameSize::Variable);
2804 m_xSFlyPara->GetFlyFormat()->SetFormatAttr(aSize);
2807 m_xSFlyPara->xMainTextPos.reset();
2808 // To create the SwFrames when inserting into an existing document, fltshell.cxx
2809 // will call pFlyFrame->MakeFrames() when setting the FltAnchor attribute
2813 //#i8062#
2814 if (m_xSFlyPara && m_xSFlyPara->GetFlyFormat())
2815 m_xFormatOfJustInsertedApo.reset(new FrameDeleteWatch(m_xSFlyPara->GetFlyFormat()));
2817 m_xSFlyPara.reset();
2818 m_xWFlyPara.reset();
2821 // TestSameApo() returns if it's the same Apo or a different one
2822 bool SwWW8ImplReader::TestSameApo(const ApoTestResults &rApo,
2823 const WW8_TablePos *pTabPos)
2825 if (!m_xWFlyPara)
2827 OSL_ENSURE(m_xWFlyPara, " Where is my pWFlyPara ? ");
2828 return true;
2831 // We need to a full comparison (excepting borders) to identify all
2832 // combinations style/hard correctly. For this reason we create a
2833 // temporary WW8FlyPara (depending on if style or not), apply the
2834 // hard attributes and then compare.
2836 // For comparison
2837 WW8FlyPara aF(m_bVer67, rApo.mpStyleApo);
2838 // WWPara for current para
2839 if (rApo.HasFrame())
2840 aF.Read(rApo.m_nSprm29, m_xPlcxMan->GetPapPLCF());
2841 aF.ApplyTabPos(pTabPos);
2843 return aF == *m_xWFlyPara;
2846 void SwWW8ImplReader::NewAttr( const SfxPoolItem& rAttr,
2847 const bool bFirstLineOfStSet,
2848 const bool bLeftIndentSet )
2850 if( m_bNoAttrImport ) // for ignoring styles during doc inserts
2851 return;
2853 if (m_pCurrentColl)
2855 OSL_ENSURE(rAttr.Which() != RES_FLTR_REDLINE, "redline in style!");
2856 m_pCurrentColl->SetFormatAttr(rAttr);
2858 else if (m_xCurrentItemSet)
2860 m_xCurrentItemSet->Put(rAttr);
2862 else if (rAttr.Which() == RES_FLTR_REDLINE)
2864 m_xRedlineStack->open(*m_pPaM->GetPoint(), rAttr);
2866 else
2868 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), rAttr);
2869 // #i103711#
2870 if ( bFirstLineOfStSet )
2872 const SwNode* pNd = &(m_pPaM->GetPoint()->GetNode());
2873 m_aTextNodesHavingFirstLineOfstSet.insert( pNd );
2875 // #i105414#
2876 if ( bLeftIndentSet )
2878 const SwNode* pNd = &(m_pPaM->GetPoint()->GetNode());
2879 m_aTextNodesHavingLeftIndentSet.insert( pNd );
2883 if (m_pPostProcessAttrsInfo && m_pPostProcessAttrsInfo->mbCopy)
2884 m_pPostProcessAttrsInfo->mItemSet.Put(rAttr);
2887 // fetches attribute from FormatColl / Stack / Doc
2888 const SfxPoolItem* SwWW8ImplReader::GetFormatAttr( sal_uInt16 nWhich )
2890 const SfxPoolItem* pRet = nullptr;
2891 if (m_pCurrentColl)
2892 pRet = &(m_pCurrentColl->GetFormatAttr(nWhich));
2893 else if (m_xCurrentItemSet)
2895 pRet = m_xCurrentItemSet->GetItem(nWhich);
2896 if (!pRet)
2897 pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2898 if (!pRet)
2899 pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2901 else if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2903 pRet = m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), nWhich);
2904 if (!pRet)
2906 if (m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_pFormat &&
2907 m_vColl[m_nCurrentColl].m_bColl)
2909 pRet = &(m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(nWhich));
2912 if (!pRet)
2913 pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2914 if (!pRet)
2915 pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2917 else
2918 pRet = m_xCtrlStck->GetFormatAttr(*m_pPaM->GetPoint(), nWhich);
2919 return pRet;
2922 // The methods get as parameters the token id and the length of the following
2923 // parameters according to the table in WWScan.cxx.
2924 void SwWW8ImplReader::Read_Special(sal_uInt16, const sal_uInt8* pData, short nLen)
2926 if (nLen < 1)
2928 m_bSpec = false;
2929 return;
2931 m_bSpec = ( *pData != 0 );
2934 // Read_Obj is used for fObj and for fOle2 !
2935 void SwWW8ImplReader::Read_Obj(sal_uInt16 , const sal_uInt8* pData, short nLen)
2937 if (nLen < 1)
2938 m_bObj = false;
2939 else
2941 m_bObj = 0 != *pData;
2943 if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2945 if (!m_aFieldStack.empty() && m_aFieldStack.back().mnFieldId == 56)
2947 // For LINK fields, store the nObjLocFc value in the field entry
2948 m_aFieldStack.back().mnObjLocFc = m_nPicLocFc;
2950 else
2952 m_nObjLocFc = m_nPicLocFc;
2958 void SwWW8ImplReader::Read_PicLoc(sal_uInt16 , const sal_uInt8* pData, short nLen )
2960 if (nLen < 4)
2962 m_nPicLocFc = 0;
2963 m_bSpec = false; // Is this always correct?
2965 else
2967 m_nPicLocFc = SVBT32ToUInt32( pData );
2968 m_bSpec = true;
2970 if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2971 m_nObjLocFc = m_nPicLocFc;
2975 void SwWW8ImplReader::Read_POutLvl(sal_uInt16, const sal_uInt8* pData, short nLen )
2977 if (nLen < 0)
2979 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_OUTLINELEVEL);
2980 return;
2983 if (m_pCurrentColl != nullptr)
2985 SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
2986 if (pSI && pSI->m_bColl && pSI->m_pFormat)
2988 pSI->mnWW8OutlineLevel =
2989 static_cast< sal_uInt8 >( ( (pData && nLen >= 1) ? *pData : 0 ) );
2990 auto nLevel = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(pSI->mnWW8OutlineLevel);
2991 if (nLevel == 0)
2993 SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pSI->m_pFormat);
2994 pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
2996 NewAttr(SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nLevel));
2999 else if (m_pPaM != nullptr)
3001 const sal_uInt8 nOutlineLevel
3002 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
3003 static_cast<sal_uInt8>(((pData && nLen >= 1) ? *pData : 0)));
3004 NewAttr(SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
3008 void SwWW8ImplReader::Read_Symbol(sal_uInt16, const sal_uInt8* pData, short nLen )
3010 if( m_bIgnoreText )
3011 return;
3013 if (nLen < (m_bVer67 ? 3 : 4))
3015 //otherwise disable after we print the char
3016 if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
3017 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
3018 m_bSymbol = false;
3020 else
3022 // Make new Font-Attribute
3023 // (will be closed in SwWW8ImplReader::ReadChars() )
3025 //Will not be added to the charencoding stack, for styles the real
3026 //font setting will be put in as the styles charset, and for plain
3027 //text encoding for symbols is moot. Drawing boxes will check bSymbol
3028 //themselves so they don't need to add it to the stack either.
3029 if (SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_FONT))
3031 SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CJK_FONT);
3032 SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CTL_FONT);
3033 if( m_bVer67 )
3035 //convert single byte from MS1252 to Unicode
3036 m_cSymbol = OUString(
3037 reinterpret_cast<const char*>(pData+2), 1,
3038 RTL_TEXTENCODING_MS_1252).toChar();
3040 else
3042 //already is Unicode
3043 m_cSymbol = SVBT16ToUInt16( pData+2 );
3045 m_bSymbol = true;
3050 SwWW8StyInf *SwWW8ImplReader::GetStyle(sal_uInt16 nColl) const
3052 return const_cast<SwWW8StyInf *>(nColl < m_vColl.size() ? &m_vColl[nColl] : nullptr);
3055 // Read_BoldUsw for italic, bold, small caps, majuscule, struck out,
3056 // contour and shadow
3057 void SwWW8ImplReader::Read_BoldUsw( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3059 const int nContiguousWestern = 8;
3060 const int nWestern = nContiguousWestern + 1;
3061 const int nEastern = 2;
3062 const int nCTL = 2;
3063 const int nIds = nWestern + nEastern + nCTL;
3064 static const sal_uInt16 nEndIds[ nIds ] =
3066 RES_CHRATR_WEIGHT, RES_CHRATR_POSTURE,
3067 RES_CHRATR_CROSSEDOUT, RES_CHRATR_CONTOUR,
3068 RES_CHRATR_SHADOWED, RES_CHRATR_CASEMAP,
3069 RES_CHRATR_CASEMAP, RES_CHRATR_HIDDEN,
3071 RES_CHRATR_CROSSEDOUT,
3073 RES_CHRATR_CJK_WEIGHT, RES_CHRATR_CJK_POSTURE,
3075 RES_CHRATR_CTL_WEIGHT, RES_CHRATR_CTL_POSTURE
3078 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3080 sal_uInt8 nI;
3081 // the attribute number for "double strike-through" breaks rank
3082 if (NS_sprm::CFDStrike::val == nId)
3083 nI = nContiguousWestern; // The out of sequence western id
3084 else
3086 // The contiguous western ids
3087 if (eVersion <= ww::eWW2)
3088 nI = static_cast< sal_uInt8 >(nId - 60);
3089 else if (eVersion < ww::eWW8)
3090 nI = static_cast< sal_uInt8 >(nId - NS_sprm::v6::sprmCFBold);
3091 else
3092 nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBold::val);
3095 sal_uInt16 nMask = 1 << nI;
3097 if (nLen < 1)
3099 if (nI < 2)
3101 if (eVersion <= ww::eWW6)
3103 // reset the CTL Weight and Posture, because they are the same as their
3104 // western equivalents in ww6
3105 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nEastern + nI ] );
3107 // reset the CJK Weight and Posture, because they are the same as their
3108 // western equivalents in word
3109 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nI ] );
3111 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nI ] );
3112 m_xCtrlStck->SetToggleAttr(nI, false);
3113 return;
3115 // value: 0 = off, 1 = on, 128 = like style, 129 contrary to style
3116 bool bOn = *pData & 1;
3117 SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
3118 if (m_xPlcxMan && eVersion > ww::eWW2)
3120 SprmResult aCharIstd =
3121 m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3122 if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3123 pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3126 if( m_pCurrentColl ) // StyleDef -> remember flags
3128 if (pSI)
3130 // The style based on has Bit 7 set ?
3131 if (
3132 pSI->m_nBase < m_vColl.size() && (*pData & 0x80) &&
3133 (m_vColl[pSI->m_nBase].m_n81Flags & nMask)
3136 bOn = !bOn; // invert
3139 if (bOn)
3140 pSI->m_n81Flags |= nMask; // set flag
3141 else
3142 pSI->m_n81Flags &= ~nMask; // delete flag
3145 else
3148 // in text -> look at flags
3149 if( *pData & 0x80 ) // bit 7 set?
3151 if (pSI && pSI->m_n81Flags & nMask) // and in StyleDef at ?
3152 bOn = !bOn; // then invert
3153 // remember on stack that this is a toggle-attribute
3154 m_xCtrlStck->SetToggleAttr(nI, true);
3158 SetToggleAttr( nI, bOn );
3161 void SwWW8ImplReader::Read_Bidi(sal_uInt16, const sal_uInt8* pData, short nLen)
3163 if (nLen < 1) //Property end
3165 m_bBidi = false;
3166 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),RES_CHRATR_BIDIRTL);
3168 else //Property start
3170 m_bBidi = true;
3171 sal_uInt8 nBidi = *pData;
3172 NewAttr( SfxInt16Item( RES_CHRATR_BIDIRTL, (nBidi!=0)? 1 : 0 ) );
3177 tdf#91916, #i8726, #i42685# there is an ambiguity
3178 around certain properties as to what they mean,
3179 which appears to be a problem with different versions
3180 of the file format where properties conflict, i.e.
3182 ooo40606-2.doc, magic is a699
3183 : 0x6f 0x4 0x0 0x71 0x4 0x0
3184 ooo40635-1.doc, magic is a699
3185 : 0x6f 0x4 0x0 0x71 0x4 0x0
3186 ooo31093/SIMPCHIN.doc, magic is a699
3187 : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3188 : 0x6f 0x5 0x0 0x70 0x5 0x0
3189 ooo31093/TRADCHIN.doc, magic is a699
3190 : 0x6f 0x1 0x0 0x70 0x0 0x0 0x71 0x1 0x0
3191 ooo31093/JAPANESE.doc, magic is a697
3192 : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3193 ooo31093/KOREAN.doc, magic is a698
3194 : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3195 ooo31093-1.doc, magic is a698
3196 : 0x6f 0x5 0x0 0x70 0x5 0x0
3197 ooo31093-1.doc, magic is a698
3198 : 0x6f 0x5 0x0 0x70 0x5 0x0
3200 meanwhile...
3202 ooo27954-1.doc, magic is a5dc
3203 : 0x6f 0x1 0x81 0x71 0x2 0x4 0x0 0x74 0x2 0x20 0x0
3205 ooo33251-1.doc, magic is a5dc
3206 : 0x6f 0x1 0x81 0x71 0x2 0x3 0x0 0x74 0x2 0x1c 0x0
3210 So we have the same sprm values, but different payloads, where
3211 the a5dc versions appear to use a len argument, followed by len
3212 bytes, while the a698<->a699 versions use a 2byte argument
3214 commit c2213db9ed70c1fd546482d22e36e4029c10aa45
3216 INTEGRATION: CWS tl28 (1.169.24); FILE MERGED
3217 2006/10/25 13:40:41 tl 1.169.24.2: RESYNC: (1.169-1.170); FILE MERGED
3218 2006/09/20 11:55:50 hbrinkm 1.169.24.1: #i42685# applied patch
3220 changed 0x6f and 0x70 from Read_BoldBiDiUsw to Read_FontCode for all versions.
3222 In the Word for Window 2 spec we have...
3223 78 //sprmCMajority
3224 80 //sprmCFBoldBi
3225 81 //sprmCFItalicBi
3226 82 //sprmCFtcBi
3227 83 //sprmClidBi
3228 84 //sprmCIcoBi
3229 85 //sprmCHpsBi
3230 as see in GetWW2SprmDispatcher, different numbers, but the sequence starts with
3231 the same sprmCMajority as appears before 0x6f in word 6/95
3233 I think the easiest explanation is that the CJK Word for Window 95, or whatever
3234 the product was went rogue, and did their own things with at least first three
3235 slots after sprmCMajority to do a different thing. I have no reason to think Tono
3236 was wrong with what they do in the a698<->a699 versions, but with magic
3237 a5dc they probably did mean sprmCFBoldBi, sprmCFItalicBi cause they have that 0x81
3238 pattern which has significance for those types of properties.
3240 void SwWW8ImplReader::Read_AmbiguousSPRM(sal_uInt16 nId, const sal_uInt8* pData,
3241 short nLen)
3243 if (m_xWwFib->m_wIdent >= 0xa697 && m_xWwFib->m_wIdent <= 0xa699)
3245 Read_FontCode(nId, pData, nLen);
3247 else
3249 Read_BoldBiDiUsw(nId, pData, nLen);
3253 // Read_BoldUsw for BiDi Italic, Bold
3254 void SwWW8ImplReader::Read_BoldBiDiUsw(sal_uInt16 nId, const sal_uInt8* pData,
3255 short nLen)
3257 static const sal_uInt16 nEndIds[2] =
3259 RES_CHRATR_CTL_WEIGHT, RES_CHRATR_CTL_POSTURE,
3262 sal_uInt8 nI;
3263 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3264 if (eVersion <= ww::eWW2)
3265 nI = static_cast< sal_uInt8 >(nId - 80);
3266 else if (eVersion < ww::eWW8)
3267 nI = static_cast< sal_uInt8 >(nId - 111);
3268 else
3269 nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBoldBi::val);
3271 OSL_ENSURE(nI <= 1, "not happening");
3272 if (nI > 1)
3273 return;
3275 sal_uInt16 nMask = 1 << nI;
3277 if (nLen < 1)
3279 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),nEndIds[nI]);
3280 m_xCtrlStck->SetToggleBiDiAttr(nI, false);
3281 return;
3283 bool bOn = *pData & 1;
3284 SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
3285 if (m_xPlcxMan)
3287 SprmResult aCharIstd =
3288 m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3289 if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3290 pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3293 if (m_pCurrentColl && eVersion > ww::eWW2) // StyleDef -> remember flags
3295 if (pSI)
3297 if( pSI->m_nBase < m_vColl.size() // Style Based on
3298 && ( *pData & 0x80 ) // bit 7 set?
3299 && ( m_vColl[pSI->m_nBase].m_n81BiDiFlags & nMask ) ) // base mask?
3300 bOn = !bOn; // invert
3302 if( bOn )
3303 pSI->m_n81BiDiFlags |= nMask; // set flag
3304 else
3305 pSI->m_n81BiDiFlags &= ~nMask; // delete flag
3308 else
3311 // in text -> look at flags
3312 if (*pData & 0x80) // Bit 7 set?
3314 if (pSI && pSI->m_n81BiDiFlags & nMask) // and in StyleDef at ?
3315 bOn = !bOn; // then invert
3316 // remember on stack that this is a toggle-attribute
3317 m_xCtrlStck->SetToggleBiDiAttr(nI, true);
3321 SetToggleBiDiAttr(nI, bOn);
3324 void SwWW8ImplReader::SetToggleBiDiAttr(sal_uInt8 nAttrId, bool bOn)
3326 switch (nAttrId)
3328 case 0:
3330 SvxWeightItem aAttr( bOn ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT );
3331 aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3332 NewAttr( aAttr );
3334 break;
3335 case 1:
3337 SvxPostureItem aAttr( bOn ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE );
3338 aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3339 NewAttr( aAttr );
3341 break;
3342 default:
3343 OSL_ENSURE(false, "Unhandled unknown bidi toggle attribute");
3344 break;
3349 void SwWW8ImplReader::SetToggleAttr(sal_uInt8 nAttrId, bool bOn)
3351 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3353 switch (nAttrId)
3355 case 0:
3357 SvxWeightItem aAttr( bOn ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT );
3358 NewAttr( aAttr );
3359 aAttr.SetWhich( RES_CHRATR_CJK_WEIGHT );
3360 NewAttr( aAttr );
3361 if (eVersion <= ww::eWW6)
3363 aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3364 NewAttr( aAttr );
3367 break;
3368 case 1:
3370 SvxPostureItem aAttr( bOn ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE );
3371 NewAttr( aAttr );
3372 aAttr.SetWhich( RES_CHRATR_CJK_POSTURE );
3373 NewAttr( aAttr );
3374 if (eVersion <= ww::eWW6)
3376 aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3377 NewAttr( aAttr );
3380 break;
3381 case 2:
3382 NewAttr(SvxCrossedOutItem(bOn ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT));
3383 break;
3384 case 3:
3385 NewAttr( SvxContourItem( bOn, RES_CHRATR_CONTOUR ) );
3386 break;
3387 case 4:
3388 NewAttr( SvxShadowedItem( bOn, RES_CHRATR_SHADOWED ) );
3389 break;
3390 case 5:
3391 NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::SmallCaps
3392 : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3393 break;
3394 case 6:
3395 NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::Uppercase
3396 : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3397 break;
3398 case 7:
3399 if (m_pPaM->GetPoint()->GetContentIndex() == 0 && m_xFormatOfJustInsertedApo)
3401 // We just inserted a frame and we're at the next paragraph start.
3402 SwFrameFormat* pFormat = m_xFormatOfJustInsertedApo->GetFormat();
3403 if (pFormat)
3405 SwNode* pAnchorNode = pFormat->GetAnchor().GetAnchorNode();
3406 if (pAnchorNode && *pAnchorNode == m_pPaM->GetPoint()->GetNode())
3408 // The anchor paragraph would be hidden, leading to hiding the frame as
3409 // well, prevent that.
3410 break;
3415 NewAttr(SvxCharHiddenItem(bOn, RES_CHRATR_HIDDEN));
3416 break;
3417 case 8:
3418 NewAttr( SvxCrossedOutItem( bOn ? STRIKEOUT_DOUBLE
3419 : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ) );
3420 break;
3421 default:
3422 OSL_ENSURE(false, "Unhandled unknown toggle attribute");
3423 break;
3427 void SwWW8ImplReader::ChkToggleAttr_( sal_uInt16 nOldStyle81Mask,
3428 sal_uInt16 nNewStyle81Mask )
3430 sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleAttrFlags();
3431 for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3433 if (
3434 (i & nToggleAttrFlags) &&
3435 ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3438 SetToggleAttr(n, (i & nOldStyle81Mask));
3443 void SwWW8ImplReader::ChkToggleBiDiAttr_( sal_uInt16 nOldStyle81Mask,
3444 sal_uInt16 nNewStyle81Mask )
3446 sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleBiDiAttrFlags();
3447 for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3449 if (
3450 (i & nToggleAttrFlags) &&
3451 ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3454 SetToggleBiDiAttr(n, (i & nOldStyle81Mask));
3459 void SwWW8ImplReader::Read_SubSuper( sal_uInt16, const sal_uInt8* pData, short nLen )
3461 if (nLen < 1)
3463 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ESCAPEMENT );
3464 return;
3467 short nEs;
3468 sal_uInt8 nProp;
3469 switch( *pData )
3471 case 1:
3472 nEs = DFLT_ESC_AUTO_SUPER;
3473 nProp = DFLT_ESC_PROP;
3474 break;
3475 case 2:
3476 nEs = DFLT_ESC_AUTO_SUB;
3477 nProp = DFLT_ESC_PROP;
3478 break;
3479 default:
3480 nEs = 0;
3481 nProp = 100;
3482 break;
3484 NewAttr( SvxEscapementItem( nEs, nProp, RES_CHRATR_ESCAPEMENT ) );
3487 SwFrameFormat *SwWW8ImplReader::ContainsSingleInlineGraphic(const SwPaM &rRegion)
3490 For inline graphics and objects word has a hacked in feature to use
3491 subscripting to force the graphic into a centered position on the line, so
3492 we must check when applying sub/super to see if it the subscript range
3493 contains only a single graphic, and if that graphic is anchored as
3494 RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3496 SwFrameFormat *pRet=nullptr;
3497 SwNodeIndex aBegin(rRegion.Start()->GetNode());
3498 const sal_Int32 nBegin(rRegion.Start()->GetContentIndex());
3499 SwNodeIndex aEnd(rRegion.End()->GetNode());
3500 const sal_Int32 nEnd(rRegion.End()->GetContentIndex());
3501 const SwTextNode* pTNd;
3502 const SwTextAttr* pTFlyAttr;
3503 if (
3504 aBegin == aEnd && nBegin == nEnd - 1 &&
3505 nullptr != (pTNd = aBegin.GetNode().GetTextNode()) &&
3506 nullptr != (pTFlyAttr = pTNd->GetTextAttrForCharAt(nBegin, RES_TXTATR_FLYCNT))
3509 const SwFormatFlyCnt& rFly = pTFlyAttr->GetFlyCnt();
3510 SwFrameFormat *pFlyFormat = rFly.GetFrameFormat();
3511 if (pFlyFormat &&
3512 (RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()))
3514 pRet = pFlyFormat;
3517 return pRet;
3520 bool SwWW8ImplReader::ConvertSubToGraphicPlacement()
3523 For inline graphics and objects word has a hacked in feature to use
3524 subscripting to force the graphic into a centered position on the line, so
3525 we must check when applying sub/super to see if it the subscript range
3526 contains only a single graphic, and if that graphic is anchored as
3527 RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3529 bool bIsGraphicPlacementHack = false;
3530 sal_uInt16 nPos;
3531 if (m_xCtrlStck->GetFormatStackAttr(RES_CHRATR_ESCAPEMENT, &nPos))
3533 SwPaM aRegion(*m_pPaM->GetPoint());
3535 SwFltPosition aMkPos((*m_xCtrlStck)[nPos].m_aMkPos);
3536 SwFltPosition aPtPos(*m_pPaM->GetPoint());
3538 SwFrameFormat *pFlyFormat = nullptr;
3539 if (SwFltStackEntry::MakeRegion(m_rDoc, aRegion, SwFltStackEntry::RegionMode::NoCheck, aMkPos, aPtPos)
3540 && nullptr != (pFlyFormat = ContainsSingleInlineGraphic(aRegion)))
3542 m_xCtrlStck->DeleteAndDestroy(nPos);
3543 pFlyFormat->SetFormatAttr(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER, text::RelOrientation::CHAR));
3544 bIsGraphicPlacementHack = true;
3547 return bIsGraphicPlacementHack;
3550 void SwWW8ImplReader::Read_SubSuperProp( sal_uInt16, const sal_uInt8* pData, short nLen )
3552 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3554 if (nLen < (eVersion <= ww::eWW2 ? 1 : 2))
3556 if (!ConvertSubToGraphicPlacement())
3557 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ESCAPEMENT );
3558 return;
3561 // if the fontsize for these characters is specified, make sure it is updated first
3562 if ( m_xPlcxMan )
3564 const sal_uInt16 nFontsizeID = m_bVer67 ? NS_sprm::v6::sprmCHps : NS_sprm::CHps::val;
3565 const SprmResult aFontsize = m_xPlcxMan->GetChpPLCF()->HasSprm( nFontsizeID, /*bFindFirst=*/false );
3566 if ( aFontsize.pSprm && aFontsize.nRemainingData )
3567 Read_FontSize(nFontsizeID, aFontsize.pSprm, aFontsize.nRemainingData);
3570 // font position in HalfPoints
3571 short nPos = eVersion <= ww::eWW2 ? static_cast< sal_Int8 >( *pData ) : SVBT16ToInt16( pData );
3572 sal_Int32 nPos2 = nPos * ( 10 * 100 ); // HalfPoints in 100 * tw
3573 const SvxFontHeightItem* pF
3574 = static_cast<const SvxFontHeightItem*>(GetFormatAttr(RES_CHRATR_FONTSIZE));
3575 OSL_ENSURE(pF, "Expected to have the fontheight available here");
3577 // #i59022: Check ensure nHeight != 0. Div by zero otherwise.
3578 sal_Int32 nHeight = 240;
3579 if (pF != nullptr && pF->GetHeight() != 0)
3580 nHeight = pF->GetHeight();
3581 nPos2 /= nHeight; // ... now in % (rounded)
3582 if( nPos2 > MAX_ESC_POS )
3583 nPos2 = MAX_ESC_POS;
3584 if( nPos2 < -MAX_ESC_POS )
3585 nPos2 = -MAX_ESC_POS;
3586 SvxEscapementItem aEs( static_cast<short>(nPos2), 100, RES_CHRATR_ESCAPEMENT );
3587 NewAttr( aEs );
3590 void SwWW8ImplReader::Read_Underline( sal_uInt16, const sal_uInt8* pData, short nLen )
3592 FontLineStyle eUnderline = LINESTYLE_NONE;
3593 bool bWordLine = false;
3594 if (pData && nLen)
3596 // Parameter: 0 = none, 1 = single, 2 = by Word,
3597 // 3 = double, 4 = dotted, 5 = hidden
3598 // 6 = thick, 7 = dash, 8 = dot(not used)
3599 // 9 = dotdash 10 = dotdotdash 11 = wave
3600 switch( *pData )
3602 case 2: bWordLine = true;
3603 [[fallthrough]];
3604 case 1: eUnderline = LINESTYLE_SINGLE; break;
3605 case 3: eUnderline = LINESTYLE_DOUBLE; break;
3606 case 4: eUnderline = LINESTYLE_DOTTED; break;
3607 case 7: eUnderline = LINESTYLE_DASH; break;
3608 case 9: eUnderline = LINESTYLE_DASHDOT; break;
3609 case 10:eUnderline = LINESTYLE_DASHDOTDOT; break;
3610 case 6: eUnderline = LINESTYLE_BOLD; break;
3611 case 11:eUnderline = LINESTYLE_WAVE; break;
3612 case 20:eUnderline = LINESTYLE_BOLDDOTTED; break;
3613 case 23:eUnderline = LINESTYLE_BOLDDASH; break;
3614 case 39:eUnderline = LINESTYLE_LONGDASH; break;
3615 case 55:eUnderline = LINESTYLE_BOLDLONGDASH; break;
3616 case 25:eUnderline = LINESTYLE_BOLDDASHDOT; break;
3617 case 26:eUnderline = LINESTYLE_BOLDDASHDOTDOT;break;
3618 case 27:eUnderline = LINESTYLE_BOLDWAVE; break;
3619 case 43:eUnderline = LINESTYLE_DOUBLEWAVE; break;
3623 // if necessary, mix up stack and exit!
3624 if (nLen < 1)
3626 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE );
3627 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_WORDLINEMODE );
3629 else
3631 NewAttr( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ));
3632 if( bWordLine )
3633 NewAttr(SvxWordLineModeItem(true, RES_CHRATR_WORDLINEMODE));
3638 //The last three vary, measurements, rotation ? ?
3639 NoBracket 78 CA 06 - 02 00 00 02 34 52
3640 () 78 CA 06 - 02 01 00 02 34 52
3641 [] 78 CA 06 - 02 02 00 02 34 52
3642 <> 78 CA 06 - 02 03 00 02 34 52
3643 {} 78 CA 06 - 02 04 00 02 34 52
3645 void SwWW8ImplReader::Read_DoubleLine_Rotate( sal_uInt16, const sal_uInt8* pData,
3646 short nLen )
3648 if (nLen < 0) // close the tag
3650 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_TWO_LINES );
3651 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ROTATE );
3653 else if( pData && 6 == nLen )
3655 switch( *pData )
3657 case 2: // double line
3659 sal_Unicode cStt = 0, cEnd = 0;
3660 switch( SVBT16ToUInt16( pData+1 ) )
3662 case 1: cStt = '('; cEnd = ')'; break;
3663 case 2: cStt = '['; cEnd = ']'; break;
3664 case 3: cStt = '<'; cEnd = '>'; break;
3665 case 4: cStt = '{'; cEnd = '}'; break;
3667 NewAttr( SvxTwoLinesItem( true, cStt, cEnd, RES_CHRATR_TWO_LINES ));
3669 break;
3671 case 1: // rotated characters
3673 bool bFitToLine = 0 != *(pData+1);
3674 NewAttr( SvxCharRotateItem( 900_deg10, bFitToLine, RES_CHRATR_ROTATE ));
3676 break;
3681 void SwWW8ImplReader::Read_TextColor( sal_uInt16, const sal_uInt8* pData, short nLen )
3683 //Has newer colour variant, ignore this old variant
3684 if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CCv::val).pSprm)
3685 return;
3687 if (nLen < 1)
3688 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3689 else
3691 sal_uInt8 b = *pData; // parameter: 0 = Auto, 1..16 colors
3693 if( b > 16 ) // unknown -> Black
3694 b = 0;
3696 NewAttr( SvxColorItem(GetCol(b), RES_CHRATR_COLOR));
3697 if (m_pCurrentColl && m_xStyles)
3698 m_xStyles->mbTextColChanged = true;
3702 void SwWW8ImplReader::Read_TextForeColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3704 if (nLen < 4)
3705 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3706 else
3708 Color aColor = msfilter::util::BGRToRGB(SVBT32ToUInt32(pData));
3710 // At least when transparency is 0xff and the color is black, Word renders that as black.
3711 if (aColor.IsTransparent() && aColor != COL_AUTO)
3713 aColor.SetAlpha(255);
3716 NewAttr(SvxColorItem(aColor, RES_CHRATR_COLOR));
3717 if (m_pCurrentColl && m_xStyles)
3718 m_xStyles->mbTextColChanged = true;
3722 void SwWW8ImplReader::Read_UnderlineColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3724 if (nLen < 0)
3726 //because the UnderlineColor is not a standalone attribute in SW, it belongs to the underline attribute.
3727 //And, the .doc file stores attributes separately, this attribute ends here, the "underline"
3728 //attribute also terminates (if the character next owns underline, that will be a new underline attribute).
3729 //so nothing is left to be done here.
3730 return;
3732 else
3734 if ( m_pCurrentColl ) //importing style
3736 if( SfxItemState::SET == m_pCurrentColl->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3738 if (nLen >= 4)
3740 const SwAttrSet& aSet = m_pCurrentColl->GetAttrSet();
3741 std::unique_ptr<SvxUnderlineItem> pUnderline(aSet.Get(RES_CHRATR_UNDERLINE, false).Clone());
3742 pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3743 m_pCurrentColl->SetFormatAttr( *pUnderline );
3747 else if (m_xCurrentItemSet)
3749 if ( SfxItemState::SET == m_xCurrentItemSet->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3751 if (nLen >= 4)
3753 std::unique_ptr<SvxUnderlineItem> pUnderline(m_xCurrentItemSet->Get(RES_CHRATR_UNDERLINE, false).Clone());
3754 pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3755 m_xCurrentItemSet->Put( std::move(pUnderline) );
3759 else
3761 SvxUnderlineItem* pUnderlineAttr = const_cast<SvxUnderlineItem*>(static_cast<const SvxUnderlineItem*>(m_xCtrlStck->GetOpenStackAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE )));
3762 if (pUnderlineAttr && nLen >= 4)
3763 pUnderlineAttr->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32( pData ) ));
3767 bool SwWW8ImplReader::GetFontParams( sal_uInt16 nFCode, FontFamily& reFamily,
3768 OUString& rName, FontPitch& rePitch, rtl_TextEncoding& reCharSet )
3770 // the definitions that are the base for these tables are in windows.h
3771 static const FontPitch ePitchA[] =
3773 PITCH_DONTKNOW, PITCH_FIXED, PITCH_VARIABLE, PITCH_DONTKNOW
3776 static const FontFamily eFamilyA[] =
3778 FAMILY_DONTKNOW, FAMILY_ROMAN, FAMILY_SWISS, FAMILY_MODERN,
3779 FAMILY_SCRIPT, FAMILY_DECORATIVE, FAMILY_DONTKNOW, FAMILY_DONTKNOW
3782 const WW8_FFN* pF = m_xFonts->GetFont( nFCode ); // Info for it
3783 if( !pF ) // font number unknown ?
3784 return false; // then ignore
3786 rName = pF->sFontname;
3788 // pF->prg : Pitch
3789 rePitch = ePitchA[pF->aFFNBase.prg];
3791 // pF->chs: Charset
3792 if( 77 == pF->aFFNBase.chs ) // Mac font in Mac Charset or
3793 reCharSet = m_eTextCharSet; // translated to ANSI charset
3794 else
3796 // #i52786#, for word 67 we'll assume that ANSI is basically invalid,
3797 // might be true for (above) mac as well, but would need a mac example
3798 // that exercises this to be sure
3799 if (m_bVer67 && pF->aFFNBase.chs == 0)
3800 reCharSet = RTL_TEXTENCODING_DONTKNOW;
3801 else
3802 reCharSet = rtl_getTextEncodingFromWindowsCharset(pF->aFFNBase.chs);
3805 // make sure Font Family Code is set correctly
3806 // at least for the most important fonts
3807 // ( might be set wrong when Doc was not created by
3808 // Winword but by third party program like Applixware... )
3809 if (rName.startsWithIgnoreAsciiCase("Tms Rmn") ||
3810 rName.startsWithIgnoreAsciiCase("Timmons") ||
3811 rName.startsWithIgnoreAsciiCase("CG Times") ||
3812 rName.startsWithIgnoreAsciiCase("MS Serif") ||
3813 rName.startsWithIgnoreAsciiCase("Garamond") ||
3814 rName.startsWithIgnoreAsciiCase("Times Roman") ||
3815 rName.startsWithIgnoreAsciiCase("Times New Roman"))
3817 reFamily = FAMILY_ROMAN;
3819 else if (rName.startsWithIgnoreAsciiCase("Helv") ||
3820 rName.startsWithIgnoreAsciiCase("Arial") ||
3821 rName.startsWithIgnoreAsciiCase("Univers") ||
3822 rName.startsWithIgnoreAsciiCase("LinePrinter") ||
3823 rName.startsWithIgnoreAsciiCase("Lucida Sans") ||
3824 rName.startsWithIgnoreAsciiCase("Small Fonts") ||
3825 rName.startsWithIgnoreAsciiCase("MS Sans Serif"))
3827 reFamily = FAMILY_SWISS;
3829 else
3831 reFamily = eFamilyA[pF->aFFNBase.ff];
3834 return true;
3837 bool SwWW8ImplReader::SetNewFontAttr(sal_uInt16 nFCode, bool bSetEnums,
3838 sal_uInt16 nWhich)
3840 FontFamily eFamily;
3841 OUString aName;
3842 FontPitch ePitch;
3843 rtl_TextEncoding eSrcCharSet;
3845 if( !GetFontParams( nFCode, eFamily, aName, ePitch, eSrcCharSet ) )
3847 //If we fail (and are not doing a style) then put something into the
3848 //character encodings stack anyway so that the property end that pops
3849 //off the stack will keep in sync
3850 if (!m_pCurrentColl && IsListOrDropcap())
3852 if (nWhich == RES_CHRATR_CJK_FONT)
3854 if (!m_aFontSrcCJKCharSets.empty())
3856 eSrcCharSet = m_aFontSrcCJKCharSets.top();
3858 else
3860 eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3863 m_aFontSrcCJKCharSets.push(eSrcCharSet);
3865 else
3867 if (!m_aFontSrcCharSets.empty())
3869 eSrcCharSet = m_aFontSrcCharSets.top();
3871 else
3873 eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3876 m_aFontSrcCharSets.push(eSrcCharSet);
3879 return false;
3882 rtl_TextEncoding eDstCharSet = eSrcCharSet;
3884 SvxFontItem aFont( eFamily, aName, OUString(), ePitch, eDstCharSet, nWhich);
3886 if( bSetEnums )
3888 if( m_pCurrentColl && m_nCurrentColl < m_vColl.size() ) // StyleDef
3890 switch(nWhich)
3892 default:
3893 case RES_CHRATR_FONT:
3894 m_vColl[m_nCurrentColl].m_eLTRFontSrcCharSet = eSrcCharSet;
3895 break;
3896 case RES_CHRATR_CTL_FONT:
3897 m_vColl[m_nCurrentColl].m_eRTLFontSrcCharSet = eSrcCharSet;
3898 break;
3899 case RES_CHRATR_CJK_FONT:
3900 m_vColl[m_nCurrentColl].m_eCJKFontSrcCharSet = eSrcCharSet;
3901 break;
3904 else if (IsListOrDropcap())
3906 //Add character text encoding to stack
3907 if (nWhich == RES_CHRATR_CJK_FONT)
3908 m_aFontSrcCJKCharSets.push(eSrcCharSet);
3909 else
3910 m_aFontSrcCharSets.push(eSrcCharSet);
3914 NewAttr( aFont ); // ...and insert
3916 return true;
3919 void SwWW8ImplReader::ResetCharSetVars()
3921 OSL_ENSURE(!m_aFontSrcCharSets.empty(),"no charset to remove");
3922 if (!m_aFontSrcCharSets.empty())
3923 m_aFontSrcCharSets.pop();
3926 void SwWW8ImplReader::ResetCJKCharSetVars()
3928 OSL_ENSURE(!m_aFontSrcCJKCharSets.empty(),"no charset to remove");
3929 if (!m_aFontSrcCJKCharSets.empty())
3930 m_aFontSrcCJKCharSets.pop();
3933 void SwWW8ImplReader::openFont(sal_uInt16 nFCode, sal_uInt16 nId)
3935 if (SetNewFontAttr(nFCode, true, nId) && m_pCurrentColl && m_xStyles)
3937 // remember for simulating default font
3938 if (RES_CHRATR_CJK_FONT == nId)
3939 m_xStyles->mbCJKFontChanged = true;
3940 else if (RES_CHRATR_CTL_FONT == nId)
3941 m_xStyles->mbCTLFontChanged = true;
3942 else
3943 m_xStyles->mbFontChanged = true;
3947 void SwWW8ImplReader::closeFont(sal_uInt16 nId)
3949 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3950 if (nId == RES_CHRATR_CJK_FONT)
3951 ResetCJKCharSetVars();
3952 else
3953 ResetCharSetVars();
3957 Turn font on or off:
3959 void SwWW8ImplReader::Read_FontCode( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3961 //Note: this function needs to be able to run multiple times on the same data.
3962 //It is called by Read_SubSuperProp to ensure that the current fontsize is known.
3964 if (m_bSymbol) // if bSymbol, the symbol's font
3965 return;
3967 // (see sprmCSymbol) is valid!
3968 switch( nId )
3970 case 113: //WW7
3971 case NS_sprm::CRgFtc2::val: //"Other" font, override with BiDi if it exists
3972 case NS_sprm::CFtcBi::val: //BiDi Font
3973 nId = RES_CHRATR_CTL_FONT;
3974 break;
3975 case NS_sprm::v6::sprmCFtc: //WW6
3976 case 111: //WW7
3977 case NS_sprm::CRgFtc0::val:
3978 nId = RES_CHRATR_FONT;
3979 break;
3980 case 112: //WW7
3981 case NS_sprm::CRgFtc1::val:
3982 nId = RES_CHRATR_CJK_FONT;
3983 break;
3984 default:
3985 return ;
3988 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3990 if (nLen < 2) // end of attribute
3992 if (eVersion <= ww::eWW6)
3994 closeFont(RES_CHRATR_CTL_FONT);
3995 closeFont(RES_CHRATR_CJK_FONT);
3997 closeFont(nId);
3999 else
4001 sal_uInt16 nFCode = SVBT16ToUInt16( pData ); // font number
4002 openFont(nFCode, nId);
4003 if (eVersion <= ww::eWW6)
4005 openFont(nFCode, RES_CHRATR_CJK_FONT);
4006 openFont(nFCode, RES_CHRATR_CTL_FONT);
4011 void SwWW8ImplReader::Read_FontSize( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4013 switch( nId )
4015 case 74: // WW2
4016 case NS_sprm::v6::sprmCHps:
4017 case NS_sprm::CHps::val:
4018 nId = RES_CHRATR_FONTSIZE;
4019 break;
4020 case 85: //WW2
4021 case 116: //WW7
4022 case NS_sprm::CHpsBi::val:
4023 nId = RES_CHRATR_CTL_FONTSIZE;
4024 break;
4025 default:
4026 return ;
4029 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
4031 if (nLen < (eVersion <= ww::eWW2 ? 1 : 2)) // end of attribute
4033 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4034 if (eVersion <= ww::eWW6) // reset additionally the CTL size
4035 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CTL_FONTSIZE );
4036 if (RES_CHRATR_FONTSIZE == nId) // reset additionally the CJK size
4037 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CJK_FONTSIZE );
4039 else
4041 // Font-Size in half points e.g. 10 = 1440 / ( 72 * 2 )
4042 sal_uLong nFSize = eVersion <= ww::eWW2 ? *pData : SVBT16ToUInt16(pData);
4043 nFSize*= 10;
4045 SvxFontHeightItem aSz( nFSize, 100, nId );
4046 NewAttr( aSz );
4047 if (RES_CHRATR_FONTSIZE == nId) // set additionally the CJK size
4049 aSz.SetWhich( RES_CHRATR_CJK_FONTSIZE );
4050 NewAttr( aSz );
4052 if (eVersion <= ww::eWW6) // set additionally the CTL size
4054 aSz.SetWhich( RES_CHRATR_CTL_FONTSIZE );
4055 NewAttr( aSz );
4057 if (m_pCurrentColl && m_xStyles) // Style-Def ?
4059 // remember for simulating default font size
4060 if (nId == RES_CHRATR_CTL_FONTSIZE)
4061 m_xStyles->mbFCTLSizeChanged = true;
4062 else
4064 m_xStyles->mbFSizeChanged = true;
4065 if (eVersion <= ww::eWW6)
4066 m_xStyles->mbFCTLSizeChanged= true;
4072 void SwWW8ImplReader::Read_CharSet(sal_uInt16 , const sal_uInt8* pData, short nLen)
4074 if (nLen < 1)
4075 { // end of attribute
4076 m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
4077 return;
4079 sal_uInt8 nfChsDiff = *pData;
4081 if (nfChsDiff && nLen >= 2)
4082 m_eHardCharSet = rtl_getTextEncodingFromWindowsCharset( *(pData + 1) );
4083 else
4084 m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
4087 void SwWW8ImplReader::Read_Language( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4089 switch( nId )
4091 case NS_sprm::v6::sprmCLid:
4092 case NS_sprm::CRgLid0_80::val:
4093 case NS_sprm::CRgLid0::val:
4094 nId = RES_CHRATR_LANGUAGE;
4095 break;
4096 case NS_sprm::CRgLid1_80::val:
4097 case NS_sprm::CRgLid1::val:
4098 nId = RES_CHRATR_CJK_LANGUAGE;
4099 break;
4100 case 83: // WW2
4101 case 114: // WW7
4102 case NS_sprm::CLidBi::val:
4103 nId = RES_CHRATR_CTL_LANGUAGE;
4104 break;
4105 default:
4106 return;
4109 if (nLen < 2) // end of attribute
4110 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4111 else
4113 sal_uInt16 nLang = SVBT16ToUInt16( pData ); // Language-Id
4114 NewAttr(SvxLanguageItem(LanguageType(nLang), nId));
4119 Turn on character style:
4121 void SwWW8ImplReader::Read_CColl( sal_uInt16, const sal_uInt8* pData, short nLen )
4123 if (nLen < 2) // end of attribute
4125 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_TXTATR_CHARFMT );
4126 m_nCharFormat = -1;
4127 return;
4129 sal_uInt16 nId = SVBT16ToUInt16( pData ); // Style-Id (NOT Sprm-Id!)
4131 if( nId >= m_vColl.size() || !m_vColl[nId].m_pFormat // invalid Id?
4132 || m_vColl[nId].m_bColl ) // or paragraph style?
4133 return; // then ignore
4135 // if current on loading a TOX field, and current trying to apply a hyperlink character style,
4136 // just ignore. For the hyperlinks inside TOX in MS Word is not same with a common hyperlink
4137 // Character styles: without underline and blue font color. And such type style will be applied in others
4138 // processes.
4139 if (m_bLoadingTOXCache && m_vColl[nId].GetWWStyleId() == ww::stiHyperlink)
4141 return;
4144 NewAttr( SwFormatCharFormat( static_cast<SwCharFormat*>(m_vColl[nId].m_pFormat) ) );
4145 m_nCharFormat = static_cast<short>(nId);
4149 Narrower or wider than normal:
4151 void SwWW8ImplReader::Read_Kern( sal_uInt16, const sal_uInt8* pData, short nLen )
4153 if (nLen < 2) // end of attribute
4155 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_KERNING );
4156 return;
4158 sal_Int16 nKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4159 NewAttr( SvxKerningItem( nKern, RES_CHRATR_KERNING ) );
4162 void SwWW8ImplReader::Read_FontKern( sal_uInt16, const sal_uInt8* pData, short nLen )
4164 if (nLen < 2) // end of attribute
4166 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_AUTOKERN );
4167 return;
4169 sal_Int16 nAutoKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4170 NewAttr(SvxAutoKernItem(static_cast<bool>(nAutoKern), RES_CHRATR_AUTOKERN));
4173 void SwWW8ImplReader::Read_CharShadow( sal_uInt16, const sal_uInt8* pData, short nLen )
4175 //Has newer colour variant, ignore this old variant
4176 if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CShd::val).pSprm)
4177 return;
4179 if (nLen < 2)
4181 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BACKGROUND );
4183 else
4185 WW8_SHD aSHD;
4186 aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4187 SwWW8Shade aSh( m_bVer67, aSHD );
4189 NewAttr( SvxBrushItem( aSh.m_aColor, RES_CHRATR_BACKGROUND ));
4191 // Add a marker to the grabbag indicating that character background was imported from MSO shading
4192 SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4193 std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4194 rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::Any(true)));
4195 NewAttr(aGrabBag);
4199 void SwWW8ImplReader::Read_TextBackColor(sal_uInt16, const sal_uInt8* pData, short nLen )
4201 if (nLen <= 0)
4203 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BACKGROUND );
4205 else
4207 OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4208 if (nLen != 10)
4209 return;
4210 Color aColour(ExtractColour(pData, m_bVer67));
4211 NewAttr(SvxBrushItem(aColour, RES_CHRATR_BACKGROUND));
4213 // Add a marker to the grabbag indicating that character background was imported from MSO shading
4214 SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4215 std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4216 rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::Any(true)));
4217 NewAttr(aGrabBag);
4221 void SwWW8ImplReader::Read_CharHighlight(sal_uInt16, const sal_uInt8* pData, short nLen)
4223 // MS Word completely ignores character highlighting in character styles.
4224 if ( m_pCurrentColl && m_pCurrentColl->Which() == RES_CHRFMT )
4225 return;
4227 if (nLen < 1)
4229 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_HIGHLIGHT );
4231 else
4233 sal_uInt8 b = *pData; // Parameter: 0 = Auto, 1..16 colors
4235 if( b > 16 ) // invalid -> Black
4236 b = 0; // Auto -> Black
4238 Color aCol(GetCol(b));
4239 NewAttr( SvxBrushItem( aCol , RES_CHRATR_HIGHLIGHT ));
4243 void SwWW8ImplReader::Read_NoLineNumb(sal_uInt16 , const sal_uInt8* pData, short nLen)
4245 if (nLen < 0) // end of attribute
4247 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_LINENUMBER );
4248 return;
4250 SwFormatLineNumber aLN;
4251 if (const SwFormatLineNumber* pLN
4252 = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
4254 aLN.SetStartValue( pLN->GetStartValue() );
4257 aLN.SetCountLines(pData && nLen >= 1 && (0 == *pData));
4258 NewAttr( aLN );
4261 static bool lcl_HasExplicitLeft(const WW8PLCFMan *pPlcxMan, bool bVer67)
4263 WW8PLCFx_Cp_FKP *pPap = pPlcxMan ? pPlcxMan->GetPapPLCF() : nullptr;
4264 if (pPap)
4266 if (bVer67)
4267 return pPap->HasSprm(NS_sprm::v6::sprmPDxaLeft).pSprm;
4268 else
4269 return (pPap->HasSprm(NS_sprm::PDxaLeft80::val).pSprm || pPap->HasSprm(NS_sprm::PDxaLeft::val).pSprm);
4271 return false;
4274 // Sprm 16, 17
4275 void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4277 if (nLen < 2) // end of attribute
4279 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_MARGIN_FIRSTLINE);
4280 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_MARGIN_TEXTLEFT);
4281 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_MARGIN_RIGHT);
4282 return;
4285 short nPara = SVBT16ToUInt16( pData );
4287 SfxPoolItem const* pItem(GetFormatAttr(RES_MARGIN_FIRSTLINE));
4288 ::std::unique_ptr<SvxFirstLineIndentItem> pFirstLine(pItem
4289 ? static_cast<SvxFirstLineIndentItem*>(pItem->Clone())
4290 : new SvxFirstLineIndentItem(RES_MARGIN_FIRSTLINE));
4291 pItem = GetFormatAttr(RES_MARGIN_TEXTLEFT);
4292 ::std::unique_ptr<SvxTextLeftMarginItem> pLeftMargin(pItem
4293 ? static_cast<SvxTextLeftMarginItem*>(pItem->Clone())
4294 : new SvxTextLeftMarginItem(RES_MARGIN_TEXTLEFT));
4295 pItem = GetFormatAttr(RES_MARGIN_RIGHT);
4296 ::std::unique_ptr<SvxRightMarginItem> pRightMargin(pItem
4297 ? static_cast<SvxRightMarginItem*>(pItem->Clone())
4298 : new SvxRightMarginItem(RES_MARGIN_RIGHT));
4300 // Fix the regression issue: #i99822#: Discussion?
4301 // Since the list level formatting doesn't apply into paragraph style
4302 // for list levels of mode LABEL_ALIGNMENT.(see ww8par3.cxx
4303 // W8ImplReader::RegisterNumFormatOnTextNode).
4304 // Need to apply the list format to the paragraph here.
4305 SwTextNode* pTextNode = m_pPaM->GetPointNode().GetTextNode();
4306 if (pTextNode
4307 && pTextNode->AreListLevelIndentsApplicable() != ::sw::ListLevelIndents::No)
4309 SwNumRule * pNumRule = pTextNode->GetNumRule();
4310 if( pNumRule )
4312 sal_uInt8 nLvl = static_cast< sal_uInt8 >(pTextNode->GetActualListLevel());
4313 const SwNumFormat* pFormat = pNumRule->GetNumFormat( nLvl );
4314 if ( pFormat && pFormat->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
4316 pLeftMargin->SetTextLeft(pFormat->GetIndentAt());
4317 pFirstLine->SetTextFirstLineOffset(static_cast<short>(pFormat->GetFirstLineIndent()));
4318 // make paragraph have hard-set indent attributes
4319 pTextNode->SetAttr(*pLeftMargin);
4320 pTextNode->SetAttr(*pFirstLine);
4326 The older word sprms mean left/right, while the new ones mean before/after.
4327 Writer now also works with before after, so when we see old left/right and
4328 we're RTL. We swap them
4330 if (IsRightToLeft())
4332 switch (nId)
4334 //Left becomes after;
4335 case NS_sprm::v6::sprmPDxaLeft:
4336 nId = NS_sprm::v6::sprmPDxaRight;
4337 break;
4338 case NS_sprm::PDxaLeft80::val:
4339 nId = NS_sprm::PDxaRight80::val;
4340 break;
4341 //Right becomes before;
4342 case NS_sprm::v6::sprmPDxaRight:
4343 nId = NS_sprm::v6::sprmPDxaLeft;
4344 break;
4345 case NS_sprm::PDxaRight80::val:
4346 nId = NS_sprm::PDxaLeft80::val;
4347 break;
4351 bool bFirstLinOfstSet( false ); // #i103711#
4352 bool bLeftIndentSet( false ); // #i105414#
4354 switch (nId)
4356 //sprmPDxaLeft
4357 case NS_sprm::v6::sprmPDxaLeft:
4358 case NS_sprm::PDxaLeft80::val:
4359 case NS_sprm::PDxaLeft::val:
4360 pLeftMargin->SetTextLeft(nPara);
4361 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4363 m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4365 bLeftIndentSet = true; // #i105414#
4366 break;
4367 //sprmPDxaLeft1
4368 case NS_sprm::v6::sprmPDxaLeft1:
4369 case NS_sprm::PDxaLeft180::val:
4370 case NS_sprm::PDxaLeft1::val:
4372 As part of an attempt to break my spirit ww 8+ formats can contain
4373 ww 7- lists. If they do and the list is part of the style, then
4374 when removing the list from a paragraph of that style there
4375 appears to be a bug where the hanging indent value which the list
4376 set is still factored into the left indent of the paragraph. Its
4377 not listed in the winword dialogs, but it is clearly there. So if
4378 our style has a broken ww 7- list and we know that the list has
4379 been removed then we will factor the original list applied hanging
4380 into our calculation.
4382 if (m_xPlcxMan && m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_bHasBrokenWW6List)
4384 SprmResult aIsZeroed = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PIlfo::val);
4385 if (aIsZeroed.pSprm && aIsZeroed.nRemainingData >= 1 && *aIsZeroed.pSprm == 0)
4387 const SvxFirstLineIndentItem & rFirstLine =
4388 m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(RES_MARGIN_FIRSTLINE);
4389 nPara = nPara - rFirstLine.GetTextFirstLineOffset();
4393 pFirstLine->SetTextFirstLineOffset(nPara);
4395 if (!m_pCurrentColl)
4397 if (const SwTextNode* pNode = m_pPaM->GetPointNode().GetTextNode())
4399 if ( const SwNumFormat *pNumFormat = GetNumFormatFromTextNode(*pNode) )
4401 if (!lcl_HasExplicitLeft(m_xPlcxMan.get(), m_bVer67))
4403 pLeftMargin->SetTextLeft(pNumFormat->GetIndentAt());
4405 // If have not explicit left, set number format list tab position is doc default tab
4406 const SvxTabStopItem *pDefaultStopItem = m_rDoc.GetAttrPool().GetPoolDefaultItem(RES_PARATR_TABSTOP);
4407 if ( pDefaultStopItem && pDefaultStopItem->Count() > 0 )
4408 const_cast<SwNumFormat*>(pNumFormat)->SetListtabPos( const_cast<SvxTabStop&>((*pDefaultStopItem)[0]).GetTabPos() );
4413 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4415 m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4417 bFirstLinOfstSet = true; // #i103711#
4418 break;
4419 //sprmPDxaRight
4420 case NS_sprm::v6::sprmPDxaRight:
4421 case NS_sprm::PDxaRight80::val:
4422 case NS_sprm::PDxaRight::val:
4423 pRightMargin->SetRight(nPara);
4424 break;
4425 default:
4426 return;
4429 NewAttr(*pFirstLine, bFirstLinOfstSet, false); // #i103711#, #i105414#
4430 NewAttr(*pLeftMargin, false, bLeftIndentSet);
4431 NewAttr(*pRightMargin, false, false);
4434 // Sprm 20
4435 void SwWW8ImplReader::Read_LineSpace( sal_uInt16, const sal_uInt8* pData, short nLen )
4437 // comment see Read_UL()
4438 if (m_bStyNormal && m_bWWBugNormal)
4439 return;
4441 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
4443 if (nLen < (eVersion <= ww::eWW2 ? 3 : 4))
4445 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_LINESPACING );
4446 if( !( m_nIniFlags & WW8FL_NO_IMPLPASP ) )
4447 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4448 return;
4451 short nSpace = SVBT16ToUInt16( pData );
4452 short nMulti = (eVersion <= ww::eWW2) ? 1 : SVBT16ToUInt16( pData + 2 );
4454 SvxLineSpaceRule eLnSpc;
4455 if( 0 > nSpace )
4457 nSpace = -nSpace;
4458 eLnSpc = SvxLineSpaceRule::Fix;
4460 else
4461 eLnSpc = SvxLineSpaceRule::Min;
4463 // WW has implicit additional paragraph spacing depending on
4464 // the line spacing. It is, for "exactly", 0.8 * line spacing "before"
4465 // and 0.2 * line spacing "after".
4466 // For "at least", it is 1 * line spacing "before" and 0 * line spacing "after".
4467 // For "multiple", it is 0 "before" and min(0cm, FontSize*(nFach-1)) "after".
4469 // SW also has implicit line spacing. It is, for "at least"
4470 // 1 * line spacing "before" and 0 "after".
4471 // For proportional, it is min(0cm, FontSize*(nFach-1)) both "before" and "after".
4473 sal_uInt16 nSpaceTw = 0;
4475 SvxLineSpacingItem aLSpc( LINE_SPACE_DEFAULT_HEIGHT, RES_PARATR_LINESPACING );
4477 if( 1 == nMulti ) // MultilineSpace ( proportional )
4479 tools::Long n = nSpace * 10 / 24; // WW: 240 = 100%, SW: 100 = 100%
4481 // here n is in [0..13653]
4482 aLSpc.SetPropLineSpace( o3tl::narrowing<sal_uInt16>(n) );
4483 const SvxFontHeightItem* pH = static_cast<const SvxFontHeightItem*>(
4484 GetFormatAttr( RES_CHRATR_FONTSIZE ));
4485 nSpaceTw = o3tl::narrowing<sal_uInt16>( n * pH->GetHeight() / 100 );
4487 else // Fixed / Minimum
4489 // for negative space, the distance is "exact", otherwise "at least"
4490 nSpaceTw = o3tl::narrowing<sal_uInt16>(nSpace);
4491 aLSpc.SetLineHeight( nSpaceTw );
4492 aLSpc.SetLineSpaceRule( eLnSpc);
4494 NewAttr( aLSpc );
4495 if (m_xSFlyPara)
4496 m_xSFlyPara->nLineSpace = nSpaceTw; // linespace for graphics APOs
4499 //#i18519# AutoSpace value depends on Dop fDontUseHTMLAutoSpacing setting
4500 sal_uInt16 SwWW8ImplReader::GetParagraphAutoSpace(bool fDontUseHTMLAutoSpacing)
4502 if (fDontUseHTMLAutoSpacing)
4503 return 100; //Seems to be always 5points in this case
4504 else
4505 return 280; //Seems to be always 14points in this case
4508 void SwWW8ImplReader::Read_ParaAutoBefore(sal_uInt16, const sal_uInt8 *pData, short nLen)
4510 if (nLen < 1)
4512 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4513 return;
4516 if (*pData)
4518 SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4519 aUL.SetUpper(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4520 NewAttr(aUL);
4521 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4522 m_vColl[m_nCurrentColl].m_bParaAutoBefore = true;
4523 else
4524 m_bParaAutoBefore = true;
4526 else
4528 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4529 m_vColl[m_nCurrentColl].m_bParaAutoBefore = false;
4530 else
4531 m_bParaAutoBefore = false;
4535 void SwWW8ImplReader::Read_ParaAutoAfter(sal_uInt16, const sal_uInt8 *pData, short nLen)
4537 if (nLen < 1)
4539 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4540 return;
4543 if (*pData)
4545 SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4546 aUL.SetLower(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4547 NewAttr(aUL);
4548 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4549 m_vColl[m_nCurrentColl].m_bParaAutoAfter = true;
4550 else
4551 m_bParaAutoAfter = true;
4553 else
4555 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4556 m_vColl[m_nCurrentColl].m_bParaAutoAfter = false;
4557 else
4558 m_bParaAutoAfter = false;
4562 // Sprm 21, 22
4563 void SwWW8ImplReader::Read_UL( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4565 // A workaround for an error in WW: For nProduct == 0c03d, usually
4566 // DyaAfter 240 (delta y distance after, comment of the translator)
4567 // is incorrectly inserted into style "Normal", even though it isn't there.
4568 // Using the ini flag WW8FL_NO_STY_DYA you can force this behavior for other
4569 // WW versions as well.
4570 // OSL_ENSURE( !bStyNormal || bWWBugNormal, "+This Document may point to a bug
4571 // in the WW version used for creating it. If the Styles <Standard> resp.
4572 // <Normal> differentiate between WW and SW in paragraph or line spacing,
4573 // then please send this Document to SH.");
4574 // bWWBugNormal is not a sufficient criterion for this distance being wrong.
4576 if (nLen < 2)
4578 // end of attribute
4579 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4580 return;
4582 short nPara = SVBT16ToUInt16( pData );
4583 if( nPara < 0 )
4584 nPara = -nPara;
4586 SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4588 switch( nId )
4590 //sprmPDyaBefore
4591 case NS_sprm::v6::sprmPDyaBefore:
4592 case NS_sprm::PDyaBefore::val:
4593 aUL.SetUpper( nPara );
4594 break;
4595 //sprmPDyaAfter
4596 case NS_sprm::v6::sprmPDyaAfter:
4597 case NS_sprm::PDyaAfter::val:
4598 aUL.SetLower( nPara );
4599 break;
4600 default:
4601 return;
4604 NewAttr( aUL );
4607 void SwWW8ImplReader::Read_ParaContextualSpacing( sal_uInt16, const sal_uInt8* pData, short nLen )
4609 if (nLen < 1)
4611 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4612 return;
4614 SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4615 aUL.SetContextValue(*pData != 0);
4616 NewAttr( aUL );
4619 void SwWW8ImplReader::Read_LineBreakClear(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
4621 if (nLen == -1 && m_oLineBreakClear.has_value())
4623 SwTextNode* pText = m_pPaM->GetPointNode().GetTextNode();
4624 sal_Int32 nPos = m_pPaM->GetPoint()->GetContentIndex();
4625 if (!pText || !nPos)
4627 // There should have been a linebreak char.
4628 return;
4631 // Replace the linebreak char with a clearing break.
4632 --nPos;
4633 m_pPaM->SetMark();
4634 m_pPaM->GetMark()->AdjustContent(-1);
4635 m_rDoc.getIDocumentContentOperations().DeleteRange(*m_pPaM);
4636 m_pPaM->DeleteMark();
4637 SwFormatLineBreak aLineBreak(*m_oLineBreakClear);
4638 m_oLineBreakClear.reset();
4639 pText->InsertItem(aLineBreak, nPos, nPos);
4642 if (nLen < 1)
4644 return;
4647 sal_uInt8 nClear = pData[0];
4648 if (nClear > 3)
4650 return;
4653 auto eClear = static_cast<SwLineBreakClear>(nClear);
4654 m_oLineBreakClear = eClear;
4657 void SwWW8ImplReader::Read_IdctHint( sal_uInt16, const sal_uInt8* pData, short nLen )
4659 // sprmcidcthint (opcode 0x286f) specifies a script bias for the text in the run.
4660 // for unicode characters that are shared between far east and non-far east scripts,
4661 // this property determines what font and language the character will use.
4662 // when this value is 0, text properties bias towards non-far east properties.
4663 // when this value is 1, text properties bias towards far east properties.
4664 // when this value is 2, text properties bias towards complex properties.
4665 if (nLen < 1) //Property end
4667 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),RES_CHRATR_IDCTHINT);
4669 else //Property start
4671 NewAttr(SfxInt16Item(RES_CHRATR_IDCTHINT, *pData));
4675 void SwWW8ImplReader::Read_Justify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4677 if (nLen < 1)
4679 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4680 return;
4683 SvxAdjust eAdjust(SvxAdjust::Left);
4684 bool bDistributed = false;
4685 switch (*pData)
4687 default:
4688 case 0:
4689 break;
4690 case 1:
4691 eAdjust = SvxAdjust::Center;
4692 break;
4693 case 2:
4694 eAdjust = SvxAdjust::Right;
4695 break;
4696 case 3:
4697 eAdjust = SvxAdjust::Block;
4698 break;
4699 case 4:
4700 eAdjust = SvxAdjust::Block;
4701 bDistributed = true;
4702 break;
4704 SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4705 if (bDistributed)
4706 aAdjust.SetLastBlock(SvxAdjust::Block);
4708 NewAttr(aAdjust);
4709 SetRelativeJustify( nId != NS_sprm::PJc80::val );
4712 bool SwWW8ImplReader::IsRightToLeft()
4714 bool bRTL = false;
4715 SprmResult aDir;
4716 if (m_xPlcxMan)
4717 aDir = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PFBiDi::val);
4718 if (aDir.pSprm && aDir.nRemainingData >= 1)
4719 bRTL = *aDir.pSprm != 0;
4720 else
4722 const SvxFrameDirectionItem* pItem=
4723 static_cast<const SvxFrameDirectionItem*>(GetFormatAttr(RES_FRAMEDIR));
4724 if (pItem && (pItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4725 bRTL = true;
4727 return bRTL;
4730 void SwWW8ImplReader::Read_RTLJustify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4732 if (nLen < 1)
4734 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4735 return;
4738 //If we are in a ltr paragraph this is the same as normal Justify,
4739 //If we are in a rtl paragraph the meaning is reversed.
4740 if (!IsRightToLeft())
4741 Read_Justify(nId, pData, nLen);
4742 else
4744 SvxAdjust eAdjust(SvxAdjust::Right);
4745 bool bDistributed = false;
4746 switch (*pData)
4748 default:
4749 case 0:
4750 break;
4751 case 1:
4752 eAdjust = SvxAdjust::Center;
4753 break;
4754 case 2:
4755 eAdjust = SvxAdjust::Left;
4756 break;
4757 case 3:
4758 eAdjust = SvxAdjust::Block;
4759 break;
4760 case 4:
4761 eAdjust = SvxAdjust::Block;
4762 bDistributed = true;
4763 break;
4765 SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4766 if (bDistributed)
4767 aAdjust.SetLastBlock(SvxAdjust::Block);
4769 NewAttr(aAdjust);
4770 SetRelativeJustify( true );
4774 void SwWW8ImplReader::Read_BoolItem( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4776 switch( nId )
4778 case NS_sprm::PFKinsoku::val:
4779 nId = RES_PARATR_FORBIDDEN_RULES;
4780 break;
4781 case NS_sprm::PFOverflowPunct::val:
4782 nId = RES_PARATR_HANGINGPUNCTUATION;
4783 break;
4784 case NS_sprm::PFAutoSpaceDE::val:
4785 nId = RES_PARATR_SCRIPTSPACE;
4786 break;
4787 default:
4788 OSL_ENSURE( false, "wrong Id" );
4789 return ;
4792 if (nLen < 1)
4793 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4794 else
4796 std::unique_ptr<SfxBoolItem> pI(static_cast<SfxBoolItem*>(GetDfltAttr( nId )->Clone()));
4797 pI->SetValue( 0 != *pData );
4798 NewAttr( *pI );
4802 void SwWW8ImplReader::Read_Emphasis( sal_uInt16, const sal_uInt8* pData, short nLen )
4804 if (nLen < 1)
4805 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_EMPHASIS_MARK );
4806 else
4808 LanguageType nLang;
4809 //Check to see if there is an up and coming cjk language property. If
4810 //there is use it, if there is not fall back to the currently set one.
4811 //Only the cjk language setting seems to matter to word, the western
4812 //one is ignored
4813 SprmResult aLang;
4814 if (m_xPlcxMan)
4815 aLang = m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CRgLid1_80::val);
4817 if (aLang.pSprm && aLang.nRemainingData >= 2)
4818 nLang = LanguageType(SVBT16ToUInt16(aLang.pSprm));
4819 else
4821 nLang = static_cast<const SvxLanguageItem *>(
4822 GetFormatAttr(RES_CHRATR_CJK_LANGUAGE))->GetLanguage();
4825 FontEmphasisMark nVal;
4826 switch( *pData )
4828 case 0:
4829 nVal = FontEmphasisMark::NONE;
4830 break;
4831 case 2:
4832 if (MsLangId::isKorean(nLang) || MsLangId::isTraditionalChinese(nLang))
4833 nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4834 else if (nLang == LANGUAGE_JAPANESE)
4835 nVal = (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove);
4836 else
4837 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4838 break;
4839 case 3:
4840 nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4841 break;
4842 case 4:
4843 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4844 break;
4845 case 1:
4846 if (MsLangId::isSimplifiedChinese(nLang))
4847 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4848 else
4849 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4850 break;
4851 default:
4852 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4853 break;
4856 NewAttr( SvxEmphasisMarkItem( nVal, RES_CHRATR_EMPHASIS_MARK ) );
4860 void SwWW8ImplReader::Read_ScaleWidth( sal_uInt16, const sal_uInt8* pData, short nLen )
4862 if (nLen < 2)
4863 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SCALEW );
4864 else
4866 sal_uInt16 nVal = SVBT16ToUInt16( pData );
4867 //The number must be between 1 and 600
4868 if (nVal < 1 || nVal > 600)
4869 nVal = 100;
4870 NewAttr( SvxCharScaleWidthItem( nVal, RES_CHRATR_SCALEW ) );
4874 void SwWW8ImplReader::Read_Relief( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4876 if (nLen < 1)
4877 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_RELIEF );
4878 else
4880 if( *pData )
4882 // not so easy because this is also a toggle attribute!
4883 // 2 x emboss on -> no emboss !!!
4884 // the actual value must be searched over the stack / template
4886 const SvxCharReliefItem* pOld = static_cast<const SvxCharReliefItem*>(
4887 GetFormatAttr( RES_CHRATR_RELIEF ));
4888 FontRelief nNewValue = NS_sprm::CFImprint::val == nId ? FontRelief::Engraved
4889 : ( NS_sprm::CFEmboss::val == nId ? FontRelief::Embossed
4890 : FontRelief::NONE );
4891 if( pOld->GetValue() == nNewValue )
4893 if( FontRelief::NONE != nNewValue )
4894 nNewValue = FontRelief::NONE;
4896 NewAttr( SvxCharReliefItem( nNewValue, RES_CHRATR_RELIEF ));
4901 void SwWW8ImplReader::Read_TextAnim(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
4903 if (nLen < 1)
4904 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_BLINK);
4905 else
4907 if (*pData)
4909 bool bBlink;
4911 // The 7 animated text effects available in word all get
4912 // mapped to a blinking text effect in LibreOffice
4913 // 0 no animation 1 Las Vegas lights
4914 // 2 background blink 3 sparkle text
4915 // 4 marching ants 5 marching red ants
4916 // 6 shimmer
4917 bBlink = *pData > 0 && *pData < 7;
4919 NewAttr(SvxBlinkItem(bBlink, RES_CHRATR_BLINK));
4924 SwWW8Shade::SwWW8Shade(bool bVer67, const WW8_SHD& rSHD)
4926 sal_uInt8 b = rSHD.GetFore();
4927 OSL_ENSURE(b < 17, "ww8: colour out of range");
4928 if (b >= 17)
4929 b = 0;
4931 Color nFore(SwWW8ImplReader::GetCol(b));
4933 b = rSHD.GetBack();
4934 OSL_ENSURE(b < 17, "ww8: colour out of range");
4935 if( b >= 17 )
4936 b = 0;
4938 Color nBack(SwWW8ImplReader::GetCol(b));
4940 b = rSHD.GetStyle(bVer67);
4942 SetShade(nFore, nBack, b);
4945 void SwWW8Shade::SetShade(Color nFore, Color nBack, sal_uInt16 nIndex)
4947 static const sal_uLong eMSGrayScale[] =
4949 // Clear-Brush
4950 0, // 0 clear
4951 // Solid-Brush
4952 1000, // 1 solid
4953 // Percent values
4954 50, // 2 pct5
4955 100, // 3 pct10
4956 200, // 4 pct20
4957 250, // 5 pct25
4958 300, // 6 pct30
4959 400, // 7 pct40
4960 500, // 8 pct50
4961 600, // 9 pct60
4962 700, // 10 pct70
4963 750, // 11 pct75
4964 800, // 12 pct80
4965 900, // 13 pct90
4966 // Special cases
4967 333, // 14 Dark Horizontal
4968 333, // 15 Dark Vertical
4969 333, // 16 Dark Forward Diagonal
4970 333, // 17 Dark Backward Diagonal
4971 333, // 18 Dark Cross
4972 333, // 19 Dark Diagonal Cross
4973 333, // 20 Horizontal
4974 333, // 21 Vertical
4975 333, // 22 Forward Diagonal
4976 333, // 23 Backward Diagonal
4977 333, // 24 Cross
4978 333, // 25 Diagonal Cross
4979 // Undefined values in DOC spec-sheet
4980 500, // 26
4981 500, // 27
4982 500, // 28
4983 500, // 29
4984 500, // 30
4985 500, // 31
4986 500, // 32
4987 500, // 33
4988 500, // 34
4989 // Different shading types
4990 25, // 35 [available in DOC, not available in DOCX]
4991 75, // 36 [available in DOC, not available in DOCX]
4992 125, // 37 pct12
4993 150, // 38 pct15
4994 175, // 39 [available in DOC, not available in DOCX]
4995 225, // 40 [available in DOC, not available in DOCX]
4996 275, // 41 [available in DOC, not available in DOCX]
4997 325, // 42 [available in DOC, not available in DOCX]
4998 350, // 43 pct35
4999 375, // 44 pct37
5000 425, // 45 [available in DOC, not available in DOCX]
5001 450, // 46 pct45
5002 475, // 47 [available in DOC, not available in DOCX]
5003 525, // 48 [available in DOC, not available in DOCX]
5004 550, // 49 pct55
5005 575, // 50 [available in DOC, not available in DOCX]
5006 625, // 51 pct62
5007 650, // 52 pct65
5008 675, // 53 [available in DOC, not available in DOCX]
5009 725, // 54 [available in DOC, not available in DOCX]
5010 775, // 55 [available in DOC, not available in DOCX]
5011 825, // 56 [available in DOC, not available in DOCX]
5012 850, // 57 pct85
5013 875, // 58 pct87
5014 925, // 59 [available in DOC, not available in DOCX]
5015 950, // 60 pct95
5016 975 // 61 [available in DOC, not available in DOCX]
5017 };// 62
5019 //NO auto for shading so Foreground: Auto = Black
5020 if (nFore == COL_AUTO)
5021 nFore = COL_BLACK;
5023 //NO auto for shading so background: Auto = White
5024 Color nUseBack = nBack;
5025 if (nUseBack == COL_AUTO)
5026 nUseBack = COL_WHITE;
5028 if( nIndex >= SAL_N_ELEMENTS( eMSGrayScale ) )
5029 nIndex = 0;
5031 sal_uLong nWW8BrushStyle = eMSGrayScale[nIndex];
5033 switch (nWW8BrushStyle)
5035 case 0: // Null-Brush
5036 m_aColor = nBack;
5037 break;
5038 default:
5040 Color aForeColor(nFore);
5041 Color aBackColor(nUseBack);
5043 sal_uInt32 nRed = aForeColor.GetRed() * nWW8BrushStyle;
5044 sal_uInt32 nGreen = aForeColor.GetGreen() * nWW8BrushStyle;
5045 sal_uInt32 nBlue = aForeColor.GetBlue() * nWW8BrushStyle;
5046 nRed += aBackColor.GetRed() * (1000 - nWW8BrushStyle);
5047 nGreen += aBackColor.GetGreen()* (1000 - nWW8BrushStyle);
5048 nBlue += aBackColor.GetBlue() * (1000 - nWW8BrushStyle);
5050 m_aColor = Color( nRed/1000, nGreen/1000, nBlue/1000 );
5052 break;
5056 void SwWW8ImplReader::Read_Shade( sal_uInt16, const sal_uInt8* pData, short nLen )
5058 if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PShd::val).pSprm)
5059 return;
5061 if (nLen < 2)
5063 // end of attribute
5064 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
5065 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
5067 else
5069 WW8_SHD aSHD;
5070 aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
5071 SwWW8Shade aSh( m_bVer67, aSHD );
5073 NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
5074 NewAttr( XFillColorItem(OUString(), aSh.m_aColor) );
5078 void SwWW8ImplReader::Read_ParaBackColor(sal_uInt16, const sal_uInt8* pData, short nLen)
5080 if (nLen <= 0)
5082 // end of attribute
5083 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
5084 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
5086 else
5088 OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
5089 if (nLen != 10)
5090 return;
5092 const Color aColor = ExtractColour(pData, m_bVer67);
5093 NewAttr( XFillColorItem(OUString(), aColor) );
5094 if ( aColor == COL_AUTO )
5095 NewAttr( XFillStyleItem(drawing::FillStyle_NONE) );
5096 else
5097 NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
5101 Color SwWW8ImplReader::ExtractColour(const sal_uInt8* &rpData, bool bVer67)
5103 OSL_ENSURE(!bVer67, "Impossible");
5104 Color nFore = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
5105 rpData+=4;
5106 Color nBack = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
5107 rpData+=4;
5108 sal_uInt16 nIndex = SVBT16ToUInt16(rpData);
5109 rpData+=2;
5110 //Being a transparent background colour doesn't actually show the page
5111 //background through, it merely acts like white
5112 if (nBack == Color(ColorTransparency, 0xFF000000))
5113 nBack = COL_AUTO;
5114 OSL_ENSURE(nBack == COL_AUTO || !nBack.IsTransparent(),
5115 "ww8: don't know what to do with such a transparent bg colour, report");
5116 SwWW8Shade aShade(nFore, nBack, nIndex);
5117 return aShade.m_aColor;
5120 void SwWW8ImplReader::Read_TextVerticalAdjustment( sal_uInt16, const sal_uInt8* pData, short nLen )
5122 if( nLen <= 0 )
5123 return;
5125 drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
5126 switch( *pData )
5128 case 1:
5129 nVA = drawing::TextVerticalAdjust_CENTER;
5130 break;
5131 case 2: //justify
5132 nVA = drawing::TextVerticalAdjust_BLOCK;
5133 break;
5134 case 3:
5135 nVA = drawing::TextVerticalAdjust_BOTTOM;
5136 break;
5137 default:
5138 break;
5140 m_aSectionManager.SetCurrentSectionVerticalAdjustment( nVA );
5143 void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
5145 if (nLen < 0)
5147 if( m_bHasBorder )
5149 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BOX );
5150 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_SHADOW );
5151 m_bHasBorder = false;
5154 else if( !m_bHasBorder )
5156 // the borders on all four sides are bundled. That
5157 // simplifies the administration, i.e., the box does not have
5158 // to be put on and removed from CtrlStack 4 times.
5159 m_bHasBorder = true;
5161 WW8_BRCVer9_5 aBrcs; // Top, Left, Bottom, Right, Between
5162 sal_uInt8 nBorder;
5164 if( m_pCurrentColl )
5165 nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, nullptr, m_xStyles.get());
5166 else
5167 nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr);
5169 if( nBorder ) // Border
5171 bool bIsB = IsBorder(aBrcs, true);
5172 if (!InLocalApo() || !bIsB || (m_xWFlyPara && !m_xWFlyPara->bBorderLines))
5174 // Do not turn *on* borders in APO, since otherwise
5175 // I get the Fly border twice;
5176 // but only when it is set on in the Fly, skip it;
5177 // otherwise there is none at all!
5179 // even if no border is set, the attribute has to be set,
5180 // otherwise it's not possible to turn off the style attribute.
5181 const SvxBoxItem* pBox
5182 = static_cast<const SvxBoxItem*>(GetFormatAttr( RES_BOX ));
5183 std::shared_ptr<SvxBoxItem> aBox(std::make_shared<SvxBoxItem>(RES_BOX));
5184 if (pBox)
5185 aBox.reset(pBox->Clone());
5186 short aSizeArray[5]={0};
5188 SetBorder(*aBox, aBrcs, &aSizeArray[0], nBorder);
5190 tools::Rectangle aInnerDist;
5191 GetBorderDistance( aBrcs, aInnerDist );
5193 if (nBorder & (1 << WW8_LEFT))
5194 aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Left()), SvxBoxItemLine::LEFT );
5196 if (nBorder & (1 << WW8_TOP))
5197 aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Top()), SvxBoxItemLine::TOP );
5199 if (nBorder & (1 << WW8_RIGHT))
5200 aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Right()), SvxBoxItemLine::RIGHT );
5202 if (nBorder & (1 << WW8_BOT))
5203 aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Bottom()), SvxBoxItemLine::BOTTOM );
5205 NewAttr( *aBox );
5207 SvxShadowItem aS(RES_SHADOW);
5208 // Word only allows shadows on visible borders
5209 if ( aBox->CalcLineSpace( SvxBoxItemLine::RIGHT ) )
5210 SetShadow( aS, &aSizeArray[0], aBrcs[WW8_RIGHT] );
5211 NewAttr( aS );
5217 void SwWW8ImplReader::Read_CharBorder(sal_uInt16 nId, const sal_uInt8* pData, short nLen )
5219 //Ignore this old border type
5220 //if (!bVer67 && pPlcxMan && pPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CBrc::val))
5221 // return;
5223 if (nLen < 0)
5225 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BOX );
5226 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SHADOW );
5228 else
5230 const SvxBoxItem* pBox
5231 = static_cast<const SvxBoxItem*>(GetFormatAttr( RES_CHRATR_BOX ));
5232 if( pBox )
5234 std::unique_ptr<SvxBoxItem> aBoxItem(pBox->Clone());
5235 WW8_BRCVer9 aBrc;
5236 int nBrcVer = (nId == NS_sprm::CBrc::val) ? 9 : (m_bVer67 ? 6 : 8);
5238 SetWW8_BRC(nBrcVer, aBrc, pData, nLen);
5240 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::TOP, 0, nullptr, true);
5241 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::BOTTOM, 0, nullptr, true);
5242 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::LEFT, 0, nullptr, true);
5243 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::RIGHT, 0, nullptr, true);
5244 NewAttr( *aBoxItem );
5246 short aSizeArray[WW8_RIGHT+1]={0}; aSizeArray[WW8_RIGHT] = 1;
5247 SvxShadowItem aShadowItem(RES_CHRATR_SHADOW);
5248 // Word only allows shadows on visible borders
5249 if ( aBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) )
5250 SetShadow( aShadowItem, &aSizeArray[0], aBrc );
5251 NewAttr( aShadowItem );
5256 void SwWW8ImplReader::Read_Hyphenation( sal_uInt16, const sal_uInt8* pData, short nLen )
5258 // set Hyphenation flag
5259 if (nLen < 1)
5260 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_HYPHENZONE );
5261 else
5263 SvxHyphenZoneItem aAttr(
5264 *static_cast<const SvxHyphenZoneItem*>(GetFormatAttr( RES_PARATR_HYPHENZONE ) ));
5266 aAttr.SetHyphen( 0 == *pData ); // sic !
5268 if( !*pData )
5270 aAttr.GetMinLead() = 2;
5271 aAttr.GetMinTrail() = 2;
5272 aAttr.GetMaxHyphens() = 0;
5275 NewAttr( aAttr );
5279 void SwWW8ImplReader::Read_WidowControl( sal_uInt16, const sal_uInt8* pData, short nLen )
5281 if (nLen < 1)
5283 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_WIDOWS );
5284 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ORPHANS );
5286 else
5288 sal_uInt8 nL = ( *pData & 1 ) ? 2 : 0;
5290 NewAttr( SvxWidowsItem( nL, RES_PARATR_WIDOWS ) ); // Off -> nLines = 0
5291 NewAttr( SvxOrphansItem( nL, RES_PARATR_ORPHANS ) );
5293 if( m_pCurrentColl && m_xStyles ) // Style-Def ?
5294 m_xStyles->mbWidowsChanged = true; // save for simulation
5295 // Default-Widows
5299 void SwWW8ImplReader::Read_UsePgsuSettings(sal_uInt16,const sal_uInt8* pData,short nLen)
5301 if (nLen < 1)
5302 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_SNAPTOGRID);
5303 else
5305 if(m_nInTable)
5306 NewAttr( SvxParaGridItem(false, RES_PARATR_SNAPTOGRID) );
5307 else
5308 NewAttr( SvxParaGridItem(*pData, RES_PARATR_SNAPTOGRID) );
5312 void SwWW8ImplReader::Read_AlignFont( sal_uInt16, const sal_uInt8* pData, short nLen )
5314 if (nLen < 2)
5315 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_VERTALIGN);
5316 else
5318 sal_uInt16 nVal = SVBT16ToUInt16( pData );
5319 SvxParaVertAlignItem::Align nAlign;
5320 switch (nVal)
5322 case 0:
5323 nAlign = SvxParaVertAlignItem::Align::Top;
5324 break;
5325 case 1:
5326 nAlign = SvxParaVertAlignItem::Align::Center;
5327 break;
5328 case 2:
5329 nAlign = SvxParaVertAlignItem::Align::Baseline;
5330 break;
5331 case 3:
5332 nAlign = SvxParaVertAlignItem::Align::Bottom;
5333 break;
5334 case 4:
5335 nAlign = SvxParaVertAlignItem::Align::Automatic;
5336 break;
5337 default:
5338 nAlign = SvxParaVertAlignItem::Align::Automatic;
5339 OSL_ENSURE(false,"Unknown paragraph vertical align");
5340 break;
5342 NewAttr( SvxParaVertAlignItem( nAlign, RES_PARATR_VERTALIGN ) );
5346 void SwWW8ImplReader::Read_KeepLines( sal_uInt16, const sal_uInt8* pData, short nLen )
5348 if (nLen < 1)
5349 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_SPLIT );
5350 else
5351 NewAttr( SvxFormatSplitItem( ( *pData & 1 ) == 0, RES_PARATR_SPLIT ) );
5354 void SwWW8ImplReader::Read_KeepParas( sal_uInt16, const sal_uInt8* pData, short nLen )
5356 if (nLen < 1)
5357 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_KEEP );
5358 else
5359 NewAttr( SvxFormatKeepItem( ( *pData & 1 ) != 0 , RES_KEEP) );
5362 void SwWW8ImplReader::Read_BreakBefore( sal_uInt16, const sal_uInt8* pData, short nLen )
5364 if (nLen < 1)
5365 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BREAK );
5366 else
5367 NewAttr( SvxFormatBreakItem(
5368 ( *pData & 1 ) ? SvxBreak::PageBefore : SvxBreak::NONE, RES_BREAK ) );
5371 void SwWW8ImplReader::Read_ApoPPC( sal_uInt16, const sal_uInt8* pData, short )
5373 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // only for Styledef, otherwise solved differently
5375 SwWW8StyInf& rSI = m_vColl[m_nCurrentColl];
5376 if (!rSI.m_xWWFly)
5377 rSI.m_xWWFly = std::make_shared<WW8FlyPara>(m_bVer67);
5378 rSI.m_xWWFly->Read(*pData, m_xStyles.get());
5379 if (rSI.m_xWWFly->IsEmpty())
5381 m_vColl[m_nCurrentColl].m_xWWFly.reset();
5386 bool SwWW8ImplReader::ParseTabPos(WW8_TablePos *pTabPos, WW8PLCFx_Cp_FKP* pPap)
5388 bool bRet = false;
5389 memset(pTabPos, 0, sizeof(WW8_TablePos));
5390 // sprmTPc contains a PositionCodeOperand structure that specifies the origin
5391 // that is used to calculate the table position when it is absolutely positioned
5392 SprmResult aRes = pPap->HasSprm(NS_sprm::TPc::val);
5393 if (aRes.pSprm && aRes.nRemainingData >= 1)
5395 pTabPos->nTPc = *aRes.pSprm;
5396 pTabPos->nPWr = 2; //Possible fail area, always parallel wrap
5397 aRes = pPap->HasSprm(NS_sprm::TDxaAbs::val);
5398 if (aRes.pSprm && aRes.nRemainingData >= 2)
5399 pTabPos->nTDxaAbs = SVBT16ToUInt16(aRes.pSprm);
5400 aRes = pPap->HasSprm(NS_sprm::TDyaAbs::val);
5401 if (aRes.pSprm && aRes.nRemainingData >= 2)
5402 pTabPos->nTDyaAbs = SVBT16ToUInt16(aRes.pSprm);
5403 aRes = pPap->HasSprm(NS_sprm::TDxaFromText::val);
5404 if (aRes.pSprm && aRes.nRemainingData >= 2)
5405 pTabPos->nLeftMargin = SVBT16ToUInt16(aRes.pSprm);
5406 aRes = pPap->HasSprm(NS_sprm::TDxaFromTextRight::val);
5407 if (aRes.pSprm && aRes.nRemainingData >= 2)
5408 pTabPos->nRightMargin = SVBT16ToUInt16(aRes.pSprm);
5409 aRes = pPap->HasSprm(NS_sprm::TDyaFromText::val);
5410 if (aRes.pSprm && aRes.nRemainingData >= 2)
5411 pTabPos->nUpperMargin = SVBT16ToUInt16(aRes.pSprm);
5412 aRes = pPap->HasSprm(NS_sprm::TDyaFromTextBottom::val);
5413 if (aRes.pSprm && aRes.nRemainingData >= 2)
5414 pTabPos->nLowerMargin = SVBT16ToUInt16(aRes.pSprm);
5416 aRes = pPap->HasSprm(NS_sprm::TFNoAllowOverlap::val);
5417 if (aRes.pSprm)
5419 // Remember the no-overlap request, to be consumed in SwWW8ImplReader::StartApo().
5420 pTabPos->nTFNoAllowOverlap = *aRes.pSprm;
5423 bRet = true;
5425 return bRet;
5428 // page attribute won't be used as attribute anymore
5429 // ( except OLST )
5430 tools::Long SwWW8ImplReader::ImportExtSprm(WW8PLCFManResult* pRes)
5432 // array for reading of the extended ( self-defined ) SPRMs
5433 typedef tools::Long (SwWW8ImplReader::*FNReadRecordExt)(WW8PLCFManResult*);
5435 static const FNReadRecordExt aWwSprmTab[] =
5437 /* 0 (256) */ &SwWW8ImplReader::Read_Footnote, // FootNote
5438 /* 1 (257) */ &SwWW8ImplReader::Read_Footnote, // EndNote
5439 /* 2 (258) */ &SwWW8ImplReader::Read_Field, // Field
5440 /* 3 (259) */ &SwWW8ImplReader::Read_Book, // Bookmark
5441 /* 4 (260) */ &SwWW8ImplReader::Read_And, // Annotation
5442 /* 5 (261) */ &SwWW8ImplReader::Read_AtnBook, // Annotationmark
5443 /* 6 (262) */ &SwWW8ImplReader::Read_FactoidBook // Smart tag bookmark
5446 if( pRes->nSprmId < 280 )
5448 sal_uInt8 nIdx = static_cast< sal_uInt8 >(pRes->nSprmId - eFTN);
5449 if( nIdx < SAL_N_ELEMENTS(aWwSprmTab)
5450 && aWwSprmTab[nIdx] )
5451 return (this->*aWwSprmTab[nIdx])(pRes);
5452 else
5453 return 0;
5455 else
5456 return 0;
5459 void SwWW8ImplReader::EndExtSprm(sal_uInt16 nSprmId)
5461 typedef sal_uInt16 (SwWW8ImplReader::*FNReadRecordExt)();
5463 static const FNReadRecordExt aWwSprmTab[] =
5465 /* 0 (256) */ &SwWW8ImplReader::End_Footnote, // FootNote
5466 /* 1 (257) */ &SwWW8ImplReader::End_Footnote, // EndNote
5467 /* 2 (258) */ &SwWW8ImplReader::End_Field, // Field
5468 /* 3 (259) */ nullptr, // Bookmark
5469 /* 4 (260) */ nullptr // Annotation
5472 sal_uInt8 nIdx = static_cast< sal_uInt8 >(nSprmId - eFTN);
5473 if( nIdx < SAL_N_ELEMENTS(aWwSprmTab)
5474 && aWwSprmTab[nIdx] )
5475 (this->*aWwSprmTab[nIdx])();
5478 // arrays for reading the SPRMs
5480 // function for reading of SPRMs. Par1: SprmId
5481 typedef void (SwWW8ImplReader::*FNReadRecord)( sal_uInt16, const sal_uInt8*, short );
5483 struct SprmReadInfo
5485 sal_uInt16 nId;
5486 FNReadRecord pReadFnc;
5489 static bool operator<(const SprmReadInfo &rFirst, const SprmReadInfo &rSecond)
5491 return (rFirst.nId < rSecond.nId);
5494 typedef ww::SortedArray<SprmReadInfo> wwSprmDispatcher;
5496 static const wwSprmDispatcher *GetWW2SprmDispatcher()
5498 static SprmReadInfo aSprms[] =
5500 {0, nullptr}, // "0" default resp. error
5501 // will be skipped! ,
5502 {2, &SwWW8ImplReader::Read_StyleCode}, //"sprmPIstd", pap.istd
5503 //(style code)
5504 {3, nullptr}, //"sprmPIstdPermute", pap.istd
5505 //permutation
5506 {4, nullptr}, //"sprmPIncLv1",
5507 //pap.istddifference
5508 {5, &SwWW8ImplReader::Read_Justify}, //"sprmPJc", pap.jc
5509 //(justification)
5510 {6, nullptr}, //"sprmPFSideBySide",
5511 //pap.fSideBySide
5512 {7, &SwWW8ImplReader::Read_KeepLines}, //"sprmPFKeep", pap.fKeep
5513 {8, &SwWW8ImplReader::Read_KeepParas}, //"sprmPFKeepFollow ",
5514 //pap.fKeepFollow
5515 {9, &SwWW8ImplReader::Read_BreakBefore}, //"sprmPPageBreakBefore",
5516 //pap.fPageBreakBefore
5517 {10, nullptr}, //"sprmPBrcl", pap.brcl
5518 {11, nullptr}, //"sprmPBrcp ", pap.brcp
5519 {12, &SwWW8ImplReader::Read_ANLevelDesc}, //"sprmPAnld", pap.anld (ANLD
5520 //structure)
5521 {13, &SwWW8ImplReader::Read_ANLevelNo}, //"sprmPNLvlAnm", pap.nLvlAnm
5522 //nn
5523 {14, &SwWW8ImplReader::Read_NoLineNumb}, //"sprmPFNoLineNumb", ap.fNoLnn
5524 {15, &SwWW8ImplReader::Read_Tab}, //"?sprmPChgTabsPapx",
5525 //pap.itbdMac, ...
5526 {16, &SwWW8ImplReader::Read_LR}, //"sprmPDxaRight", pap.dxaRight
5527 {17, &SwWW8ImplReader::Read_LR}, //"sprmPDxaLeft", pap.dxaLeft
5528 {18, nullptr}, //"sprmPNest", pap.dxaLeft
5529 {19, &SwWW8ImplReader::Read_LR}, //"sprmPDxaLeft1", pap.dxaLeft1
5530 {20, &SwWW8ImplReader::Read_LineSpace}, //"sprmPDyaLine", pap.lspd
5531 //an LSPD
5532 {21, &SwWW8ImplReader::Read_UL}, //"sprmPDyaBefore",
5533 //pap.dyaBefore
5534 {22, &SwWW8ImplReader::Read_UL}, //"sprmPDyaAfter", pap.dyaAfter
5535 {23, nullptr}, //"?sprmPChgTabs", pap.itbdMac,
5536 //pap.rgdxaTab, ...
5537 {24, nullptr}, //"sprmPFInTable", pap.fInTable
5538 {25, &SwWW8ImplReader::Read_TabRowEnd}, //"sprmPTtp", pap.fTtp
5539 {26, nullptr}, //"sprmPDxaAbs", pap.dxaAbs
5540 {27, nullptr}, //"sprmPDyaAbs", pap.dyaAbs
5541 {28, nullptr}, //"sprmPDxaWidth", pap.dxaWidth
5542 {29, &SwWW8ImplReader::Read_ApoPPC}, //"sprmPPc", pap.pcHorz,
5543 //pap.pcVert
5544 {30, nullptr}, //"sprmPBrcTop10", pap.brcTop
5545 //BRC10
5546 {31, nullptr}, //"sprmPBrcLeft10",
5547 //pap.brcLeft BRC10
5548 {32, nullptr}, //"sprmPBrcBottom10",
5549 //pap.brcBottom BRC10
5550 {33, nullptr}, //"sprmPBrcRight10",
5551 //pap.brcRight BRC10
5552 {34, nullptr}, //"sprmPBrcBetween10",
5553 //pap.brcBetween BRC10
5554 {35, nullptr}, //"sprmPBrcBar10", pap.brcBar
5555 //BRC10
5556 {36, nullptr}, //"sprmPFromText10",
5557 //pap.dxaFromText dxa
5558 {37, nullptr}, //"sprmPWr", pap.wr wr
5559 {38, &SwWW8ImplReader::Read_Border}, //"sprmPBrcTop", pap.brcTop BRC
5560 {39, &SwWW8ImplReader::Read_Border}, //"sprmPBrcLeft",
5561 //pap.brcLeft BRC
5562 {40, &SwWW8ImplReader::Read_Border}, //"sprmPBrcBottom",
5563 //pap.brcBottom BRC
5564 {41, &SwWW8ImplReader::Read_Border}, //"sprmPBrcRight",
5565 //pap.brcRight BRC
5566 {42, &SwWW8ImplReader::Read_Border}, //"sprmPBrcBetween",
5567 //pap.brcBetween BRC
5568 {43, nullptr}, //"sprmPBrcBar", pap.brcBar
5569 //BRC word
5570 {44, &SwWW8ImplReader::Read_Hyphenation}, //"sprmPFNoAutoHyph",
5571 //pap.fNoAutoHyph
5572 {45, nullptr}, //"sprmPWHeightAbs",
5573 //pap.wHeightAbs w
5574 {46, nullptr}, //"sprmPDcs", pap.dcs DCS
5575 {47, &SwWW8ImplReader::Read_Shade}, //"sprmPShd", pap.shd SHD
5576 {48, nullptr}, //"sprmPDyaFromText",
5577 //pap.dyaFromText dya
5578 {49, nullptr}, //"sprmPDxaFromText",
5579 //pap.dxaFromText dxa
5580 {50, nullptr}, //"sprmPFLocked", pap.fLocked
5581 //0 or 1 byte
5582 {51, &SwWW8ImplReader::Read_WidowControl}, //"sprmPFWidowControl",
5583 //pap.fWidowControl 0 or 1 byte
5584 {52, nullptr}, //"?sprmPRuler 52",
5585 {53, nullptr}, //"??53",
5586 {54, nullptr}, //"??54",
5587 {55, nullptr}, //"??55",
5588 {56, nullptr}, //"??56",
5589 {57, nullptr}, //"??57",
5590 {58, nullptr}, //"??58",
5591 {59, nullptr}, //"??59",
5593 {60, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFBold", chp.fBold 0,1,
5594 //128, or 129 byte
5595 {61, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFItalic", chp.fItalic
5596 //0,1, 128, or 129 byte
5597 {62, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFStrike", chp.fStrike
5598 //0,1, 128, or 129 byte
5599 {63, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFOutline", chp.fOutline
5600 //0,1, 128, or 129 byte
5601 {64, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFShadow", chp.fShadow
5602 //0,1, 128, or 129 byte
5603 {65, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFSmallCaps",
5604 //chp.fSmallCaps 0,1, 128, or
5605 //129 byte
5606 {66, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFCaps", chp.fCaps 0,1,
5607 //128, or 129 byte
5608 {67, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFVanish", chp.fVanish
5609 //0,1, 128, or 129 byte
5610 {68, &SwWW8ImplReader::Read_FontCode}, //"sprmCFtc", chp.ftc ftc word
5611 {69, &SwWW8ImplReader::Read_Underline}, // "sprmCKul", chp.kul kul byte
5612 {70, nullptr}, //"sprmCSizePos", chp.hps,
5613 //chp.hpsPos 3 bytes
5614 {71, &SwWW8ImplReader::Read_Kern}, //"sprmCDxaSpace",
5615 //chp.dxaSpace dxa word
5616 {72, &SwWW8ImplReader::Read_Language}, //"sprmCLid", chp.lid LID word
5617 {73, &SwWW8ImplReader::Read_TextColor}, //"sprmCIco", chp.ico ico byte
5618 {74, &SwWW8ImplReader::Read_FontSize}, //"sprmCHps", chp.hps hps word!
5619 {75, nullptr}, //"sprmCHpsInc", chp.hps byte
5620 {76, &SwWW8ImplReader::Read_SubSuperProp}, //"sprmCHpsPos", chp.hpsPos
5621 //hps byte
5622 {77, nullptr}, //"sprmCHpsPosAdj", chp.hpsPos
5623 //hps byte
5624 {78, &SwWW8ImplReader::Read_Majority}, //"?sprmCMajority", chp.fBold,
5625 //chp.fItalic, chp.fSmallCaps
5626 {80, &SwWW8ImplReader::Read_BoldBiDiUsw}, //sprmCFBoldBi
5627 {81, &SwWW8ImplReader::Read_BoldBiDiUsw}, //sprmCFItalicBi
5628 {82, &SwWW8ImplReader::Read_FontCode}, //sprmCFtcBi
5629 {83, &SwWW8ImplReader::Read_Language}, //sprmClidBi
5630 {84, &SwWW8ImplReader::Read_TextColor}, //sprmCIcoBi
5631 {85, &SwWW8ImplReader::Read_FontSize}, //sprmCHpsBi
5632 {86, nullptr}, //sprmCFBiDi
5633 {87, nullptr}, //sprmCFDiacColor
5634 {94, nullptr}, //"sprmPicBrcl", pic.brcl brcl
5635 //(see PIC structure
5636 //definition) byte
5637 {95, nullptr}, //"sprmPicScale", pic.mx,
5638 //pic.my, pic.dxaCropleft,
5639 {96, nullptr}, //"sprmPicBrcTop", pic.brcTop
5640 //BRC word
5641 {97, nullptr}, //"sprmPicBrcLeft",
5642 //pic.brcLeft BRC word
5643 {98, nullptr}, //"sprmPicBrcBottom",
5644 //pic.brcBottom BRC word
5645 {99, nullptr} //"sprmPicBrcRight",
5648 static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
5649 return &aSprmSrch;
5652 static const wwSprmDispatcher *GetWW6SprmDispatcher()
5654 static SprmReadInfo aSprms[] =
5656 {0, nullptr}, // "0" default resp. error
5657 // will be skipped!
5658 {NS_sprm::v6::sprmPIstd, &SwWW8ImplReader::Read_StyleCode}, // pap.istd (style code)
5659 {NS_sprm::v6::sprmPIstdPermute, nullptr}, // pap.istd permutation
5660 {NS_sprm::v6::sprmPIncLv1, nullptr}, // pap.istddifference
5661 {NS_sprm::v6::sprmPJc, &SwWW8ImplReader::Read_Justify}, // pap.jc (justification)
5662 {NS_sprm::v6::sprmPFSideBySide, nullptr}, // pap.fSideBySide
5663 {NS_sprm::v6::sprmPFKeep, &SwWW8ImplReader::Read_KeepLines}, // pap.fKeep
5664 {NS_sprm::v6::sprmPFKeepFollow, &SwWW8ImplReader::Read_KeepParas}, // pap.fKeepFollow
5665 {NS_sprm::v6::sprmPPageBreakBefore, &SwWW8ImplReader::Read_BreakBefore}, // pap.fPageBreakBefore
5666 {NS_sprm::v6::sprmPBrcl, nullptr}, // pap.brcl
5667 {NS_sprm::v6::sprmPBrcp, nullptr}, // pap.brcp
5668 {NS_sprm::v6::sprmPAnld, &SwWW8ImplReader::Read_ANLevelDesc}, // pap.anld (ANLD structure)
5669 {NS_sprm::v6::sprmPNLvlAnm, &SwWW8ImplReader::Read_ANLevelNo}, // pap.nLvlAnm nn
5670 {NS_sprm::v6::sprmPFNoLineNumb, &SwWW8ImplReader::Read_NoLineNumb}, // ap.fNoLnn
5671 {NS_sprm::v6::sprmPChgTabsPapx, &SwWW8ImplReader::Read_Tab}, // pap.itbdMac, ...
5672 {NS_sprm::v6::sprmPDxaRight, &SwWW8ImplReader::Read_LR}, // pap.dxaRight
5673 {NS_sprm::v6::sprmPDxaLeft, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft
5674 {NS_sprm::v6::sprmPNest, nullptr}, // pap.dxaLeft
5675 {NS_sprm::v6::sprmPDxaLeft1, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft1
5676 {NS_sprm::v6::sprmPDyaLine, &SwWW8ImplReader::Read_LineSpace}, // pap.lspd an LSPD
5677 {NS_sprm::v6::sprmPDyaBefore, &SwWW8ImplReader::Read_UL}, // pap.dyaBefore
5678 {NS_sprm::v6::sprmPDyaAfter, &SwWW8ImplReader::Read_UL}, // pap.dyaAfter
5679 {NS_sprm::v6::sprmPChgTabs, nullptr}, // pap.itbdMac, pap.rgdxaTab, ...
5680 {NS_sprm::v6::sprmPFInTable, nullptr}, // pap.fInTable
5681 {NS_sprm::v6::sprmPTtp, &SwWW8ImplReader::Read_TabRowEnd}, // pap.fTtp
5682 {NS_sprm::v6::sprmPDxaAbs, nullptr}, // pap.dxaAbs
5683 {NS_sprm::v6::sprmPDyaAbs, nullptr}, // pap.dyaAbs
5684 {NS_sprm::v6::sprmPDxaWidth, nullptr}, // pap.dxaWidth
5685 {NS_sprm::v6::sprmPPc, &SwWW8ImplReader::Read_ApoPPC}, // pap.pcHorz, pap.pcVert
5686 {NS_sprm::v6::sprmPBrcTop10, nullptr}, // pap.brcTop BRC10
5687 {NS_sprm::v6::sprmPBrcLeft10, nullptr}, // pap.brcLeft BRC10
5688 {NS_sprm::v6::sprmPBrcBottom10, nullptr}, // pap.brcBottom BRC10
5689 {NS_sprm::v6::sprmPBrcRight10, nullptr}, // pap.brcRight BRC10
5690 {NS_sprm::v6::sprmPBrcBetween10, nullptr}, // pap.brcBetween BRC10
5691 {NS_sprm::v6::sprmPBrcBar10, nullptr}, // pap.brcBar BRC10
5692 {NS_sprm::v6::sprmPFromText10, nullptr}, // pap.dxaFromText dxa
5693 {NS_sprm::v6::sprmPWr, nullptr}, // pap.wr wr
5694 {NS_sprm::v6::sprmPBrcTop, &SwWW8ImplReader::Read_Border}, // pap.brcTop BRC
5695 {NS_sprm::v6::sprmPBrcLeft, &SwWW8ImplReader::Read_Border}, // pap.brcLeft BRC
5696 {NS_sprm::v6::sprmPBrcBottom, &SwWW8ImplReader::Read_Border}, // pap.brcBottom BRC
5697 {NS_sprm::v6::sprmPBrcRight, &SwWW8ImplReader::Read_Border}, // pap.brcRight BRC
5698 {NS_sprm::v6::sprmPBrcBetween, &SwWW8ImplReader::Read_Border}, // pap.brcBetween BRC
5699 {NS_sprm::v6::sprmPBrcBar, nullptr}, // pap.brcBar BRC word
5700 {NS_sprm::v6::sprmPFNoAutoHyph, &SwWW8ImplReader::Read_Hyphenation}, // pap.fNoAutoHyph
5701 {NS_sprm::v6::sprmPWHeightAbs, nullptr}, // pap.wHeightAbs w
5702 {NS_sprm::v6::sprmPDcs, nullptr}, // pap.dcs DCS
5703 {NS_sprm::v6::sprmPShd, &SwWW8ImplReader::Read_Shade}, // pap.shd SHD
5704 {NS_sprm::v6::sprmPDyaFromText, nullptr}, // pap.dyaFromText dya
5705 {NS_sprm::v6::sprmPDxaFromText, nullptr}, // pap.dxaFromText dxa
5706 {NS_sprm::v6::sprmPFLocked, nullptr}, // pap.fLocked 0 or 1 byte
5707 {NS_sprm::v6::sprmPFWidowControl, &SwWW8ImplReader::Read_WidowControl}, // pap.fWidowControl 0 or 1 byte
5708 {NS_sprm::v6::sprmPRuler, nullptr},
5709 {53, nullptr}, //"??53",
5710 {54, nullptr}, //"??54",
5711 {55, nullptr}, //"??55",
5712 {56, nullptr}, //"??56",
5713 {57, nullptr}, //"??57",
5714 {58, nullptr}, //"??58",
5715 {59, nullptr}, //"??59",
5716 {60, nullptr}, //"??60",
5717 {61, nullptr}, //"??61",
5718 {62, nullptr}, //"??62",
5719 {63, nullptr}, //"??63",
5720 {64, &SwWW8ImplReader::Read_ParaBiDi}, //"rtl bidi ?
5721 {NS_sprm::v6::sprmCFStrikeRM, &SwWW8ImplReader::Read_CFRMarkDel}, // chp.fRMarkDel 1 or 0 bit
5722 {NS_sprm::v6::sprmCFRMark, &SwWW8ImplReader::Read_CFRMark}, // chp.fRMark 1 or 0 bit
5723 {NS_sprm::v6::sprmCFFldVanish, &SwWW8ImplReader::Read_FieldVanish}, // chp.fFieldVanish 1 or 0 bit
5724 {NS_sprm::v6::sprmCPicLocation, &SwWW8ImplReader::Read_PicLoc}, // chp.fcPic and chp.fSpec
5725 {NS_sprm::v6::sprmCIbstRMark, nullptr}, // chp.ibstRMark index into sttbRMark
5726 {NS_sprm::v6::sprmCDttmRMark, nullptr}, // chp.dttm DTTM long
5727 {NS_sprm::v6::sprmCFData, nullptr}, // chp.fData 1 or 0 bit
5728 {NS_sprm::v6::sprmCRMReason, nullptr}, // chp.idslRMReason an index to a table
5729 {NS_sprm::v6::sprmCChse, &SwWW8ImplReader::Read_CharSet}, // chp.fChsDiff and chp.chse 3 bytes
5730 {NS_sprm::v6::sprmCSymbol, &SwWW8ImplReader::Read_Symbol}, // chp.fSpec, chp.chSym and chp.ftcSym
5731 {NS_sprm::v6::sprmCFOle2, &SwWW8ImplReader::Read_Obj}, // chp.fOle2 1 or 0 bit
5732 {76, nullptr}, //"??76",
5733 {77, nullptr}, //"??77",
5734 {78, nullptr}, //"??78",
5735 {79, nullptr}, //"??79",
5736 {NS_sprm::v6::sprmCIstd, &SwWW8ImplReader::Read_CColl}, // chp.istd istd, see stylesheet definition; short
5737 {NS_sprm::v6::sprmCIstdPermute, nullptr}, // chp.istd permutation vector
5738 {NS_sprm::v6::sprmCDefault, nullptr}, // whole CHP none variable length
5739 {NS_sprm::v6::sprmCPlain, nullptr}, // whole CHP none 0
5740 {84, nullptr}, //"??84",
5741 {NS_sprm::v6::sprmCFBold, &SwWW8ImplReader::Read_BoldUsw}, // chp.fBold 0,1, 128, or 129 byte
5742 {NS_sprm::v6::sprmCFItalic, &SwWW8ImplReader::Read_BoldUsw}, // chp.fItalic 0,1, 128, or 129 byte
5743 {NS_sprm::v6::sprmCFStrike, &SwWW8ImplReader::Read_BoldUsw}, // chp.fStrike 0,1, 128, or 129 byte
5744 {NS_sprm::v6::sprmCFOutline, &SwWW8ImplReader::Read_BoldUsw}, // chp.fOutline 0,1, 128, or 129 byte
5745 {NS_sprm::v6::sprmCFShadow, &SwWW8ImplReader::Read_BoldUsw}, // chp.fShadow 0,1, 128, or 129 byte
5746 {NS_sprm::v6::sprmCFSmallCaps, &SwWW8ImplReader::Read_BoldUsw}, // chp.fSmallCaps 0,1, 128, or 129 byte
5747 {NS_sprm::v6::sprmCFCaps, &SwWW8ImplReader::Read_BoldUsw}, // chp.fCaps 0,1, 128, or 129 byte
5748 {NS_sprm::v6::sprmCFVanish, &SwWW8ImplReader::Read_BoldUsw}, // chp.fVanish 0,1, 128, or 129 byte
5749 {NS_sprm::v6::sprmCFtc, &SwWW8ImplReader::Read_FontCode}, // chp.ftc ftc word
5750 {NS_sprm::v6::sprmCKul, &SwWW8ImplReader::Read_Underline}, // chp.kul kul byte
5751 {NS_sprm::v6::sprmCSizePos, nullptr}, // chp.hps, chp.hpsPos 3 bytes
5752 {NS_sprm::v6::sprmCDxaSpace, &SwWW8ImplReader::Read_Kern}, // chp.dxaSpace dxa word
5753 {NS_sprm::v6::sprmCLid, &SwWW8ImplReader::Read_Language}, // chp.lid LID word
5754 {NS_sprm::v6::sprmCIco, &SwWW8ImplReader::Read_TextColor}, // chp.ico ico byte
5755 {NS_sprm::v6::sprmCHps, &SwWW8ImplReader::Read_FontSize}, // chp.hps hps word!
5756 {NS_sprm::v6::sprmCHpsInc, nullptr}, // chp.hps byte
5757 {NS_sprm::v6::sprmCHpsPos, &SwWW8ImplReader::Read_SubSuperProp}, // chp.hpsPos hps byte
5758 {NS_sprm::v6::sprmCHpsPosAdj, nullptr}, // chp.hpsPos hps byte
5759 {NS_sprm::v6::sprmCMajority, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fSmallCaps
5760 {NS_sprm::v6::sprmCIss, &SwWW8ImplReader::Read_SubSuper}, // chp.iss iss byte
5761 {NS_sprm::v6::sprmCHpsNew50, nullptr}, // chp.hps hps variable width, length always recorded as 2
5762 {NS_sprm::v6::sprmCHpsInc1, nullptr}, // chp.hps complex variable width, length always recorded as 2
5763 {NS_sprm::v6::sprmCHpsKern, &SwWW8ImplReader::Read_FontKern}, // chp.hpsKern hps short
5764 {NS_sprm::v6::sprmCMajority50, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fSmallCaps, chp.fVanish, ...
5765 {NS_sprm::v6::sprmCHpsMul, nullptr}, // chp.hps percentage to grow hps short
5766 {NS_sprm::v6::sprmCCondHyhen, nullptr}, // chp.ysri ysri short
5767 {111, &SwWW8ImplReader::Read_AmbiguousSPRM},//sprmCFBoldBi or font code
5768 {112, &SwWW8ImplReader::Read_AmbiguousSPRM},//sprmCFItalicBi or font code
5769 {113, &SwWW8ImplReader::Read_FontCode}, //sprmCFtcBi
5770 {114, &SwWW8ImplReader::Read_Language}, //sprmClidBi
5771 {115, &SwWW8ImplReader::Read_TextColor}, //sprmCIcoBi
5772 {116, &SwWW8ImplReader::Read_FontSize}, //sprmCHpsBi
5773 {NS_sprm::v6::sprmCFSpec, &SwWW8ImplReader::Read_Special}, // chp.fSpec 1 or 0 bit
5774 {NS_sprm::v6::sprmCFObj, &SwWW8ImplReader::Read_Obj}, // chp.fObj 1 or 0 bit
5775 {NS_sprm::v6::sprmPicBrcl, nullptr}, // pic.brcl brcl (see PIC structure definition) byte
5776 {NS_sprm::v6::sprmPicScale, nullptr}, // pic.mx, pic.my, pic.dxaCropleft,
5777 {NS_sprm::v6::sprmPicBrcTop, nullptr}, // pic.brcTop BRC word
5778 {NS_sprm::v6::sprmPicBrcLeft, nullptr}, // pic.brcLeft BRC word
5779 {NS_sprm::v6::sprmPicBrcBottom, nullptr}, // pic.brcBottom BRC word
5780 {NS_sprm::v6::sprmPicBrcRight, nullptr}, // pic.brcRight BRC word
5781 {125, nullptr}, //"??125",
5782 {126, nullptr}, //"??126",
5783 {127, nullptr}, //"??127",
5784 {128, nullptr}, //"??128",
5785 {129, nullptr}, //"??129",
5786 {130, nullptr}, //"??130",
5787 {NS_sprm::v6::sprmSScnsPgn, nullptr}, // sep.cnsPgn cns byte
5788 {NS_sprm::v6::sprmSiHeadingPgn, nullptr}, // sep.iHeadingPgn heading number level byte
5789 {NS_sprm::v6::sprmSOlstAnm, &SwWW8ImplReader::Read_OLST}, // sep.olstAnm OLST variable length
5790 {134, nullptr}, //"??135",
5791 {135, nullptr}, //"??135",
5792 {NS_sprm::v6::sprmSDxaColWidth, nullptr}, // sep.rgdxaColWidthSpacing complex 3 bytes
5793 {NS_sprm::v6::sprmSDxaColSpacing, nullptr}, // sep.rgdxaColWidthSpacing complex 3 bytes
5794 {NS_sprm::v6::sprmSFEvenlySpaced, nullptr}, // sep.fEvenlySpaced 1 or 0 byte
5795 {NS_sprm::v6::sprmSFProtected, nullptr}, // sep.fUnlocked 1 or 0 byte
5796 {NS_sprm::v6::sprmSDmBinFirst, nullptr}, // sep.dmBinFirst word
5797 {NS_sprm::v6::sprmSDmBinOther, nullptr}, // sep.dmBinOther word
5798 {NS_sprm::v6::sprmSBkc, nullptr}, // sep.bkc bkc byte BreakCode
5799 {NS_sprm::v6::sprmSFTitlePage, nullptr}, // sep.fTitlePage 0 or 1 byte
5800 {NS_sprm::v6::sprmSCcolumns, nullptr}, // sep.ccolM1 # of cols - 1 word
5801 {NS_sprm::v6::sprmSDxaColumns, nullptr}, // sep.dxaColumns dxa word
5802 {NS_sprm::v6::sprmSFAutoPgn, nullptr}, // sep.fAutoPgn obsolete byte
5803 {NS_sprm::v6::sprmSNfcPgn, nullptr}, // sep.nfcPgn nfc byte
5804 {NS_sprm::v6::sprmSDyaPgn, nullptr}, // sep.dyaPgn dya short
5805 {NS_sprm::v6::sprmSDxaPgn, nullptr}, // sep.dxaPgn dya short
5806 {NS_sprm::v6::sprmSFPgnRestart, nullptr}, // sep.fPgnRestart 0 or 1 byte
5807 {NS_sprm::v6::sprmSFEndnote, nullptr}, // sep.fEndnote 0 or 1 byte
5808 {NS_sprm::v6::sprmSLnc, nullptr}, // sep.lnc lnc byte
5809 {NS_sprm::v6::sprmSGprfIhdt, nullptr}, // sep.grpfIhdt grpfihdt byte
5810 {NS_sprm::v6::sprmSNLnnMod, nullptr}, // sep.nLnnMod non-neg int. word
5811 {NS_sprm::v6::sprmSDxaLnn, nullptr}, // sep.dxaLnn dxa word
5812 {NS_sprm::v6::sprmSDyaHdrTop, nullptr}, // sep.dyaHdrTop dya word
5813 {NS_sprm::v6::sprmSDyaHdrBottom, nullptr}, // sep.dyaHdrBottom dya word
5814 {NS_sprm::v6::sprmSLBetween, nullptr}, // sep.fLBetween 0 or 1 byte
5815 {NS_sprm::v6::sprmSVjc, nullptr}, // sep.vjc vjc byte
5816 {NS_sprm::v6::sprmSLnnMin, nullptr}, // sep.lnnMin lnn word
5817 {NS_sprm::v6::sprmSPgnStart, nullptr}, // sep.pgnStart pgn word
5818 {NS_sprm::v6::sprmSBOrientation, nullptr}, // sep.dmOrientPage dm byte
5819 {NS_sprm::v6::sprmSBCustomize, nullptr}, // ?
5820 {NS_sprm::v6::sprmSXaPage, nullptr}, // sep.xaPage xa word
5821 {NS_sprm::v6::sprmSYaPage, nullptr}, // sep.yaPage ya word
5822 {NS_sprm::v6::sprmSDxaLeft, nullptr}, // sep.dxaLeft dxa word
5823 {NS_sprm::v6::sprmSDxaRight, nullptr}, // sep.dxaRight dxa word
5824 {NS_sprm::v6::sprmSDyaTop, nullptr}, // sep.dyaTop dya word
5825 {NS_sprm::v6::sprmSDyaBottom, nullptr}, // sep.dyaBottom dya word
5826 {NS_sprm::v6::sprmSDzaGutter, nullptr}, // sep.dzaGutter dza word
5827 {NS_sprm::v6::sprmSDMPaperReq, nullptr}, // sep.dmPaperReq dm word
5828 {172, nullptr}, //"??172",
5829 {173, nullptr}, //"??173",
5830 {174, nullptr}, //"??174",
5831 {175, nullptr}, //"??175",
5832 {176, nullptr}, //"??176",
5833 {177, nullptr}, //"??177",
5834 {178, nullptr}, //"??178",
5835 {179, nullptr}, //"??179",
5836 {180, nullptr}, //"??180",
5837 {181, nullptr}, //"??181",
5838 {NS_sprm::v6::sprmTJc, nullptr}, // tap.jc jc word (low order byte is significant)
5839 {NS_sprm::v6::sprmTDxaLeft, nullptr}, // tap.rgdxaCenter dxa word
5840 {NS_sprm::v6::sprmTDxaGapHalf, nullptr}, // tap.dxaGapHalf, tap.rgdxaCenter dxa word
5841 {NS_sprm::v6::sprmTFCantSplit, nullptr}, // tap.fCantSplit 1 or 0 byte
5842 {NS_sprm::v6::sprmTTableHeader, nullptr}, // tap.fTableHeader 1 or 0 byte
5843 {NS_sprm::v6::sprmTTableBorders, nullptr}, // tap.rgbrcTable complex 12 bytes
5844 {NS_sprm::v6::sprmTDefTable10, nullptr}, // tap.rgdxaCenter, tap.rgtc complex variable length
5845 {NS_sprm::v6::sprmTDyaRowHeight, nullptr}, // tap.dyaRowHeight dya word
5846 {NS_sprm::v6::sprmTDefTable, nullptr}, // tap.rgtc complex
5847 {NS_sprm::v6::sprmTDefTableShd, nullptr}, // tap.rgshd complex
5848 {NS_sprm::v6::sprmTTlp, nullptr}, // tap.tlp TLP 4 bytes
5849 {NS_sprm::v6::sprmTSetBrc, nullptr}, // tap.rgtc[].rgbrc complex 5 bytes
5850 {NS_sprm::v6::sprmTInsert, nullptr}, // tap.rgdxaCenter, tap.rgtc complex 4 bytes
5851 {NS_sprm::v6::sprmTDelete, nullptr}, // tap.rgdxaCenter, tap.rgtc complex word
5852 {NS_sprm::v6::sprmTDxaCol, nullptr}, // tap.rgdxaCenter complex 4 bytes
5853 {NS_sprm::v6::sprmTMerge, nullptr}, // tap.fFirstMerged, tap.fMerged complex word
5854 {NS_sprm::v6::sprmTSplit, nullptr}, // tap.fFirstMerged, tap.fMerged complex word
5855 {NS_sprm::v6::sprmTSetBrc10, nullptr}, // tap.rgtc[].rgbrc complex 5 bytes
5856 {NS_sprm::v6::sprmTSetShd, nullptr}, // tap.rgshd complex 4 bytes
5857 {207, nullptr}, //dunno
5860 static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
5861 return &aSprmSrch;
5864 static const wwSprmDispatcher *GetWW8SprmDispatcher()
5866 static SprmReadInfo aSprms[] =
5868 {0, nullptr}, // "0" default resp. error
5870 {NS_sprm::PIstd::val, &SwWW8ImplReader::Read_StyleCode}, // pap.istd;istd (style code);short;
5871 {NS_sprm::PIstdPermute::val, nullptr}, // pap.istd;permutation vector;
5872 // variable length;
5873 {NS_sprm::PIncLvl::val, nullptr}, // pap.istd, pap.lvl;difference between
5874 // istd of base PAP and istd of
5875 // PAP to be produced;byte;
5876 {NS_sprm::PJc80::val, &SwWW8ImplReader::Read_Justify}, // pap.jc;jc (justification);byte;
5877 {NS_sprm::LN_PFSideBySide, nullptr}, // pap.fSideBySide;0 or 1;byte;
5878 {NS_sprm::PFKeep::val, &SwWW8ImplReader::Read_KeepLines}, // pap.fKeep;0 or 1;byte;
5879 {NS_sprm::PFKeepFollow::val, &SwWW8ImplReader::Read_KeepParas}, // pap.fKeepFollow;0 or 1;byte;
5880 {NS_sprm::PFPageBreakBefore::val, &SwWW8ImplReader::Read_BreakBefore}, // pap.fPageBreakBefore;0 or 1;byte;
5881 {NS_sprm::LN_PBrcl, nullptr}, // pap.brcl;brcl;byte;
5882 {NS_sprm::LN_PBrcp, nullptr}, // pap.brcp;brcp;byte;
5883 {NS_sprm::PIlvl::val, &SwWW8ImplReader::Read_ListLevel}, // pap.ilvl;ilvl;byte;
5884 {NS_sprm::PIlfo::val, &SwWW8ImplReader::Read_LFOPosition}, // pap.ilfo;ilfo (list index);short;
5885 {NS_sprm::PFNoLineNumb::val, &SwWW8ImplReader::Read_NoLineNumb}, // pap.fNoLnn;0 or 1;byte;
5886 {NS_sprm::PChgTabsPapx::val, &SwWW8ImplReader::Read_Tab}, // pap.itbdMac, pap.rgdxaTab, pap.rgtbd;
5887 // complex;variable length
5888 {NS_sprm::PDxaRight80::val, &SwWW8ImplReader::Read_LR}, // pap.dxaRight;dxa;word;
5889 {NS_sprm::PDxaLeft80::val, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft;dxa;word;
5890 {NS_sprm::PNest80::val, nullptr}, // pap.dxaLeft;dxa;word;
5891 {NS_sprm::PDxaLeft180::val, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft1;dxa;word;
5892 {NS_sprm::PDyaLine::val, &SwWW8ImplReader::Read_LineSpace}, // pap.lspd;an LSPD, a long word
5893 // structure consisting of a short
5894 // of dyaLine followed by a short
5895 // of fMultLinespace;long;
5896 {NS_sprm::PDyaBefore::val, &SwWW8ImplReader::Read_UL}, // pap.dyaBefore;dya;word;
5897 {NS_sprm::PDyaAfter::val, &SwWW8ImplReader::Read_UL}, // pap.dyaAfter;dya;word;
5898 {NS_sprm::PChgTabs::val, nullptr}, // pap.itbdMac, pap.rgdxaTab, pap.rgtbd;
5899 // complex;variable length;
5900 {NS_sprm::PFInTable::val, nullptr}, // pap.fInTable;0 or 1;byte;
5901 {NS_sprm::PFTtp::val, &SwWW8ImplReader::Read_TabRowEnd}, // pap.fTtp;0 or 1;byte;
5902 {NS_sprm::PDxaAbs::val, nullptr}, // pap.dxaAbs;dxa;word;
5903 {NS_sprm::PDyaAbs::val, nullptr}, // pap.dyaAbs;dya;word;
5904 {NS_sprm::PDxaWidth::val, nullptr}, // pap.dxaWidth;dxa;word;
5905 {NS_sprm::PPc::val, &SwWW8ImplReader::Read_ApoPPC}, // pap.pcHorz, pap.pcVert;complex;byte;
5906 {NS_sprm::LN_PBrcTop10, nullptr}, // pap.brcTop;BRC10;word;
5907 {NS_sprm::LN_PBrcLeft10, nullptr}, // pap.brcLeft;BRC10;word;
5908 {NS_sprm::LN_PBrcBottom10, nullptr}, // pap.brcBottom;BRC10;word;
5909 {NS_sprm::LN_PBrcRight10, nullptr}, // pap.brcRight;BRC10;word;
5910 {NS_sprm::LN_PBrcBetween10, nullptr}, // pap.brcBetween;BRC10;word;
5911 {NS_sprm::LN_PBrcBar10, nullptr}, // pap.brcBar;BRC10;word;
5912 {NS_sprm::LN_PDxaFromText10, nullptr}, // pap.dxaFromText;dxa;word;
5913 {NS_sprm::PWr::val, nullptr}, // pap.wr;wr;byte;
5914 {NS_sprm::PBrcTop80::val, &SwWW8ImplReader::Read_Border}, // pap.brcTop;BRC;long;
5915 {NS_sprm::PBrcLeft80::val, &SwWW8ImplReader::Read_Border}, // pap.brcLeft;BRC;long;
5916 {NS_sprm::PBrcBottom80::val, &SwWW8ImplReader::Read_Border}, // pap.brcBottom;BRC;long;
5917 {NS_sprm::PBrcRight80::val, &SwWW8ImplReader::Read_Border}, // pap.brcRight;BRC;long;
5918 {NS_sprm::PBrcBetween80::val, &SwWW8ImplReader::Read_Border}, // pap.brcBetween;BRC;long;
5919 {NS_sprm::PBrcBar80::val, nullptr}, // pap.brcBar;BRC;long;
5920 {NS_sprm::PFNoAutoHyph::val, &SwWW8ImplReader::Read_Hyphenation}, // pap.fNoAutoHyph;0 or 1;byte;
5921 {NS_sprm::PWHeightAbs::val, nullptr}, // pap.wHeightAbs;w;word;
5922 {NS_sprm::PDcs::val, nullptr}, // pap.dcs;DCS;short;
5923 {NS_sprm::PShd80::val, &SwWW8ImplReader::Read_Shade}, // pap.shd;SHD;word;
5924 {NS_sprm::PDyaFromText::val, nullptr}, // pap.dyaFromText;dya;word;
5925 {NS_sprm::PDxaFromText::val, nullptr}, // pap.dxaFromText;dxa;word;
5926 {NS_sprm::PFLocked::val, nullptr}, // pap.fLocked;0 or 1;byte;
5927 {NS_sprm::PFWidowControl::val, &SwWW8ImplReader::Read_WidowControl}, // pap.fWidowControl;0 or 1;byte
5928 {NS_sprm::LN_PRuler, nullptr}, // variable length;
5929 {NS_sprm::PFKinsoku::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fKinsoku;0 or 1;byte;
5930 {NS_sprm::PFWordWrap::val, nullptr}, // pap.fWordWrap;0 or 1;byte;
5931 {NS_sprm::PFOverflowPunct::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fOverflowPunct; 0 or 1;byte;
5932 {NS_sprm::PFTopLinePunct::val, nullptr}, // pap.fTopLinePunct;0 or 1;byte
5933 {NS_sprm::PFAutoSpaceDE::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fAutoSpaceDE;0 or 1;byte;
5934 {NS_sprm::PFAutoSpaceDN::val, nullptr}, // pap.fAutoSpaceDN;0 or 1;byte;
5935 {NS_sprm::PWAlignFont::val, &SwWW8ImplReader::Read_AlignFont}, // pap.wAlignFont;iFa;word;
5936 {NS_sprm::PFrameTextFlow::val, nullptr}, // pap.fVertical pap.fBackward
5937 // pap.fRotateFont;complex; word
5938 {NS_sprm::LN_PISnapBaseLine, nullptr}, // obsolete, not applicable in
5939 // Word97 and later versions;;byte;
5940 {NS_sprm::LN_PAnld, &SwWW8ImplReader::Read_ANLevelDesc}, // pap.anld;;variable length;
5941 {NS_sprm::LN_PPropRMark, nullptr}, // pap.fPropRMark;complex;
5942 // variable length;
5943 {NS_sprm::POutLvl::val, &SwWW8ImplReader::Read_POutLvl}, // pap.lvl;has no effect if pap.istd
5944 // is < 1 or is > 9;byte;
5945 {NS_sprm::PFBiDi::val, &SwWW8ImplReader::Read_ParaBiDi}, // ;;byte;
5946 {NS_sprm::PFNumRMIns::val, nullptr}, // pap.fNumRMIns;1 or 0;bit;
5947 {NS_sprm::LN_PCrLf, nullptr}, // ;;byte;
5948 {NS_sprm::PNumRM::val, nullptr}, // pap.numrm;;variable length;
5949 {NS_sprm::LN_PHugePapx, nullptr}, // ;fc in the data stream to locate
5950 // the huge grpprl;long;
5951 {NS_sprm::PHugePapx::val, nullptr}, // ;fc in the data stream to locate
5952 // the huge grpprl;long;
5953 {NS_sprm::PFUsePgsuSettings::val, &SwWW8ImplReader::Read_UsePgsuSettings}, // pap.fUsePgsuSettings;1 or 0;byte;
5954 {NS_sprm::PFAdjustRight::val, nullptr}, // pap.fAdjustRight;1 or 0;byte;
5955 {NS_sprm::CFRMarkDel::val, &SwWW8ImplReader::Read_CFRMarkDel}, // chp.fRMarkDel;1 or 0;bit;
5956 {NS_sprm::CFRMarkIns::val, &SwWW8ImplReader::Read_CFRMark}, // chp.fRMark;1 or 0;bit;
5957 {NS_sprm::CFFldVanish::val, &SwWW8ImplReader::Read_FieldVanish}, // chp.fFieldVanish;1 or 0;bit;
5958 {NS_sprm::CPicLocation::val, &SwWW8ImplReader::Read_PicLoc}, // chp.fcPic and chp.fSpec;variable
5959 // length, length recorded is always 4;
5960 {NS_sprm::CIbstRMark::val, nullptr}, // chp.ibstRMark;index into
5961 // sttbRMark;short;
5962 {NS_sprm::CDttmRMark::val, nullptr}, // chp.dttmRMark;DTTM;long;
5963 {NS_sprm::CFData::val, nullptr}, // chp.fData;1 or 0;bit;
5964 {NS_sprm::CIdslRMark::val, nullptr}, // chp.idslRMReason;an index to
5965 // a table of strings defined in
5966 // Word 6.0 executables;short;
5967 {NS_sprm::LN_CChs, &SwWW8ImplReader::Read_CharSet}, // chp.fChsDiff and chp.chse;3 bytes;
5968 {NS_sprm::CSymbol::val, &SwWW8ImplReader::Read_Symbol}, // chp.fSpec, chp.xchSym and chp.ftcSym;
5969 // variable length, length
5970 // recorded is always 4;
5971 {NS_sprm::CFOle2::val, &SwWW8ImplReader::Read_Obj}, // chp.fOle2;1 or 0;bit;
5972 //NS_sprm::LN_CIdCharType, // obsolete: not applicable in Word97
5973 // and later versions
5974 {NS_sprm::CHighlight::val, &SwWW8ImplReader::Read_CharHighlight}, // chp.fHighlight, chp.icoHighlight;ico
5975 // (fHighlight is set to 1 iff
5976 // ico is not 0);byte;
5977 {NS_sprm::LN_CObjLocation, &SwWW8ImplReader::Read_PicLoc}, // chp.fcObj;FC;long;
5978 //NS_sprm::LN_CFFtcAsciSymb, ? ? ?,
5979 {NS_sprm::CIstd::val, &SwWW8ImplReader::Read_CColl}, // chp.istd;istd,short;
5980 {NS_sprm::CIstdPermute::val, nullptr}, // chp.istd;permutation vector;
5981 // variable length;
5982 {NS_sprm::LN_CDefault, nullptr}, // whole CHP;none;variable length;
5983 {NS_sprm::CPlain::val, nullptr}, // whole CHP;none;length: 0;
5984 {NS_sprm::CKcd::val, &SwWW8ImplReader::Read_Emphasis},
5985 {NS_sprm::CFBold::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fBold;0,1, 128, or 129;byte;
5986 {NS_sprm::CFItalic::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fItalic;0,1, 128, or 129; byte;
5987 {NS_sprm::CFStrike::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fStrike;0,1, 128, or 129; byte;
5988 {NS_sprm::CFOutline::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fOutline;0,1, 128, or 129; byte;
5989 {NS_sprm::CFShadow::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fShadow;0,1, 128, or 129; byte;
5990 {NS_sprm::CFSmallCaps::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fSmallCaps;0,1, 128, or 129;byte;
5991 {NS_sprm::CFCaps::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fCaps;0,1, 128, or 129; byte;
5992 {NS_sprm::CFVanish::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fVanish;0,1, 128, or 129; byte;
5993 //NS_sprm::LN_CFtcDefault, 0, // ftc, only used internally, never
5994 // stored in file;word;
5995 {NS_sprm::CKul::val, &SwWW8ImplReader::Read_Underline}, // chp.kul;kul;byte;
5996 {NS_sprm::LN_CSizePos, nullptr}, // chp.hps, chp.hpsPos;3 bytes;
5997 {NS_sprm::CDxaSpace::val, &SwWW8ImplReader::Read_Kern}, // chp.dxaSpace;dxa;word;
5998 {NS_sprm::LN_CLid, &SwWW8ImplReader::Read_Language}, // ;only used internally, never stored;
5999 // word;
6000 {NS_sprm::CIco::val, &SwWW8ImplReader::Read_TextColor}, // chp.ico;ico;byte;
6001 {NS_sprm::CHps::val, &SwWW8ImplReader::Read_FontSize}, // chp.hps;hps;byte;
6002 {NS_sprm::LN_CHpsInc, nullptr}, // chp.hps;byte;
6003 {NS_sprm::CHpsPos::val, &SwWW8ImplReader::Read_SubSuperProp}, // chp.hpsPos;hps;byte;
6004 {NS_sprm::LN_CHpsPosAdj, nullptr}, // chp.hpsPos;hps;byte;
6005 {NS_sprm::CMajority::val, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fStrike,
6006 // chp.fSmallCaps, chp.fVanish, chp.fCaps,
6007 // chp.hps, chp.hpsPos, chp.dxaSpace,
6008 // chp.kul, chp.ico, chp.rgftc, chp.rglid;
6009 // complex;variable length, length byte
6010 // plus size of following grpprl;
6011 {NS_sprm::CIss::val, &SwWW8ImplReader::Read_SubSuper}, // chp.iss;iss;byte;
6012 {NS_sprm::LN_CHpsNew50, nullptr}, // chp.hps;hps;variable width, length
6013 // always recorded as 2;
6014 {NS_sprm::LN_CHpsInc1, nullptr}, // chp.hps;complex; variable width,
6015 // length always recorded as 2;
6016 {NS_sprm::CHpsKern::val, &SwWW8ImplReader::Read_FontKern}, // chp.hpsKern;hps;short;
6017 {NS_sprm::LN_CMajority50, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fStrike,
6018 // chp.fSmallCaps, chp.fVanish, chp.fCaps,
6019 // chp.ftc, chp.hps, chp.hpsPos, chp.kul,
6020 // chp.dxaSpace, chp.ico;complex;
6021 // variable length;
6022 {NS_sprm::LN_CHpsMul, nullptr}, // chp.hps;percentage to grow hps;short;
6023 {NS_sprm::CHresi::val, nullptr}, // ???? "sprmCYsri" chp.ysri;ysri;short;
6024 {NS_sprm::CRgFtc0::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[0];ftc for ASCII text;short;
6025 {NS_sprm::CRgFtc1::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[1];ftc for Far East text;
6026 // short;
6027 {NS_sprm::CRgFtc2::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[2];ftc for non-Far East text;
6028 // short;
6029 {NS_sprm::CCharScale::val, &SwWW8ImplReader::Read_ScaleWidth},
6030 {NS_sprm::CFDStrike::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fDStrike;;byte;
6031 {NS_sprm::CFImprint::val, &SwWW8ImplReader::Read_Relief}, // chp.fImprint;1 or 0;bit;
6032 {NS_sprm::CFSpec::val, &SwWW8ImplReader::Read_Special}, // chp.fSpec;1 or 0;bit;
6033 {NS_sprm::CFObj::val, &SwWW8ImplReader::Read_Obj}, // chp.fObj;1 or 0;bit;
6034 {NS_sprm::CPropRMark90::val, &SwWW8ImplReader::Read_CPropRMark}, // chp.fPropRMark, chp.ibstPropRMark,
6035 // chp.dttmPropRMark;Complex;variable
6036 // length always recorded as 7 bytes;
6037 {NS_sprm::CFEmboss::val, &SwWW8ImplReader::Read_Relief}, // chp.fEmboss;1 or 0;bit;
6038 {NS_sprm::CSfxText::val, &SwWW8ImplReader::Read_TextAnim}, // chp.sfxtText;text animation;byte;
6039 {NS_sprm::CFBiDi::val, &SwWW8ImplReader::Read_Bidi},
6040 {NS_sprm::LN_CFDiacColor, nullptr},
6041 {NS_sprm::CFBoldBi::val, &SwWW8ImplReader::Read_BoldBiDiUsw},
6042 {NS_sprm::CFItalicBi::val, &SwWW8ImplReader::Read_BoldBiDiUsw},
6043 {NS_sprm::CFtcBi::val, &SwWW8ImplReader::Read_FontCode},
6044 {NS_sprm::CLidBi::val, &SwWW8ImplReader::Read_Language},
6045 //NS_sprm::CIcoBi::val, ? ? ?,
6046 {NS_sprm::CHpsBi::val, &SwWW8ImplReader::Read_FontSize},
6047 {NS_sprm::CDispFldRMark::val, nullptr}, // chp.fDispFieldRMark,
6048 // chp.ibstDispFieldRMark,
6049 // chp.dttmDispFieldRMark;
6050 // Complex;variable length
6051 // always recorded as 39 bytes;
6052 {NS_sprm::CIbstRMarkDel::val, nullptr}, // chp.ibstRMarkDel;index into
6053 // sttbRMark;short;
6054 {NS_sprm::CDttmRMarkDel::val, nullptr}, // chp.dttmRMarkDel;DTTM;long;
6055 {NS_sprm::CBrc80::val, &SwWW8ImplReader::Read_CharBorder}, // chp.brc;BRC;long;
6056 {NS_sprm::CBrc::val, &SwWW8ImplReader::Read_CharBorder}, // chp.brc;BRC;long;
6057 {NS_sprm::CShd80::val, &SwWW8ImplReader::Read_CharShadow}, // chp.shd;SHD;short;
6058 {NS_sprm::CIdslRMarkDel::val, nullptr}, // chp.idslRMReasonDel;an index to
6059 // a table of strings defined in
6060 // Word 6.0 executables;short;
6061 {NS_sprm::CFUsePgsuSettings::val, nullptr}, // chp.fUsePgsuSettings; 1 or 0;bit;
6062 {NS_sprm::LN_CCpg, nullptr}, // ;;word;
6063 {NS_sprm::CRgLid0_80::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[0];
6064 // LID: for non-Far East text;word;
6065 {NS_sprm::CRgLid1_80::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[1];
6066 // LID: for Far East text;word;
6067 {NS_sprm::CIdctHint::val, &SwWW8ImplReader::Read_IdctHint}, // chp.idctHint;IDCT: byte;
6068 {NS_sprm::LN_PicBrcl, nullptr}, // pic.brcl;brcl (see PIC structure
6069 // definition);byte;
6070 {NS_sprm::LN_PicScale, nullptr}, // pic.mx, pic.my, pic.dxaCropleft,
6071 // pic.dyaCropTop pic.dxaCropRight,
6072 // pic.dyaCropBottom;Complex;
6073 // length byte plus 12 bytes;
6074 {NS_sprm::PicBrcTop80::val, nullptr}, // pic.brcTop;BRC;long;
6075 {NS_sprm::PicBrcLeft80::val, nullptr}, // pic.brcLeft;BRC;long;
6076 {NS_sprm::PicBrcBottom80::val, nullptr}, // pic.brcBottom;BRC;long;
6077 {NS_sprm::PicBrcRight80::val, nullptr}, // pic.brcRight;BRC;long;
6078 {NS_sprm::ScnsPgn::val, nullptr}, // sep.cnsPgn;cns;byte;
6079 {NS_sprm::SiHeadingPgn::val, nullptr}, // sep.iHeadingPgn;heading number level;
6080 // byte;
6081 {NS_sprm::LN_SOlstAnm, &SwWW8ImplReader::Read_OLST}, // sep.olstAnm;OLST;variable length;
6082 {NS_sprm::SDxaColWidth::val, nullptr}, // sep.rgdxaColWidthSpacing;complex;
6083 // 3 bytes;
6084 {NS_sprm::SDxaColSpacing::val, nullptr}, // sep.rgdxaColWidthSpacing;complex;
6085 // 3 bytes;
6086 {NS_sprm::SFEvenlySpaced::val, nullptr}, // sep.fEvenlySpaced; 1 or 0;byte;
6087 {NS_sprm::SFProtected::val, nullptr}, // sep.fUnlocked;1 or 0;byte;
6088 {NS_sprm::SDmBinFirst::val, nullptr}, // sep.dmBinFirst;;word;
6089 {NS_sprm::SDmBinOther::val, nullptr}, // sep.dmBinOther;;word;
6090 {NS_sprm::SBkc::val, nullptr}, // sep.bkc;bkc;byte;
6091 {NS_sprm::SFTitlePage::val, nullptr}, // sep.fTitlePage;0 or 1;byte;
6092 {NS_sprm::SCcolumns::val, nullptr}, // sep.ccolM1;# of cols - 1;word;
6093 {NS_sprm::SDxaColumns::val, nullptr}, // sep.dxaColumns;dxa;word;
6094 {NS_sprm::LN_SFAutoPgn, nullptr}, // sep.fAutoPgn;obsolete;byte;
6095 {NS_sprm::SNfcPgn::val, nullptr}, // sep.nfcPgn;nfc;byte;
6096 {NS_sprm::LN_SDyaPgn, nullptr}, // sep.dyaPgn;dya;short;
6097 {NS_sprm::LN_SDxaPgn, nullptr}, // sep.dxaPgn;dya;short;
6098 {NS_sprm::SFPgnRestart::val, nullptr}, // sep.fPgnRestart;0 or 1;byte;
6099 {NS_sprm::SFEndnote::val, nullptr}, // sep.fEndnote;0 or 1;byte;
6100 {NS_sprm::SLnc::val, nullptr}, // sep.lnc;lnc;byte;
6101 {NS_sprm::LN_SGprfIhdt, nullptr}, // sep.grpfIhdt;grpfihdt;byte;
6102 {NS_sprm::SNLnnMod::val, nullptr}, // sep.nLnnMod;non-neg int.;word;
6103 {NS_sprm::SDxaLnn::val, nullptr}, // sep.dxaLnn;dxa;word;
6104 {NS_sprm::SDyaHdrTop::val, nullptr}, // sep.dyaHdrTop;dya;word;
6105 {NS_sprm::SDyaHdrBottom::val, nullptr}, // sep.dyaHdrBottom;dya;word;
6106 {NS_sprm::SLBetween::val, nullptr}, // sep.fLBetween;0 or 1;byte;
6107 {NS_sprm::SVjc::val, &SwWW8ImplReader::Read_TextVerticalAdjustment}, // sep.vjc;vjc;byte;
6108 {NS_sprm::SLnnMin::val, nullptr}, // sep.lnnMin;lnn;word;
6109 {NS_sprm::SPgnStart97::val, nullptr}, // sep.pgnStart;pgn;word;
6110 {NS_sprm::SBOrientation::val, nullptr}, // sep.dmOrientPage;dm;byte;
6111 //NS_sprm::LN_SBCustomize, ? ? ?,
6112 {NS_sprm::SXaPage::val, nullptr}, // sep.xaPage;xa;word;
6113 {NS_sprm::SYaPage::val, nullptr}, // sep.yaPage;ya;word;
6114 {0x2205, nullptr}, // ???? "sprmSDxaLeft" sep.dxaLeft;
6115 // dxa;word;
6116 {NS_sprm::SDxaLeft::val, nullptr}, // sep.dxaLeft;dxa;word;
6117 {NS_sprm::SDxaRight::val, nullptr}, // sep.dxaRight;dxa;word;
6118 {NS_sprm::SDyaTop::val, nullptr}, // sep.dyaTop;dya;word;
6119 {NS_sprm::SDyaBottom::val, nullptr}, // sep.dyaBottom;dya;word;
6120 {NS_sprm::SDzaGutter::val, nullptr}, // sep.dzaGutter;dza;word;
6121 {NS_sprm::SDmPaperReq::val, nullptr}, // sep.dmPaperReq;dm;word;
6122 {NS_sprm::LN_SPropRMark, nullptr}, // sep.fPropRMark, sep.ibstPropRMark,
6123 // sep.dttmPropRMark;complex; variable
6124 // length always recorded as 7 bytes;
6125 //NS_sprm::SFBiDi::val, ? ? ?,
6126 //NS_sprm::LN_SFFacingCol, ? ? ?,
6127 {NS_sprm::SFRTLGutter::val, nullptr}, // set to 1 if gutter is on the right.
6128 {NS_sprm::SBrcTop80::val, nullptr}, // sep.brcTop;BRC;long;
6129 {NS_sprm::SBrcLeft80::val, nullptr}, // sep.brcLeft;BRC;long;
6130 {NS_sprm::SBrcBottom80::val, nullptr}, // sep.brcBottom;BRC;long;
6131 {NS_sprm::SBrcRight80::val, nullptr}, // sep.brcRight;BRC;long;
6132 {NS_sprm::SPgbProp::val, nullptr}, // sep.pgbProp;word;
6133 {NS_sprm::SDxtCharSpace::val, nullptr}, // sep.dxtCharSpace;dxt;long;
6134 {NS_sprm::SDyaLinePitch::val, nullptr}, // sep.dyaLinePitch;dya;
6135 // WRONG:long; RIGHT:short; !
6136 //NS_sprm::SClm::val, ? ? ?,
6137 {NS_sprm::STextFlow::val, nullptr}, // sep.wTextFlow;complex;short
6138 {NS_sprm::TJc90::val, nullptr}, // tap.jc;jc;word
6139 // (low order byte is significant);
6140 {NS_sprm::TDxaLeft::val, nullptr}, // tap.rgdxaCenter;dxa;word;
6141 {NS_sprm::TDxaGapHalf::val, nullptr}, // tap.dxaGapHalf,
6142 // tap.rgdxaCenter;dxa;word;
6143 {NS_sprm::TFCantSplit90::val, nullptr}, // tap.fCantSplit90;1 or 0;byte;
6144 {NS_sprm::TTableHeader::val, nullptr}, // tap.fTableHeader;1 or 0;byte;
6145 {NS_sprm::TFCantSplit::val, nullptr}, // tap.fCantSplit;1 or 0;byte;
6146 {NS_sprm::TTableBorders80::val, nullptr}, // tap.rgbrcTable;complex;24 bytes;
6147 {NS_sprm::LN_TDefTable10, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
6148 // variable length;
6149 {NS_sprm::TDyaRowHeight::val, nullptr}, // tap.dyaRowHeight;dya;word;
6150 {NS_sprm::TDefTable::val, nullptr}, // tap.rgtc;complex
6151 {NS_sprm::TDefTableShd80::val, nullptr}, // tap.rgshd;complex
6152 {NS_sprm::TTlp::val, nullptr}, // tap.tlp;TLP;4 bytes;
6153 //NS_sprm::TFBiDi::val, ? ? ?,
6154 //NS_sprm::LN_THTMLProps, ? ? ?,
6155 {NS_sprm::TSetBrc80::val, nullptr}, // tap.rgtc[].rgbrc;complex;5 bytes;
6156 {NS_sprm::TInsert::val, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
6157 // 4 bytes;
6158 {NS_sprm::TDelete::val, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
6159 // word;
6160 {NS_sprm::TDxaCol::val, nullptr}, // tap.rgdxaCenter;complex;4 bytes;
6161 {NS_sprm::TMerge::val, nullptr}, // tap.fFirstMerged, tap.fMerged;
6162 // complex; word;
6163 {NS_sprm::TSplit::val, nullptr}, // tap.fFirstMerged, tap.fMerged;
6164 // complex;word;
6165 {NS_sprm::LN_TSetBrc10, nullptr}, // tap.rgtc[].rgbrc;complex;5 bytes;
6166 {NS_sprm::LN_TSetShd80, nullptr}, // tap.rgshd;complex;4 bytes;
6167 {NS_sprm::LN_TSetShdOdd80, nullptr}, // tap.rgshd;complex;4 bytes;
6168 {NS_sprm::TTextFlow::val, nullptr}, // tap.rgtc[].fVertical
6169 // tap.rgtc[].fBackward
6170 // tap.rgtc[].fRotateFont
6171 // 0 or 10 or 10 or 1;word;
6172 //NS_sprm::LN_TDiagLine, ? ? ? ,
6173 {NS_sprm::TVertMerge::val, nullptr}, // tap.rgtc[].vertMerge;complex;variable
6174 // length always recorded as 2 bytes;
6175 {NS_sprm::TVertAlign::val, nullptr}, // tap.rgtc[].vertAlign;complex;variable
6176 // length always recorded as 3 bytes;
6177 {NS_sprm::CFELayout::val, &SwWW8ImplReader::Read_DoubleLine_Rotate},
6178 {NS_sprm::PItap::val, nullptr},
6179 {NS_sprm::TTableWidth::val, nullptr}, // recorded as 3 bytes;
6180 {NS_sprm::TDefTableShd::val, nullptr},
6181 {NS_sprm::TTableBorders::val, nullptr},
6182 {NS_sprm::TBrcTopCv::val, nullptr},
6183 {NS_sprm::TBrcLeftCv::val, nullptr},
6184 {NS_sprm::TBrcBottomCv::val, nullptr},
6185 {NS_sprm::TBrcRightCv::val, nullptr},
6186 {NS_sprm::TCellPaddingDefault::val, nullptr},
6187 {NS_sprm::TCellPadding::val, nullptr},
6188 {0xD238, nullptr}, // undocumented sep
6189 {NS_sprm::PBrcTop::val, &SwWW8ImplReader::Read_Border},
6190 {NS_sprm::PBrcLeft::val, &SwWW8ImplReader::Read_Border},
6191 {NS_sprm::PBrcBottom::val, &SwWW8ImplReader::Read_Border},
6192 {NS_sprm::PBrcRight::val, &SwWW8ImplReader::Read_Border},
6193 {NS_sprm::PBrcBetween::val, &SwWW8ImplReader::Read_Border},
6194 {NS_sprm::TWidthIndent::val, nullptr},
6195 {NS_sprm::CRgLid0::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[0];
6196 // LID: for non-Far East text;
6197 {NS_sprm::CRgLid1::val, nullptr}, // chp.rglid[1];
6198 // LID: for Far East text
6199 {0x6463, nullptr}, // undocumented
6200 {NS_sprm::PJc::val, &SwWW8ImplReader::Read_RTLJustify},
6201 {NS_sprm::PDxaLeft::val, &SwWW8ImplReader::Read_LR},
6202 {NS_sprm::PDxaLeft1::val, &SwWW8ImplReader::Read_LR},
6203 {NS_sprm::PDxaRight::val, &SwWW8ImplReader::Read_LR},
6204 {NS_sprm::TFAutofit::val, nullptr},
6205 {NS_sprm::TPc::val, nullptr},
6206 {NS_sprm::TDxaAbs::val, nullptr},
6207 {NS_sprm::TDyaAbs::val, nullptr},
6208 {NS_sprm::TDxaFromText::val, nullptr},
6209 {NS_sprm::SRsid::val, nullptr},
6210 {NS_sprm::SFpc::val, nullptr},
6211 {NS_sprm::PFInnerTableCell::val, &SwWW8ImplReader::Read_TabCellEnd},
6212 {NS_sprm::PFInnerTtp::val, &SwWW8ImplReader::Read_TabRowEnd},
6213 {NS_sprm::CRsidProp::val, nullptr},
6214 {NS_sprm::CRsidText::val, nullptr},
6215 {NS_sprm::CCv::val, &SwWW8ImplReader::Read_TextForeColor},
6216 {NS_sprm::CCvUl::val, &SwWW8ImplReader::Read_UnderlineColor},
6217 {NS_sprm::PShd::val, &SwWW8ImplReader::Read_ParaBackColor},
6218 {NS_sprm::PRsid::val, nullptr},
6219 {NS_sprm::TWidthBefore::val, nullptr},
6220 {NS_sprm::TSetShdTable::val, nullptr},
6221 {NS_sprm::TDefTableShdRaw::val, nullptr},
6222 {NS_sprm::CShd::val, &SwWW8ImplReader::Read_TextBackColor},
6223 {NS_sprm::SRncFtn::val, nullptr},
6224 {NS_sprm::PFDyaBeforeAuto::val, &SwWW8ImplReader::Read_ParaAutoBefore},
6225 {NS_sprm::PFDyaAfterAuto::val, &SwWW8ImplReader::Read_ParaAutoAfter},
6226 {NS_sprm::PFContextualSpacing::val, &SwWW8ImplReader::Read_ParaContextualSpacing},
6227 {NS_sprm::CLbcCRJ::val, &SwWW8ImplReader::Read_LineBreakClear},
6230 static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
6231 return &aSprmSrch;
6234 // helper routines : find SPRM
6236 const SprmReadInfo& SwWW8ImplReader::GetSprmReadInfo(sal_uInt16 nId) const
6238 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
6239 const wwSprmDispatcher *pDispatcher;
6240 if (eVersion <= ww::eWW2)
6241 pDispatcher = GetWW2SprmDispatcher();
6242 else if (eVersion < ww::eWW8)
6243 pDispatcher = GetWW6SprmDispatcher();
6244 else
6245 pDispatcher = GetWW8SprmDispatcher();
6247 SprmReadInfo aSrch = {0, nullptr};
6248 aSrch.nId = nId;
6249 const SprmReadInfo* pFound = pDispatcher->search(aSrch);
6251 if (!pFound)
6253 aSrch.nId = 0;
6254 pFound = pDispatcher->search(aSrch);
6257 return *pFound;
6260 // helper routines : SPRMs
6262 void SwWW8ImplReader::EndSprm( sal_uInt16 nId )
6264 if( ( nId > 255 ) && ( nId < 0x0800 ) ) return;
6266 const SprmReadInfo& rSprm = GetSprmReadInfo( nId );
6268 if (rSprm.pReadFnc)
6269 (this->*rSprm.pReadFnc)( nId, nullptr, -1 );
6272 short SwWW8ImplReader::ImportSprm(const sal_uInt8* pPos, sal_Int32 nMemLen, sal_uInt16 nId)
6274 if (!nId)
6275 nId = m_oSprmParser->GetSprmId(pPos);
6277 OSL_ENSURE( nId != 0xff, "Sprm FF !!!!" );
6279 const SprmReadInfo& rSprm = GetSprmReadInfo(nId);
6281 sal_Int32 nFixedLen = m_oSprmParser->DistanceToData(nId);
6282 sal_Int32 nL = m_oSprmParser->GetSprmSize(nId, pPos, nMemLen);
6284 if (rSprm.pReadFnc)
6285 (this->*rSprm.pReadFnc)(nId, pPos + nFixedLen, nL - nFixedLen);
6287 return nL;
6290 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */