nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / filter / ww8 / ww8par6.cxx
blobec87b0abc1b659ccc6f6edc55719d25c51c4861a
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 <svl/itemiter.hxx>
23 #include <svl/grabbagitem.hxx>
24 #include <rtl/tencinfo.h>
25 #include <sal/log.hxx>
27 #include <hintids.hxx>
28 #include <editeng/lspcitem.hxx>
29 #include <editeng/wrlmitem.hxx>
30 #include <editeng/udlnitem.hxx>
31 #include <editeng/kernitem.hxx>
32 #include <editeng/langitem.hxx>
33 #include <editeng/cmapitem.hxx>
34 #include <editeng/shdditem.hxx>
35 #include <editeng/contouritem.hxx>
36 #include <editeng/crossedoutitem.hxx>
37 #include <editeng/postitem.hxx>
38 #include <editeng/wghtitem.hxx>
39 #include <editeng/colritem.hxx>
40 #include <editeng/brushitem.hxx>
41 #include <editeng/spltitem.hxx>
42 #include <editeng/keepitem.hxx>
43 #include <editeng/orphitem.hxx>
44 #include <editeng/widwitem.hxx>
45 #include <editeng/adjustitem.hxx>
46 #include <editeng/escapementitem.hxx>
47 #include <editeng/fhgtitem.hxx>
48 #include <editeng/fontitem.hxx>
49 #include <editeng/shaditem.hxx>
50 #include <editeng/boxitem.hxx>
51 #include <editeng/ulspitem.hxx>
52 #include <editeng/lrspitem.hxx>
53 #include <editeng/tstpitem.hxx>
54 #include <editeng/autokernitem.hxx>
55 #include <editeng/paperinf.hxx>
56 #include <editeng/emphasismarkitem.hxx>
57 #include <editeng/twolinesitem.hxx>
58 #include <editeng/charscaleitem.hxx>
59 #include <editeng/charrotateitem.hxx>
60 #include <editeng/charreliefitem.hxx>
61 #include <editeng/blinkitem.hxx>
62 #include <editeng/hyphenzoneitem.hxx>
63 #include <editeng/paravertalignitem.hxx>
64 #include <editeng/pgrditem.hxx>
65 #include <editeng/frmdiritem.hxx>
66 #include <editeng/charhiddenitem.hxx>
67 #include <i18nlangtag/mslangid.hxx>
68 #include <svx/xfillit0.hxx>
69 #include <svx/xflclit.hxx>
70 #include "sortedarray.hxx"
71 #include "sprmids.hxx"
72 #include <node.hxx>
73 #include <ndtxt.hxx>
74 #include <pam.hxx>
75 #include <doc.hxx>
76 #include <IDocumentSettingAccess.hxx>
77 #include <pagedesc.hxx>
78 #include <fmtanchr.hxx>
79 #include <fmtcntnt.hxx>
80 #include <fchrfmt.hxx>
81 #include <fmthdft.hxx>
82 #include <fmtclds.hxx>
83 #include <fmtftntx.hxx>
84 #include <frmatr.hxx>
85 #include <section.hxx>
86 #include <lineinfo.hxx>
87 #include <fmtline.hxx>
88 #include <txatbase.hxx>
89 #include <fmtflcnt.hxx>
90 #include <tgrditem.hxx>
91 #include <hfspacingitem.hxx>
92 #include <swtable.hxx>
93 #include <fltini.hxx>
94 #include "writerhelper.hxx"
95 #include "writerwordglue.hxx"
96 #include "ww8scan.hxx"
97 #include "ww8par2.hxx"
98 #include "ww8graf.hxx"
100 #include <fmtwrapinfluenceonobjpos.hxx>
102 using namespace sw::util;
103 using namespace sw::types;
104 using namespace ::com::sun::star;
105 using namespace nsHdFtFlags;
107 // various
109 #define MM_250 1417 // WW default for horizontal borders: 2.5 cm
110 #define MM_200 1134 // WW default for lower border: 2.0 cm
113 static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
114 const WW8RStyle* pSty = nullptr, const WW8PLCFx_SEPX* pSep = nullptr);
116 Color SwWW8ImplReader::GetCol(sal_uInt8 nIco)
118 static const Color eSwWW8ColA[] =
120 COL_AUTO, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
121 COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
122 COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
123 COL_LIGHTGRAY
125 SAL_WARN_IF(
126 nIco >= SAL_N_ELEMENTS(eSwWW8ColA), "sw.ww8",
127 "ico " << sal_uInt32(nIco) << " >= " << SAL_N_ELEMENTS(eSwWW8ColA));
128 return nIco < SAL_N_ELEMENTS(eSwWW8ColA) ? eSwWW8ColA[nIco] : COL_AUTO;
131 static sal_uInt32 MSRoundTweak(sal_uInt32 x)
133 return x;
136 // page attribute which are not handled via the attribute management but
137 // using ...->HasSprm
138 // (except OLST which stays a normal attribute)
139 static short ReadSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
141 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
142 const sal_uInt8* pS = aRes.pSprm;
143 short nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToInt16(pS) : nDefaultVal;
144 return nVal;
147 static sal_uInt16 ReadUSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
149 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
150 const sal_uInt8* pS = aRes.pSprm;
151 sal_uInt16 nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToUInt16(pS) : nDefaultVal;
152 return nVal;
155 static sal_uInt8 ReadBSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, sal_uInt8 nDefaultVal )
157 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
158 const sal_uInt8* pS = aRes.pSprm;
159 sal_uInt8 nVal = (pS && aRes.nRemainingData >= 1) ? *pS : nDefaultVal;
160 return nVal;
163 void wwSection::SetDirection()
165 //sprmSTextFlow
166 switch (maSep.wTextFlow)
168 default:
169 OSL_ENSURE(false, "Unknown layout type");
170 [[fallthrough]];
171 case 0:
172 meDir=SvxFrameDirection::Horizontal_LR_TB;
173 break;
174 case 1:
175 meDir=SvxFrameDirection::Vertical_RL_TB;
176 break;
177 case 2:
178 //asian letters are not rotated, western are. We can't import
179 //bottom to top going left to right, we can't do this in
180 //pages, (in drawboxes we could partly hack it with a rotated
181 //drawing box, though not frame)
182 meDir=SvxFrameDirection::Vertical_RL_TB;
183 break;
184 case 3:
185 //asian letters are not rotated, western are. We can't import
186 meDir=SvxFrameDirection::Vertical_RL_TB;
187 break;
188 case 4:
189 //asian letters are rotated, western not. We can't import
190 meDir=SvxFrameDirection::Horizontal_LR_TB;
191 break;
194 sal_uInt8 bRTLPgn = maSep.fBiDi;
195 if ((meDir == SvxFrameDirection::Horizontal_LR_TB) && bRTLPgn)
196 meDir = SvxFrameDirection::Horizontal_RL_TB;
199 bool wwSection::IsVertical() const
201 return meDir == SvxFrameDirection::Vertical_RL_TB || meDir == SvxFrameDirection::Vertical_LR_TB;
205 This is something of festering mapping, I'm open to better ways of doing it,
206 but primarily the grid in writer is different to that in word. In writer the
207 grid elements are squares with ruby rows inbetween. While in word there is no
208 ruby stuff, and the elements are rectangles. By misusing the ruby row I can
209 handle distortions in one direction, but its all a bit of a mess:
211 void SwWW8ImplReader::SetDocumentGrid(SwFrameFormat &rFormat, const wwSection &rSection)
213 if (m_bVer67)
214 return;
216 rFormat.SetFormatAttr(SvxFrameDirectionItem(rSection.meDir, RES_FRAMEDIR));
218 SwTwips nTextareaHeight = rFormat.GetFrameSize().GetHeight();
219 const SvxULSpaceItem &rUL = ItemGet<SvxULSpaceItem>(rFormat, RES_UL_SPACE);
220 nTextareaHeight -= rUL.GetUpper();
221 nTextareaHeight -= rUL.GetLower();
223 SwTwips nTextareaWidth = rFormat.GetFrameSize().GetWidth();
224 const SvxLRSpaceItem &rLR = ItemGet<SvxLRSpaceItem>(rFormat, RES_LR_SPACE);
225 nTextareaWidth -= rLR.GetLeft();
226 nTextareaWidth -= rLR.GetRight();
228 if (rSection.IsVertical())
229 std::swap(nTextareaHeight, nTextareaWidth);
231 SwTextGridItem aGrid;
232 aGrid.SetDisplayGrid(false);
233 aGrid.SetPrintGrid(false);
234 SwTextGrid eType=GRID_NONE;
236 switch (rSection.maSep.clm)
238 case 0:
239 eType = GRID_NONE;
240 break;
241 default:
242 OSL_ENSURE(false, "Unknown grid type");
243 [[fallthrough]];
244 case 3:
245 eType = GRID_LINES_CHARS;
246 aGrid.SetSnapToChars(true);
247 break;
248 case 1:
249 eType = GRID_LINES_CHARS;
250 aGrid.SetSnapToChars(false);
251 break;
252 case 2:
253 eType = GRID_LINES_ONLY;
254 break;
257 aGrid.SetGridType(eType);
259 // seem to not add external leading in word, or the character would run across
260 // two line in some cases.
261 if (eType != GRID_NONE)
262 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, false);
264 //force to set document as standard page mode
265 bool bSquaredMode = false;
266 m_rDoc.SetDefaultPageMode( bSquaredMode );
267 aGrid.SetSquaredMode( bSquaredMode );
269 //Get the size of word's default styles font
270 sal_uInt32 nCharWidth=240;
271 for (sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); ++nI)
273 if (m_vColl[nI].m_bValid && m_vColl[nI].m_pFormat &&
274 m_vColl[nI].IsWW8BuiltInDefaultStyle())
276 nCharWidth = ItemGet<SvxFontHeightItem>(*(m_vColl[nI].m_pFormat),
277 RES_CHRATR_CJK_FONTSIZE).GetHeight();
278 break;
282 //dxtCharSpace
283 if (rSection.maSep.dxtCharSpace)
285 sal_uInt32 nCharSpace = rSection.maSep.dxtCharSpace;
286 //main lives in top 20 bits, and is signed.
287 sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
288 nMain/=0x1000;
289 nCharWidth += nMain*20;
291 int nFraction = (nCharSpace & 0x00000FFF);
292 nFraction = (nFraction*20)/0xFFF;
293 nCharWidth += nFraction;
296 aGrid.SetBaseWidth( writer_cast<sal_uInt16>(nCharWidth));
298 //sep.dyaLinePitch
299 sal_Int32 nLinePitch = rSection.maSep.dyaLinePitch;
300 if (nLinePitch >= 1 && nLinePitch <= 31680)
302 aGrid.SetLines(writer_cast<sal_uInt16>(nTextareaHeight/nLinePitch));
303 aGrid.SetBaseHeight(writer_cast<sal_uInt16>(nLinePitch));
306 aGrid.SetRubyHeight(0);
308 rFormat.SetFormatAttr(aGrid);
311 void SwWW8ImplReader::SetRelativeJustify( bool bRel )
313 if ( m_pCurrentColl && StyleExists(m_nCurrentColl) ) // importing style
314 m_vColl[m_nCurrentColl].m_nRelativeJustify = bRel ? 1 : 0;
315 else if ( m_xPlcxMan && m_xPlcxMan->GetPap() ) // importing paragraph
316 m_xPlcxMan->GetPap()->nRelativeJustify = bRel ? 1 : 0;
319 bool SwWW8ImplReader::IsRelativeJustify()
321 bool bRet = m_xWwFib->GetFIBVersion() >= ww::eWW8;
322 if ( bRet )
324 // if relativeJustify is undefined (-1), then check the parent style.
325 if ( m_pCurrentColl && StyleExists(m_nCurrentColl) )
327 sal_Int16 nRelative = m_vColl[m_nCurrentColl].m_nRelativeJustify;
328 if ( nRelative < 0 && m_nCurrentColl )
330 o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
331 bRet = IsRelativeJustify(m_vColl[m_nCurrentColl].m_nBase, aVisitedStyles);
333 else
334 bRet = nRelative > 0;
336 else if ( m_xPlcxMan && m_xPlcxMan->GetPap() )
338 sal_Int16 nRelative = m_xPlcxMan->GetPap()->nRelativeJustify;
339 if ( nRelative < 0 )
341 o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
342 bRet = IsRelativeJustify(m_nCurrentColl, aVisitedStyles);
344 else
345 bRet = nRelative > 0;
349 return bRet;
352 bool SwWW8ImplReader::IsRelativeJustify(sal_uInt16 nColl, o3tl::sorted_vector<sal_uInt16>& rVisitedStyles)
354 assert( m_xWwFib->GetFIBVersion() >= ww::eWW8
355 && "pointless to search styles if relative justify is impossible");
356 bool bRet = true;
357 if ( StyleExists(nColl) )
359 rVisitedStyles.insert(nColl);
360 // if relativeJustify is undefined (-1), then check the parent style.
361 sal_Int16 nRelative = m_vColl[nColl].m_nRelativeJustify;
362 if ( nColl == 0 || nRelative >= 0 )
363 bRet = nRelative > 0;
364 else if (rVisitedStyles.find(m_vColl[nColl].m_nBase) == rVisitedStyles.end()) // detect loop in chain
365 bRet = IsRelativeJustify(m_vColl[nColl].m_nBase, rVisitedStyles);
368 return bRet;
371 void SwWW8ImplReader::Read_ParaBiDi(sal_uInt16, const sal_uInt8* pData, short nLen)
373 if (nLen < 1)
374 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FRAMEDIR);
375 else
377 SvxFrameDirection eDir =
378 *pData ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB;
380 // In eWW8+, justify can be absolute, or relative to BiDi
381 bool bBiDiSwap = IsRelativeJustify();
382 if ( bBiDiSwap )
384 // Only change if ParaBiDi doesn't match previous setting.
385 const bool bParentRTL = IsRightToLeft();
386 bBiDiSwap = (eDir == SvxFrameDirection::Horizontal_RL_TB && !bParentRTL)
387 || (eDir == SvxFrameDirection::Horizontal_LR_TB && bParentRTL);
390 if ( bBiDiSwap )
392 const SvxAdjustItem* pItem = static_cast<const SvxAdjustItem*>(GetFormatAttr(RES_PARATR_ADJUST));
393 if ( !pItem )
395 // no previous adjust: set appropriate default
396 if ( eDir == SvxFrameDirection::Horizontal_LR_TB )
397 NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
398 else
399 NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
401 else
403 // previous adjust and bidi has changed: swap Left/Right
404 const SvxAdjust eJustify = pItem->GetAdjust();
405 if ( eJustify == SvxAdjust::Left )
406 NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
407 else if ( eJustify == SvxAdjust::Right )
408 NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
412 NewAttr(SvxFrameDirectionItem(eDir, RES_FRAMEDIR));
414 if ( m_pCurrentColl && m_xStyles ) // in style definition
415 m_xStyles->mbBidiChanged = true;
419 bool wwSectionManager::SetCols(SwFrameFormat &rFormat, const wwSection &rSection,
420 sal_uInt32 nNetWidth)
422 //sprmSCcolumns - number of columns - 1
423 const sal_Int16 nCols = rSection.NoCols();
425 if (nCols < 2) //check for no columns or other weird state
426 return false;
428 const sal_uInt16 nNetWriterWidth = writer_cast<sal_uInt16>(nNetWidth);
429 if (nNetWriterWidth == 0)
430 return false;
432 SwFormatCol aCol; // Create SwFormatCol
434 //sprmSDxaColumns - Default distance is 1.25 cm
435 sal_Int32 nColSpace = rSection.StandardColSeparation();
437 const SEPr& rSep = rSection.maSep;
439 // sprmSLBetween
440 if (rSep.fLBetween)
442 aCol.SetLineAdj(COLADJ_TOP); // Line
443 aCol.SetLineHeight(100);
444 aCol.SetLineColor(COL_BLACK);
445 aCol.SetLineWidth(1);
448 aCol.Init(nCols, writer_cast<sal_uInt16>(nColSpace), nNetWriterWidth);
450 // sprmSFEvenlySpaced
451 if (!rSep.fEvenlySpaced)
453 aCol.SetOrtho_(false);
454 const sal_uInt16 maxIdx = SAL_N_ELEMENTS(rSep.rgdxaColumnWidthSpacing);
455 for (sal_uInt16 i = 0, nIdx = 1; i < nCols && nIdx < maxIdx; i++, nIdx+=2 )
457 SwColumn* pCol = &aCol.GetColumns()[i];
458 const sal_Int32 nLeft = rSep.rgdxaColumnWidthSpacing[nIdx-1]/2;
459 const sal_Int32 nRight = rSep.rgdxaColumnWidthSpacing[nIdx+1]/2;
460 const sal_Int32 nWishWidth = rSep.rgdxaColumnWidthSpacing[nIdx]
461 + nLeft + nRight;
462 pCol->SetWishWidth(writer_cast<sal_uInt16>(nWishWidth));
463 pCol->SetLeft(writer_cast<sal_uInt16>(nLeft));
464 pCol->SetRight(writer_cast<sal_uInt16>(nRight));
466 aCol.SetWishWidth(nNetWriterWidth);
468 rFormat.SetFormatAttr(aCol);
469 return true;
472 void wwSectionManager::SetLeftRight(wwSection &rSection)
474 // 3. LR-Margin
475 sal_uInt32 nWWLe = MSRoundTweak(rSection.maSep.dxaLeft);
476 sal_uInt32 nWWRi = MSRoundTweak(rSection.maSep.dxaRight);
477 sal_uInt32 nWWGu = rSection.maSep.dzaGutter;
480 fRTLGutter is set if the gutter is on the right, the gutter is otherwise
481 placed on the left unless the global dop options are to put it on top, that
482 case is handled in GetPageULData.
484 if (rSection.maSep.fRTLGutter)
485 nWWRi += nWWGu;
486 else if (!mrReader.m_xWDop->iGutterPos)
487 nWWLe += nWWGu;
489 // Left / Right
490 if ((rSection.nPgWidth - nWWLe - nWWRi) < MINLAY)
493 There are some label templates which are "broken", they specify
494 margins which make no sense e.g. Left 16.10cm, Right 16.10cm. So the
495 space left between the margins is less than 0 In word the left margin
496 is honoured and if the right margin would be past the left margin is
497 left at the left margin position.
499 Now this will work fine for importing, layout and exporting, *but* the
500 page layout dialog has a hardcoded minimum page width of 0.5cm so it
501 will report a different value than what is actually being used. i.e.
502 it will add up the values to give a wider page than is actually being
503 used.
505 nWWRi = rSection.nPgWidth - nWWLe - MINLAY;
508 rSection.nPgLeft = nWWLe;
509 rSection.nPgRight = nWWRi;
512 void wwSectionManager::SetPage(SwPageDesc &rInPageDesc, SwFrameFormat &rFormat,
513 const wwSection &rSection, bool bIgnoreCols)
515 // 1. orientation
516 rInPageDesc.SetLandscape(rSection.IsLandScape());
518 // 2. paper size
519 SwFormatFrameSize aSz( rFormat.GetFrameSize() );
520 aSz.SetWidth(rSection.GetPageWidth());
521 aSz.SetHeight(SvxPaperInfo::GetSloppyPaperDimension(rSection.GetPageHeight()));
522 rFormat.SetFormatAttr(aSz);
524 rFormat.SetFormatAttr(
525 SvxLRSpaceItem(rSection.GetPageLeft(), rSection.GetPageRight(), 0, 0, RES_LR_SPACE));
527 if (!bIgnoreCols)
528 SetCols(rFormat, rSection, rSection.GetTextAreaWidth());
531 namespace {
532 // Returns corrected (ODF) margin size
533 tools::Long SetBorderDistance(bool bFromEdge, SvxBoxItem& aBox, SvxBoxItemLine eLine, tools::Long nMSMargin)
535 const editeng::SvxBorderLine* pLine = aBox.GetLine(eLine);
536 if (!pLine)
537 return nMSMargin;
538 sal_Int32 nNewMargin = nMSMargin;
539 sal_Int32 nNewDist = aBox.GetDistance(eLine);
540 sal_Int32 nLineWidth = pLine->GetScaledWidth();
542 editeng::BorderDistanceFromWord(bFromEdge, nNewMargin, nNewDist, nLineWidth);
543 aBox.SetDistance(nNewDist, eLine);
545 return nNewMargin;
549 void SwWW8ImplReader::SetPageBorder(SwFrameFormat &rFormat, const wwSection &rSection)
551 if (!IsBorder(rSection.brc))
552 return;
554 SfxItemSet aSet(rFormat.GetAttrSet());
555 short aSizeArray[5]={0};
556 SetFlyBordersShadow(aSet, rSection.brc, &aSizeArray[0]);
557 SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE));
558 SvxULSpaceItem aUL(ItemGet<SvxULSpaceItem>(aSet, RES_UL_SPACE));
559 SvxBoxItem aBox(ItemGet<SvxBoxItem>(aSet, RES_BOX));
560 bool bFromEdge = rSection.maSep.pgbOffsetFrom == 1;
562 aLR.SetLeft(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::LEFT, aLR.GetLeft()));
563 aLR.SetRight(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::RIGHT, aLR.GetRight()));
564 aUL.SetUpper(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::TOP, aUL.GetUpper()));
565 aUL.SetLower(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::BOTTOM, aUL.GetLower()));
567 aSet.Put(aBox);
568 aSet.Put(aLR);
569 aSet.Put(aUL);
570 rFormat.SetFormatAttr(aSet);
573 void wwSectionManager::GetPageULData(const wwSection &rSection,
574 wwSectionManager::wwULSpaceData& rData) const
576 sal_Int32 nWWUp = rSection.maSep.dyaTop;
577 sal_Int32 nWWLo = rSection.maSep.dyaBottom;
578 sal_uInt32 nWWHTop = rSection.maSep.dyaHdrTop;
579 sal_uInt32 nWWFBot = rSection.maSep.dyaHdrBottom;
582 If there is gutter in 97+ and the dop says put it on top then get the
583 gutter distance and set it to the top margin. When we are "two pages
584 in one" the gutter is put at the top of odd pages, and bottom of
585 even pages, something we cannot do. So we will put it on top of all
586 pages, that way the pages are at least the right size.
588 if (!mrReader.m_bVer67 && mrReader.m_xWDop->iGutterPos &&
589 rSection.maSep.fRTLGutter)
591 nWWUp += rSection.maSep.dzaGutter;
594 /* Check whether this section has headers / footers */
595 sal_uInt16 nHeaderMask = WW8_HEADER_EVEN | WW8_HEADER_ODD;
596 sal_uInt16 nFooterMask = WW8_FOOTER_EVEN | WW8_FOOTER_ODD;
597 /* Ignore the presence of a first-page header/footer unless it is enabled */
598 if( rSection.HasTitlePage() )
600 nHeaderMask |= WW8_HEADER_FIRST;
601 nFooterMask |= WW8_FOOTER_FIRST;
603 rData.bHasHeader = (rSection.maSep.grpfIhdt & nHeaderMask) != 0;
604 rData.bHasFooter = (rSection.maSep.grpfIhdt & nFooterMask) != 0;
606 if( rData.bHasHeader )
608 rData.nSwUp = nWWHTop; // Header -> convert
609 // #i19922# - correction:
610 // consider that <nWWUp> can be negative, compare only if it's positive
611 if ( nWWUp > 0 &&
612 o3tl::make_unsigned(abs(nWWUp)) >= nWWHTop )
613 rData.nSwHLo = nWWUp - nWWHTop;
614 else
615 rData.nSwHLo = 0;
617 // #i19922# - minimum page header height is now 1mm
618 // use new constant <cMinHdFtHeight>
619 if (rData.nSwHLo < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
620 rData.nSwHLo = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
622 else // no header -> just use Up as-is
623 rData.nSwUp = std::abs(nWWUp);
625 if( rData.bHasFooter )
627 rData.nSwLo = nWWFBot; // footer -> convert
628 // #i19922# - correction: consider that <nWWLo> can be negative, compare only if it's positive
629 if ( nWWLo > 0 &&
630 o3tl::make_unsigned(abs(nWWLo)) >= nWWFBot )
631 rData.nSwFUp = nWWLo - nWWFBot;
632 else
633 rData.nSwFUp = 0;
635 // #i19922# - minimum page header height is now 1mm
636 // use new constant <cMinHdFtHeight>
637 if (rData.nSwFUp < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
638 rData.nSwFUp = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
640 else // no footer -> just use Lo as-is
641 rData.nSwLo = std::abs(nWWLo);
644 void wwSectionManager::SetPageULSpaceItems(SwFrameFormat &rFormat,
645 wwSectionManager::wwULSpaceData const & rData, const wwSection &rSection)
647 if (rData.bHasHeader) // ... and set Header-Lower
649 // set header height to minimum
650 if (SwFrameFormat* pHdFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat()))
652 SvxULSpaceItem aHdUL(pHdFormat->GetULSpace());
653 if (!rSection.IsFixedHeightHeader()) //normal
655 pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwHLo));
656 // #i19922# - minimum page header height is now 1mm
657 // use new constant <cMinHdFtHeight>
658 aHdUL.SetLower( writer_cast<sal_uInt16>(rData.nSwHLo - cMinHdFtHeight) );
659 pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
660 RES_HEADER_FOOTER_EAT_SPACING, true));
662 else
664 // Hack alert: these calculations are based on
665 // #112727# import negative height headers/footers as floating frames inside fixed height headers/footer
666 // #i48832# - set correct spacing between header and body.
667 const sal_Int32 nHdLowerSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaTop) - rData.nSwUp - rData.nSwHLo));
668 pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwHLo + nHdLowerSpace));
669 aHdUL.SetLower( static_cast< sal_uInt16 >(nHdLowerSpace) );
670 pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
671 RES_HEADER_FOOTER_EAT_SPACING, false));
673 pHdFormat->SetFormatAttr(aHdUL);
677 if (rData.bHasFooter) // ... and set footer-upper
679 if (SwFrameFormat* pFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat()))
681 SvxULSpaceItem aFtUL(pFtFormat->GetULSpace());
682 if (!rSection.IsFixedHeightFooter()) //normal
684 pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwFUp));
685 // #i19922# - minimum page header height is now 1mm
686 // use new constant <cMinHdFtHeight>
687 aFtUL.SetUpper( writer_cast<sal_uInt16>(rData.nSwFUp - cMinHdFtHeight) );
688 pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
689 RES_HEADER_FOOTER_EAT_SPACING, true));
691 else
693 // #i48832# - set correct spacing between footer and body.
694 const sal_Int32 nFtUpperSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaBottom) - rData.nSwLo - rData.nSwFUp));
695 pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwFUp + nFtUpperSpace));
696 aFtUL.SetUpper( static_cast< sal_uInt16 >(nFtUpperSpace) );
697 pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
698 RES_HEADER_FOOTER_EAT_SPACING, false));
700 pFtFormat->SetFormatAttr(aFtUL);
704 SvxULSpaceItem aUL(writer_cast<sal_uInt16>(rData.nSwUp),
705 writer_cast<sal_uInt16>(rData.nSwLo), RES_UL_SPACE);
706 rFormat.SetFormatAttr(aUL);
709 SwSectionFormat *wwSectionManager::InsertSection(
710 SwPaM const & rMyPaM, wwSection &rSection)
712 SwSectionData aSection( SectionType::Content,
713 mrReader.m_rDoc.GetUniqueSectionName() );
715 SfxItemSet aSet( mrReader.m_rDoc.GetAttrPool(), aFrameFormatSetRange );
717 bool bRTLPgn = !maSegments.empty() && maSegments.back().IsBiDi();
718 aSet.Put(SvxFrameDirectionItem(
719 bRTLPgn ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
721 if (2 == mrReader.m_xWDop->fpc)
722 aSet.Put( SwFormatFootnoteAtTextEnd(FTNEND_ATTXTEND));
723 if (0 == mrReader.m_xWDop->epc)
724 aSet.Put( SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
726 aSection.SetProtectFlag(SectionIsProtected(rSection));
728 rSection.mpSection =
729 mrReader.m_rDoc.InsertSwSection( rMyPaM, aSection, nullptr, & aSet );
730 OSL_ENSURE(rSection.mpSection, "section not inserted!");
731 if (!rSection.mpSection)
732 return nullptr;
734 SwPageDesc *pPage = nullptr;
735 auto aIter = std::find_if(maSegments.rbegin(), maSegments.rend(),
736 [](const wwSection& rSegment) { return rSegment.mpPage != nullptr; });
737 if (aIter != maSegments.rend())
738 pPage = aIter->mpPage;
740 OSL_ENSURE(pPage, "no page outside this section!");
742 if (!pPage)
743 pPage = &mrReader.m_rDoc.GetPageDesc(0);
745 SwSectionFormat *pFormat = rSection.mpSection->GetFormat();
746 OSL_ENSURE(pFormat, "impossible");
747 if (!pFormat)
748 return nullptr;
750 SwFrameFormat& rFormat = pPage->GetMaster();
751 const SvxLRSpaceItem& rLR = rFormat.GetLRSpace();
752 tools::Long nPageLeft = rLR.GetLeft();
753 tools::Long nPageRight = rLR.GetRight();
754 tools::Long nSectionLeft = rSection.GetPageLeft() - nPageLeft;
755 tools::Long nSectionRight = rSection.GetPageRight() - nPageRight;
756 if ((nSectionLeft != 0) || (nSectionRight != 0))
758 SvxLRSpaceItem aLR(nSectionLeft, nSectionRight, 0, 0, RES_LR_SPACE);
759 pFormat->SetFormatAttr(aLR);
762 SetCols(*pFormat, rSection, rSection.GetTextAreaWidth());
763 return pFormat;
766 void SwWW8ImplReader::HandleLineNumbering(const wwSection &rSection)
768 // check if Line Numbering must be activated or reset
769 if (!(m_bNewDoc && rSection.maSep.nLnnMod))
770 return;
772 // restart-numbering-mode: 0 per page, 1 per section, 2 never restart
773 bool bRestartLnNumPerSection = (1 == rSection.maSep.lnc);
775 if (m_bNoLnNumYet)
777 SwLineNumberInfo aInfo( m_rDoc.GetLineNumberInfo() );
779 aInfo.SetPaintLineNumbers(true);
781 aInfo.SetRestartEachPage(rSection.maSep.lnc == 0);
783 // A value of 0 (auto) indicates that the application MUST automatically determine positioning.
784 if ( rSection.maSep.dxaLnn )
785 aInfo.SetPosFromLeft(writer_cast<sal_uInt16>(rSection.maSep.dxaLnn));
787 //Paint only for every n line
788 aInfo.SetCountBy(rSection.maSep.nLnnMod);
790 // to be defaulted features ( HARDCODED in MS Word 6,7,8,9 )
791 aInfo.SetCountBlankLines(true);
792 aInfo.SetCountInFlys(false);
793 aInfo.SetPos( LINENUMBER_POS_LEFT );
794 SvxNumberType aNumType; // this sets SVX_NUM_ARABIC per default
795 aInfo.SetNumType( aNumType );
797 m_rDoc.SetLineNumberInfo( aInfo );
798 m_bNoLnNumYet = false;
801 if ((0 < rSection.maSep.lnnMin) || bRestartLnNumPerSection)
803 SwFormatLineNumber aLN;
804 if (const SwFormatLineNumber* pLN
805 = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
807 aLN.SetCountLines( pLN->IsCount() );
809 aLN.SetStartValue(1 + rSection.maSep.lnnMin);
810 NewAttr(aLN);
811 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LINENUMBER);
815 wwSection::wwSection(const SwPosition &rPos) : maStart(rPos.nNode)
816 , mpSection(nullptr)
817 , mpPage(nullptr)
818 , meDir(SvxFrameDirection::Horizontal_LR_TB)
819 , nPgWidth(SvxPaperInfo::GetPaperSize(PAPER_A4).Width())
820 , nPgLeft(MM_250)
821 , nPgRight(MM_250)
822 , mnVerticalAdjustment(drawing::TextVerticalAdjust_TOP)
823 , mnBorders(0)
824 , mbHasFootnote(false)
828 void wwSectionManager::SetNumberingType(const wwSection &rNewSection,
829 SwPageDesc &rPageDesc)
831 // save page number format
832 static const SvxNumType aNumTyp[5] =
834 SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
835 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N
838 SvxNumberType aType;
839 aType.SetNumberingType( aNumTyp[rNewSection.maSep.nfcPgn] );
840 rPageDesc.SetNumType(aType);
843 // CreateSep is called for every section change (even at the start of
844 // the document. CreateSep also creates the pagedesc(s) and
845 // fills it/them with attributes and KF texts.
846 // This has become necessary because the translation of the various
847 // page attributes is interconnected too much.
848 void wwSectionManager::CreateSep(const tools::Long nTextPos)
851 #i1909# section/page breaks should not occur in tables or subpage
852 elements like frames. Word itself ignores them in this case. The bug is
853 more likely that this filter created such documents in the past!
855 if (mrReader.m_nInTable || mrReader.m_bTxbxFlySection || mrReader.InLocalApo())
856 return;
858 WW8PLCFx_SEPX* pSep = mrReader.m_xPlcxMan->GetSepPLCF();
859 OSL_ENSURE(pSep, "impossible!");
860 if (!pSep)
861 return;
863 if (!maSegments.empty() && mrReader.m_pLastAnchorPos && *mrReader.m_pLastAnchorPos == *mrReader.m_pPaM->GetPoint())
865 bool insert = true;
866 SwPaM pam( *mrReader.m_pLastAnchorPos );
867 if( pam.Move(fnMoveBackward, GoInNode))
868 if( SwTextNode* txtNode = pam.GetPoint()->nNode.GetNode().GetTextNode())
869 if( txtNode->Len() == 0 )
870 insert = false;
871 if( insert )
872 mrReader.AppendTextNode(*mrReader.m_pPaM->GetPoint());
875 ww::WordVersion eVer = mrReader.GetFib().GetFIBVersion();
877 // M.M. Create a linked section if the WkbPLCF
878 // has an entry for one at this cp
879 WW8PLCFspecial* pWkb = mrReader.m_xPlcxMan->GetWkbPLCF();
880 if (pWkb && pWkb->SeekPosExact(nTextPos) &&
881 pWkb->Where() == nTextPos)
883 void* pData;
884 WW8_CP nTest;
885 bool bSuccess = pWkb->Get(nTest, pData);
886 if (!bSuccess)
887 return;
888 OUString sSectionName = mrReader.m_aLinkStringMap[SVBT16ToUInt16( static_cast<WW8_WKB*>(pData)->nLinkId) ];
889 sSectionName = mrReader.ConvertFFileName(sSectionName);
890 SwSectionData aSection(SectionType::FileLink, sSectionName);
891 aSection.SetLinkFileName( sSectionName );
892 aSection.SetProtectFlag(true);
893 // #i19922# - improvement: return value of method <Insert> not used.
894 mrReader.m_rDoc.InsertSwSection(*mrReader.m_pPaM, aSection, nullptr, nullptr, false);
897 wwSection aLastSection(*mrReader.m_pPaM->GetPoint());
898 if (!maSegments.empty())
899 aLastSection = maSegments.back();
901 //Here
902 sal_uInt16 nLIdx = ( ( static_cast<sal_uInt16>(mrReader.m_xWwFib->m_lid) & 0xff ) == 0x9 ) ? 1 : 0;
904 //BEGIN read section values
905 wwSection aNewSection(*mrReader.m_pPaM->GetPoint());
907 static const sal_uInt16 aVer2Ids0[] =
909 /*sprmSBkc*/ 117,
910 /*sprmSFTitlePage*/ 118,
911 /*sprmSNfcPgn*/ 122,
912 /*sprmSCcolumns*/ 119,
913 /*sprmSDxaColumns*/ 120,
914 /*sprmSLBetween*/ 133
917 static const sal_uInt16 aVer67Ids0[] =
919 NS_sprm::v6::sprmSBkc,
920 NS_sprm::v6::sprmSFTitlePage,
921 NS_sprm::v6::sprmSNfcPgn,
922 NS_sprm::v6::sprmSCcolumns,
923 NS_sprm::v6::sprmSDxaColumns,
924 NS_sprm::v6::sprmSLBetween
927 static const sal_uInt16 aVer8Ids0[] =
929 NS_sprm::SBkc::val,
930 NS_sprm::SFTitlePage::val,
931 NS_sprm::SNfcPgn::val,
932 NS_sprm::SCcolumns::val,
933 NS_sprm::SDxaColumns::val,
934 NS_sprm::SLBetween::val
937 const sal_uInt16* pIds = eVer <= ww::eWW2 ? aVer2Ids0 : eVer <= ww::eWW7 ? aVer67Ids0 : aVer8Ids0;
939 SprmResult aRes = pSep->HasSprm(pIds[0]);
940 const sal_uInt8* pSprmBkc = aRes.pSprm;
941 if (!maSegments.empty())
943 // Type of break: break codes are:
944 // 0 No break
945 // 1 New column
946 // 2 New page
947 // 3 Even page
948 // 4 Odd page
949 if (pSprmBkc && aRes.nRemainingData >= 1)
950 aNewSection.maSep.bkc = *pSprmBkc;
953 // Has a table page
954 aNewSection.maSep.fTitlePage =
955 sal_uInt8(0 != ReadBSprm( pSep, pIds[1], 0 ));
957 // sprmSNfcPgn
958 aNewSection.maSep.nfcPgn = ReadBSprm( pSep, pIds[2], 0 );
959 if (aNewSection.maSep.nfcPgn > 4)
960 aNewSection.maSep.nfcPgn = 0;
962 aNewSection.maSep.fUnlocked = eVer > ww::eWW2 ? ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFProtected : NS_sprm::SFProtected::val), 0 ) : 0;
964 // sprmSFBiDi
965 aNewSection.maSep.fBiDi = eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFBiDi::val, 0) : 0;
967 // Reading section property sprmSCcolumns - one less than the number of columns in the section.
968 // It must be less than MAX_NO_OF_SEP_COLUMNS according the WW8 specification.
969 aNewSection.maSep.ccolM1 = ReadSprm(pSep, pIds[3], 0 );
970 if ( aNewSection.maSep.ccolM1 >= MAX_NO_OF_SEP_COLUMNS )
972 // clip to max
973 aNewSection.maSep.ccolM1 = MAX_NO_OF_SEP_COLUMNS-1;
976 //sprmSDxaColumns - default distance 1.25 cm
977 aNewSection.maSep.dxaColumns = ReadUSprm( pSep, pIds[4], 708 );
979 // sprmSLBetween
980 aNewSection.maSep.fLBetween = ReadBSprm(pSep, pIds[5], 0 );
982 if (eVer >= ww::eWW6)
984 // sprmSFEvenlySpaced
985 aNewSection.maSep.fEvenlySpaced =
986 sal_uInt8(ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFEvenlySpaced : NS_sprm::SFEvenlySpaced::val), 1) != 0);
988 if (aNewSection.maSep.ccolM1 > 0 && !aNewSection.maSep.fEvenlySpaced)
990 int nColumnDataIdx = 0;
991 aNewSection.maSep.rgdxaColumnWidthSpacing[nColumnDataIdx] = 0;
993 const sal_uInt16 nColumnWidthSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColWidth : NS_sprm::SDxaColWidth::val);
994 const sal_uInt16 nColumnSpacingSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColSpacing : NS_sprm::SDxaColSpacing::val);
995 const sal_uInt8 nColumnCount = static_cast< sal_uInt8 >(aNewSection.maSep.ccolM1 + 1);
996 for ( sal_uInt8 nColumn = 0; nColumn < nColumnCount; ++nColumn )
998 //sprmSDxaColWidth
999 SprmResult aSWRes = pSep->HasSprm(nColumnWidthSprmId, nColumn);
1000 const sal_uInt8* pSW = aSWRes.pSprm;
1002 OSL_ENSURE( pSW, "+Sprm 136 (resp. 0xF203) (ColWidth) missing" );
1003 sal_uInt16 nWidth = (pSW && aSWRes.nRemainingData >= 3) ? SVBT16ToUInt16(pSW + 1) : 1440;
1005 aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
1007 if ( nColumn < nColumnCount - 1 )
1009 //sprmSDxaColSpacing
1010 SprmResult aSDRes = pSep->HasSprm(nColumnSpacingSprmId, nColumn);
1011 const sal_uInt8* pSD = aSDRes.pSprm;
1013 OSL_ENSURE( pSD, "+Sprm 137 (resp. 0xF204) (Colspacing) missing" );
1014 if (pSD && aSDRes.nRemainingData >= 3)
1016 nWidth = SVBT16ToUInt16(pSD + 1);
1017 aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
1024 static const sal_uInt16 aVer2Ids1[] =
1026 /*sprmSBOrientation*/ 137,
1027 /*sprmSXaPage*/ 139,
1028 /*sprmSYaPage*/ 140,
1029 /*sprmSDxaLeft*/ 141,
1030 /*sprmSDxaRight*/ 142,
1031 /*sprmSDzaGutter*/ 145,
1032 /*sprmSFPgnRestart*/ 125,
1033 /*sprmSPgnStart*/ 136,
1034 /*sprmSDmBinFirst*/ 115,
1035 /*sprmSDmBinOther*/ 116
1038 static const sal_uInt16 aVer67Ids1[] =
1040 NS_sprm::v6::sprmSBOrientation,
1041 NS_sprm::v6::sprmSXaPage,
1042 NS_sprm::v6::sprmSYaPage,
1043 NS_sprm::v6::sprmSDxaLeft,
1044 NS_sprm::v6::sprmSDxaRight,
1045 NS_sprm::v6::sprmSDzaGutter,
1046 NS_sprm::v6::sprmSFPgnRestart,
1047 NS_sprm::v6::sprmSPgnStart,
1048 NS_sprm::v6::sprmSDmBinFirst,
1049 NS_sprm::v6::sprmSDmBinOther
1052 static const sal_uInt16 aVer8Ids1[] =
1054 NS_sprm::SBOrientation::val,
1055 NS_sprm::SXaPage::val,
1056 NS_sprm::SYaPage::val,
1057 NS_sprm::SDxaLeft::val,
1058 NS_sprm::SDxaRight::val,
1059 NS_sprm::SDzaGutter::val,
1060 NS_sprm::SFPgnRestart::val,
1061 NS_sprm::SPgnStart97::val,
1062 NS_sprm::SDmBinFirst::val,
1063 NS_sprm::SDmBinOther::val
1066 pIds = eVer <= ww::eWW2 ? aVer2Ids1 : eVer <= ww::eWW7 ? aVer67Ids1 : aVer8Ids1;
1068 // 1. orientation
1069 aNewSection.maSep.dmOrientPage = ReadBSprm(pSep, pIds[0], 0);
1071 // 2. paper size
1072 aNewSection.maSep.xaPage = ReadUSprm(pSep, pIds[1], lLetterWidth);
1073 aNewSection.nPgWidth = SvxPaperInfo::GetSloppyPaperDimension(aNewSection.maSep.xaPage);
1075 aNewSection.maSep.yaPage = ReadUSprm(pSep, pIds[2], lLetterHeight);
1077 // 3. LR borders
1078 static const sal_uInt16 nLef[] = { MM_250, 1800 };
1079 static const sal_uInt16 nRig[] = { MM_250, 1800 };
1081 aNewSection.maSep.dxaLeft = ReadUSprm( pSep, pIds[3], nLef[nLIdx]);
1082 aNewSection.maSep.dxaRight = ReadUSprm( pSep, pIds[4], nRig[nLIdx]);
1084 // 2pages in 1sheet hackery ?
1085 // #i31806# but only swap if 2page in 1sheet is enabled.
1086 // it's not clear if dmOrientPage is the correct member to
1087 // decide on this.
1088 if(mrReader.m_xWDop->doptypography.m_f2on1 &&
1089 aNewSection.maSep.dmOrientPage == 2)
1090 std::swap(aNewSection.maSep.dxaLeft, aNewSection.maSep.dxaRight);
1092 aNewSection.maSep.dzaGutter = ReadUSprm( pSep, pIds[5], 0);
1094 aNewSection.maSep.fRTLGutter = static_cast< sal_uInt8 >(eVer >= ww::eWW8 ? ReadUSprm( pSep, NS_sprm::SFRTLGutter::val, 0 ) : 0);
1096 // Page Number Restarts - sprmSFPgnRestart
1097 aNewSection.maSep.fPgnRestart = ReadBSprm(pSep, pIds[6], 0);
1099 aNewSection.maSep.pgnStart = ReadUSprm( pSep, pIds[7], 0 );
1101 // if the document's first page number is unspecified, but it starts with an even page break,
1102 // then set the first page number to two
1103 if ( maSegments.empty() && !aNewSection.maSep.fPgnRestart && pSprmBkc && *pSprmBkc == 3 )
1105 aNewSection.maSep.pgnStart = 2;
1106 aNewSection.maSep.fPgnRestart = 1;
1109 if (eVer >= ww::eWW6)
1111 aRes = pSep->HasSprm(eVer <= ww::eWW7 ? NS_sprm::v6::sprmSiHeadingPgn : NS_sprm::SiHeadingPgn::val);
1112 if (aRes.pSprm && aRes.nRemainingData >= 1)
1113 aNewSection.maSep.iHeadingPgn = *aRes.pSprm;
1115 aRes = pSep->HasSprm(eVer <= ww::eWW7 ? NS_sprm::v6::sprmSScnsPgn : NS_sprm::ScnsPgn::val);
1116 if (aRes.pSprm && aRes.nRemainingData >= 1)
1117 aNewSection.maSep.cnsPgn = *aRes.pSprm;
1120 aRes = pSep->HasSprm(pIds[8]);
1121 const sal_uInt8* pSprmSDmBinFirst = aRes.pSprm;
1122 if (pSprmSDmBinFirst && aRes.nRemainingData >= 1)
1123 aNewSection.maSep.dmBinFirst = *pSprmSDmBinFirst;
1125 aRes = pSep->HasSprm(pIds[9]);
1126 const sal_uInt8* pSprmSDmBinOther = aRes.pSprm;
1127 if (pSprmSDmBinOther && aRes.nRemainingData >= 1)
1128 aNewSection.maSep.dmBinOther = *pSprmSDmBinOther;
1130 static const sal_uInt16 nTop[] = { MM_250, 1440 };
1131 static const sal_uInt16 nBot[] = { MM_200, 1440 };
1133 static const sal_uInt16 aVer2Ids2[] =
1135 /*sprmSDyaTop*/ 143,
1136 /*sprmSDyaBottom*/ 144,
1137 /*sprmSDyaHdrTop*/ 131,
1138 /*sprmSDyaHdrBottom*/ 132,
1139 /*sprmSNLnnMod*/ 129,
1140 /*sprmSLnc*/ 127,
1141 /*sprmSDxaLnn*/ 130,
1142 /*sprmSLnnMin*/ 135
1145 static const sal_uInt16 aVer67Ids2[] =
1147 NS_sprm::v6::sprmSDyaTop,
1148 NS_sprm::v6::sprmSDyaBottom,
1149 NS_sprm::v6::sprmSDyaHdrTop,
1150 NS_sprm::v6::sprmSDyaHdrBottom,
1151 NS_sprm::v6::sprmSNLnnMod,
1152 NS_sprm::v6::sprmSLnc,
1153 NS_sprm::v6::sprmSDxaLnn,
1154 NS_sprm::v6::sprmSLnnMin
1156 static const sal_uInt16 aVer8Ids2[] =
1158 NS_sprm::SDyaTop::val,
1159 NS_sprm::SDyaBottom::val,
1160 NS_sprm::SDyaHdrTop::val,
1161 NS_sprm::SDyaHdrBottom::val,
1162 NS_sprm::SNLnnMod::val,
1163 NS_sprm::SLnc::val,
1164 NS_sprm::SDxaLnn::val,
1165 NS_sprm::SLnnMin::val
1168 pIds = eVer <= ww::eWW2 ? aVer2Ids2 : eVer <= ww::eWW7 ? aVer67Ids2 : aVer8Ids2;
1170 aNewSection.maSep.dyaTop = ReadSprm( pSep, pIds[0], nTop[nLIdx] );
1171 aNewSection.maSep.dyaBottom = ReadSprm( pSep, pIds[1], nBot[nLIdx] );
1172 aNewSection.maSep.dyaHdrTop = ReadUSprm( pSep, pIds[2], 720 );
1173 aNewSection.maSep.dyaHdrBottom = ReadUSprm( pSep, pIds[3], 720 );
1175 if (eVer >= ww::eWW8)
1177 aNewSection.maSep.wTextFlow = ReadUSprm(pSep, NS_sprm::STextFlow::val, 0);
1178 aNewSection.maSep.clm = ReadUSprm( pSep, NS_sprm::SClm::val, 0 );
1179 aNewSection.maSep.dyaLinePitch = ReadUSprm(pSep, NS_sprm::SDyaLinePitch::val, 360);
1180 aRes = pSep->HasSprm(NS_sprm::SDxtCharSpace::val);
1181 if (aRes.pSprm && aRes.nRemainingData >= 4)
1182 aNewSection.maSep.dxtCharSpace = SVBT32ToUInt32(aRes.pSprm);
1184 //sprmSPgbProp
1185 sal_uInt16 pgbProp = ReadSprm( pSep, NS_sprm::SPgbProp::val, 0 );
1186 aNewSection.maSep.pgbApplyTo = pgbProp & 0x0007;
1187 aNewSection.maSep.pgbPageDepth = (pgbProp & 0x0018) >> 3;
1188 aNewSection.maSep.pgbOffsetFrom = (pgbProp & 0x00E0) >> 5;
1190 aNewSection.mnBorders = ::lcl_ReadBorders(false, aNewSection.brc, nullptr, nullptr, pSep);
1193 // check if Line Numbering must be activated or reset
1194 SprmResult aSprmSNLnnMod = pSep->HasSprm(pIds[4]);
1195 if (aSprmSNLnnMod.pSprm && aSprmSNLnnMod.nRemainingData >= 1)
1196 aNewSection.maSep.nLnnMod = *aSprmSNLnnMod.pSprm;
1198 SprmResult aSprmSLnc = pSep->HasSprm(pIds[5]);
1199 if (aSprmSLnc.pSprm && aSprmSLnc.nRemainingData >= 1)
1200 aNewSection.maSep.lnc = *aSprmSLnc.pSprm;
1202 SprmResult aSprmSDxaLnn = pSep->HasSprm(pIds[6]);
1203 if (aSprmSDxaLnn.pSprm && aSprmSDxaLnn.nRemainingData >= 2)
1204 aNewSection.maSep.dxaLnn = SVBT16ToUInt16(aSprmSDxaLnn.pSprm);
1206 SprmResult aSprmSLnnMin = pSep->HasSprm(pIds[7]);
1207 if (aSprmSLnnMin.pSprm && aSprmSLnnMin.nRemainingData >= 1)
1208 aNewSection.maSep.lnnMin = *aSprmSLnnMin.pSprm;
1210 if (eVer <= ww::eWW7)
1211 aNewSection.maSep.grpfIhdt = ReadBSprm(pSep, eVer <= ww::eWW2 ? 128 : 153, 0);
1212 else if (mrReader.m_xHdFt)
1214 aNewSection.maSep.grpfIhdt = WW8_HEADER_ODD | WW8_FOOTER_ODD
1215 | WW8_HEADER_FIRST | WW8_FOOTER_FIRST;
1217 // It is possible for a first page header to be provided
1218 // for this section, but not actually shown in this section. In this
1219 // case (aNewSection.maSep.grpfIhdt & WW8_HEADER_FIRST) will be nonzero
1220 // but aNewSection.HasTitlePage() will be false.
1221 // Likewise for first page footer.
1223 if (mrReader.m_xWDop->fFacingPages)
1224 aNewSection.maSep.grpfIhdt |= WW8_HEADER_EVEN | WW8_FOOTER_EVEN;
1226 //See if we have a header or footer for each enabled possibility
1227 //if we do not then we inherit the previous sections header/footer,
1228 for (int nI = 0, nMask = 1; nI < 6; ++nI, nMask <<= 1)
1230 if (aNewSection.maSep.grpfIhdt & nMask)
1232 WW8_CP nStart, nLen;
1233 mrReader.m_xHdFt->GetTextPosExact( static_cast< short >(nI + ( maSegments.size() + 1) * 6), nStart, nLen);
1234 //No header or footer, inherit previous one, or set to zero
1235 //if no previous one
1236 if (!nLen)
1238 if (
1239 maSegments.empty() ||
1240 !(maSegments.back().maSep.grpfIhdt & nMask)
1243 aNewSection.maSep.grpfIhdt &= ~nMask;
1250 SetLeftRight(aNewSection);
1251 //END read section values
1253 if (eVer >= ww::eWW8)
1254 aNewSection.SetDirection();
1256 mrReader.HandleLineNumbering(aNewSection);
1257 maSegments.push_back(aNewSection);
1260 void SwWW8ImplReader::CopyPageDescHdFt(const SwPageDesc* pOrgPageDesc,
1261 SwPageDesc* pNewPageDesc, sal_uInt8 nCode )
1263 // copy odd header content section
1264 if( nCode & WW8_HEADER_ODD )
1266 m_rDoc.CopyHeader(pOrgPageDesc->GetMaster(),
1267 pNewPageDesc->GetMaster() );
1269 // copy odd footer content section
1270 if( nCode & WW8_FOOTER_ODD )
1272 m_rDoc.CopyFooter(pOrgPageDesc->GetMaster(),
1273 pNewPageDesc->GetMaster());
1275 // copy even header content section
1276 if( nCode & WW8_HEADER_EVEN )
1278 m_rDoc.CopyHeader(pOrgPageDesc->GetLeft(),
1279 pNewPageDesc->GetLeft());
1281 // copy even footer content section
1282 if( nCode & WW8_FOOTER_EVEN )
1284 m_rDoc.CopyFooter(pOrgPageDesc->GetLeft(),
1285 pNewPageDesc->GetLeft());
1287 // copy first page header content section
1288 if( nCode & WW8_HEADER_FIRST )
1290 m_rDoc.CopyHeader(pOrgPageDesc->GetFirstMaster(),
1291 pNewPageDesc->GetFirstMaster());
1293 // copy first page footer content section
1294 if( nCode & WW8_FOOTER_FIRST )
1296 m_rDoc.CopyFooter(pOrgPageDesc->GetFirstMaster(),
1297 pNewPageDesc->GetFirstMaster());
1301 // helper functions for graphics, Apos and tables
1303 // Read BoRder Control structure
1304 // nBrcVer should be set to the version of the BRC record being read (6, 8 or 9)
1305 // This will be converted to the latest format (9).
1306 static bool SetWW8_BRC(int nBrcVer, WW8_BRCVer9& rVar, const sal_uInt8* pS, size_t nLen)
1309 if( pS )
1311 if (nBrcVer == 9 && nLen >= sizeof(WW8_BRCVer9))
1312 rVar = *reinterpret_cast<const WW8_BRCVer9*>(pS);
1313 else if (nBrcVer == 8 && nLen >= sizeof(WW8_BRC))
1314 rVar = WW8_BRCVer9(*reinterpret_cast<const WW8_BRC*>(pS));
1315 else if (nLen >= sizeof(WW8_BRCVer6)) // nBrcVer == 6
1316 rVar = WW8_BRCVer9(WW8_BRC(*reinterpret_cast<const WW8_BRCVer6*>(pS)));
1319 return nullptr != pS;
1322 static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
1323 const WW8RStyle* pSty, const WW8PLCFx_SEPX* pSep)
1326 //returns a sal_uInt8 filled with a bit for each position that had a sprm
1327 //setting that border
1329 sal_uInt8 nBorder = 0;
1330 if( pSep )
1332 if( !bVer67 )
1334 SprmResult a8Sprm[4];
1335 if (pSep->Find4Sprms(
1336 NS_sprm::SBrcTop80::val, NS_sprm::SBrcLeft80::val,
1337 NS_sprm::SBrcBottom80::val, NS_sprm::SBrcRight80::val,
1338 a8Sprm[0], a8Sprm[1], a8Sprm[2], a8Sprm[3]))
1340 for( int i = 0; i < 4; ++i )
1341 nBorder |= int(SetWW8_BRC(8, brc[i], a8Sprm[i].pSprm, a8Sprm[i].nRemainingData))<<i;
1344 // Version 9 BRCs if present will override version 8
1345 SprmResult a9Sprm[4];
1346 if (pSep->Find4Sprms(
1347 NS_sprm::SBrcTop::val, NS_sprm::SBrcLeft::val,
1348 NS_sprm::SBrcBottom::val, NS_sprm::SBrcRight::val,
1349 a9Sprm[0], a9Sprm[1], a9Sprm[2], a9Sprm[3]))
1351 for( int i = 0; i < 4; ++i )
1352 nBorder |= int(SetWW8_BRC(9, brc[i], a9Sprm[i].pSprm, a9Sprm[i].nRemainingData))<<i;
1356 else
1359 static const sal_uInt16 aVer67Ids[5] = {
1360 NS_sprm::v6::sprmPBrcTop,
1361 NS_sprm::v6::sprmPBrcLeft,
1362 NS_sprm::v6::sprmPBrcBottom,
1363 NS_sprm::v6::sprmPBrcRight,
1364 NS_sprm::v6::sprmPBrcBetween
1367 static const sal_uInt16 aVer8Ids[5] = {
1368 NS_sprm::PBrcTop80::val,
1369 NS_sprm::PBrcLeft80::val,
1370 NS_sprm::PBrcBottom80::val,
1371 NS_sprm::PBrcRight80::val,
1372 NS_sprm::PBrcBetween80::val
1375 static const sal_uInt16 aVer9Ids[5] = {
1376 NS_sprm::PBrcTop::val,
1377 NS_sprm::PBrcLeft::val,
1378 NS_sprm::PBrcBottom::val,
1379 NS_sprm::PBrcRight::val,
1380 NS_sprm::PBrcBetween::val
1383 if( pPap )
1385 if (bVer67)
1387 for( int i = 0; i < 5; ++i )
1389 SprmResult aRes(pPap->HasSprm(aVer67Ids[i]));
1390 nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1393 else
1395 for( int i = 0; i < 5; ++i )
1397 SprmResult aRes(pPap->HasSprm(aVer8Ids[i]));
1398 nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1400 // Version 9 BRCs if present will override version 8
1401 for( int i = 0; i < 5; ++i )
1403 SprmResult aRes(pPap->HasSprm(aVer9Ids[i]));
1404 nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1408 else if( pSty )
1410 if (bVer67)
1412 for( int i = 0; i < 5; ++i )
1414 SprmResult aRes(pSty->HasParaSprm(aVer67Ids[i]));
1415 nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1418 else
1420 for( int i = 0; i < 5; ++i )
1422 SprmResult aRes(pSty->HasParaSprm(aVer8Ids[i]));
1423 nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1425 // Version 9 BRCs if present will override version 8
1426 for( int i = 0; i < 5; ++i )
1428 SprmResult aRes(pSty->HasParaSprm(aVer9Ids[i]));
1429 nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
1433 else {
1434 OSL_ENSURE( pSty || pPap, "WW8PLCFx_Cp_FKP and WW8RStyle "
1435 "and WW8PLCFx_SEPX is 0" );
1439 return nBorder;
1442 static void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace,
1443 sal_uInt32 cv, short nIdx, SvxBoxItemLine nOOIndex, sal_uInt16 nWWIndex,
1444 short *pSize)
1446 // LO cannot handle outset/inset (new in WW9 BRC) so fall back same as WW8
1447 if ( nIdx == 0x1A || nIdx == 0x1B )
1449 nIdx = (nIdx == 0x1A) ? 0x12 : 0x11;
1450 cv = 0xc0c0c0;
1453 SvxBorderLineStyle const eStyle(
1454 ::editeng::ConvertBorderStyleFromWord(nIdx));
1456 ::editeng::SvxBorderLine aLine;
1457 aLine.SetBorderLineStyle( eStyle );
1458 double const fConverted( (SvxBorderLineStyle::NONE == eStyle) ? 0.0 :
1459 ::editeng::ConvertBorderWidthFromWord(eStyle, nLineThickness, nIdx));
1460 aLine.SetWidth(fConverted);
1462 //No AUTO for borders as yet, so if AUTO, use BLACK
1463 Color col = (cv==0xff000000) ? COL_BLACK : msfilter::util::BGRToRGB(cv);
1465 aLine.SetColor(col);
1467 if (pSize)
1468 pSize[nWWIndex] = fConverted + nSpace;
1470 rBox.SetLine(&aLine, nOOIndex);
1471 rBox.SetDistance(nSpace, nOOIndex);
1475 static void Set1Border(SvxBoxItem &rBox, const WW8_BRCVer9& rBor, SvxBoxItemLine nOOIndex,
1476 sal_uInt16 nWWIndex, short *pSize, const bool bIgnoreSpace)
1478 short nSpace;
1479 short nLineThickness = rBor.DetermineBorderProperties(&nSpace);
1481 GetLineIndex(rBox, nLineThickness, bIgnoreSpace ? 0 : nSpace,
1482 rBor.cv(), rBor.brcType(), nOOIndex, nWWIndex, pSize );
1486 static bool lcl_IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn = false)
1488 return pbrc[WW8_TOP ].brcType() || // brcType != 0
1489 pbrc[WW8_LEFT ].brcType() ||
1490 pbrc[WW8_BOT ].brcType() ||
1491 pbrc[WW8_RIGHT].brcType() ||
1492 (bChkBtwn && pbrc[WW8_BETW ].brcType());
1495 bool SwWW8ImplReader::IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn)
1497 return lcl_IsBorder(pbrc, bChkBtwn);
1500 bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRCVer9* pbrc,
1501 short *pSizeArray, sal_uInt8 nSetBorders)
1503 bool bChange = false;
1504 static const std::pair<sal_uInt16, SvxBoxItemLine> aIdArr[] =
1506 { WW8_TOP, SvxBoxItemLine::TOP },
1507 { WW8_LEFT, SvxBoxItemLine::LEFT },
1508 { WW8_RIGHT, SvxBoxItemLine::RIGHT },
1509 { WW8_BOT, SvxBoxItemLine::BOTTOM },
1510 { WW8_BETW, SvxBoxItemLine::BOTTOM }
1513 for( int i = 0; i < 4; ++i )
1515 // filter out the invalid borders
1516 const WW8_BRCVer9& rB = pbrc[ aIdArr[ i ].first ];
1517 if( !rB.isNil() && rB.brcType() )
1519 Set1Border(rBox, rB, aIdArr[i].second, aIdArr[i].first, pSizeArray, false);
1520 bChange = true;
1522 else if ( nSetBorders & (1 << aIdArr[i].first) )
1525 ##826##, ##653##
1527 If a style has borders set,and the para attributes attempt remove
1528 the borders, then this is perfectly acceptable, so we shouldn't
1529 ignore this blank entry
1531 nSetBorders has a bit set for each location that a sprm set a
1532 border, so with a sprm set, but no border, then disable the
1533 appropriate border
1535 rBox.SetLine( nullptr, aIdArr[ i ].second );
1538 return bChange;
1541 bool SwWW8ImplReader::SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
1542 const WW8_BRCVer9& aRightBrc)
1544 bool bRet = aRightBrc.fShadow() && pSizeArray && pSizeArray[WW8_RIGHT];
1545 if (bRet)
1547 rShadow.SetColor(COL_BLACK);
1548 //i120718
1549 short nVal = aRightBrc.DetermineBorderProperties();
1550 //End
1551 if (nVal < 0x10)
1552 nVal = 0x10;
1553 rShadow.SetWidth(nVal);
1554 rShadow.SetLocation(SvxShadowLocation::BottomRight);
1555 bRet = true;
1557 return bRet;
1560 void SwWW8ImplReader::GetBorderDistance(const WW8_BRCVer9* pbrc,
1561 tools::Rectangle& rInnerDist)
1563 rInnerDist = tools::Rectangle( pbrc[ 1 ].dptSpace() * 20,
1564 pbrc[ 0 ].dptSpace() * 20,
1565 pbrc[ 3 ].dptSpace() * 20,
1566 pbrc[ 2 ].dptSpace() * 20 );
1569 bool SwWW8ImplReader::SetFlyBordersShadow(SfxItemSet& rFlySet,
1570 const WW8_BRCVer9 *pbrc, short *pSizeArray)
1572 bool bShadowed = false;
1573 if (IsBorder(pbrc))
1575 SvxBoxItem aBox( RES_BOX );
1576 SetBorder(aBox, pbrc, pSizeArray);
1578 rFlySet.Put( aBox );
1580 // fShadow
1581 SvxShadowItem aShadow( RES_SHADOW );
1582 if( SetShadow( aShadow, pSizeArray, pbrc[WW8_RIGHT] ))
1584 bShadowed = true;
1585 rFlySet.Put( aShadow );
1588 return bShadowed;
1591 // APOs
1593 // for computing the minimal FrameSize
1594 #define MAX_BORDER_SIZE 210 // max. size of border
1595 #define MAX_EMPTY_BORDER 10 // for off-by-one errors, at least 1
1597 static void FlySecur1(short& rSize, const bool bBorder)
1599 short nMin = MINFLY +
1600 (bBorder ? MAX_BORDER_SIZE : MAX_EMPTY_BORDER);
1602 if ( rSize < nMin )
1603 rSize = nMin;
1606 static bool SetValSprm( sal_Int16* pVar, WW8PLCFx_Cp_FKP* pPap, sal_uInt16 nId )
1608 SprmResult aS = pPap->HasSprm(nId);
1609 if (aS.pSprm && aS.nRemainingData >= 2)
1610 *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
1611 return aS.pSprm != nullptr;
1614 static bool SetValSprm( sal_Int16* pVar, const WW8RStyle* pStyle, sal_uInt16 nId )
1616 SprmResult aS = pStyle->HasParaSprm(nId);
1617 if (aS.pSprm && aS.nRemainingData >= 2)
1618 *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
1619 return aS.pSprm != nullptr;
1623 #i1930 revealed that sprm 0x360D (sprmTPc) as used in tables can affect the frame
1624 around the table. Its full structure is not fully understood as yet.
1626 void WW8FlyPara::ApplyTabPos(const WW8_TablePos *pTabPos)
1628 if (pTabPos)
1630 nSp26 = pTabPos->nSp26;
1631 nSp27 = pTabPos->nSp27;
1632 nSp29 = pTabPos->nSp29;
1633 nLeMgn = pTabPos->nLeMgn;
1634 nRiMgn = pTabPos->nRiMgn;
1635 nUpMgn = pTabPos->nUpMgn;
1636 nLoMgn = pTabPos->nLoMgn;
1637 nSp37 = pTabPos->nSp37;
1641 WW8FlyPara::WW8FlyPara(bool bIsVer67, const WW8FlyPara* pSrc /* = 0 */)
1643 if ( pSrc )
1644 memcpy( this, pSrc, sizeof( WW8FlyPara ) ); // Copy-Ctor
1645 else
1647 nSp26 = 0;
1648 nSp27 = 0;
1649 nSp45 = 0;
1650 nSp28 = 0;
1651 nLeMgn = 0;
1652 nRiMgn = 0;
1653 nUpMgn = 0;
1654 nLoMgn = 0;
1655 nSp29 = 0;
1656 nSp37 = 2; // Default: wrapping
1657 bBorderLines = false;
1658 bGrafApo = false;
1659 mbVertSet = false;
1661 bVer67 = bIsVer67;
1664 bool WW8FlyPara::operator==(const WW8FlyPara& rSrc) const
1667 Compare the parts that word seems to compare for equivalence.
1668 Interestingly being autoheight or absolute height (the & 0x7fff) doesn't
1669 matter to word
1671 return
1673 (nSp26 == rSrc.nSp26) &&
1674 (nSp27 == rSrc.nSp27) &&
1675 ((nSp45 & 0x7fff) == (rSrc.nSp45 & 0x7fff)) &&
1676 (nSp28 == rSrc.nSp28) &&
1677 (nLeMgn == rSrc.nLeMgn) &&
1678 (nRiMgn == rSrc.nRiMgn) &&
1679 (nUpMgn == rSrc.nUpMgn) &&
1680 (nLoMgn == rSrc.nLoMgn) &&
1681 (nSp29 == rSrc.nSp29) &&
1682 (nSp37 == rSrc.nSp37)
1686 // Read for normal text
1687 void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8PLCFx_Cp_FKP* pPap)
1689 if( bVer67 )
1691 SetValSprm( &nSp26, pPap, 26 ); // X-position //sprmPDxaAbs
1692 //set in me or in parent style
1693 mbVertSet |= SetValSprm( &nSp27, pPap, 27 ); // Y-position //sprmPDyaAbs
1694 SetValSprm( &nSp45, pPap, 45 ); // height //sprmPWHeightAbs
1695 SetValSprm( &nSp28, pPap, 28 ); // width //sprmPDxaWidth
1696 SetValSprm( &nLeMgn, pPap, 49 ); // L-border //sprmPDxaFromText
1697 SetValSprm( &nRiMgn, pPap, 49 ); // R-border //sprmPDxaFromText
1698 SetValSprm( &nUpMgn, pPap, 48 ); // U-border //sprmPDyaFromText
1699 SetValSprm( &nLoMgn, pPap, 48 ); // D-border //sprmPDyaFromText
1701 SprmResult aS = pPap->HasSprm(NS_sprm::v6::sprmPWr);
1702 if (aS.pSprm && aS.nRemainingData >= 1)
1703 nSp37 = *aS.pSprm;
1705 else
1707 SetValSprm( &nSp26, pPap, NS_sprm::PDxaAbs::val ); // X-position
1708 //set in me or in parent style
1709 mbVertSet |= SetValSprm( &nSp27, pPap, NS_sprm::PDyaAbs::val ); // Y-position
1710 SetValSprm( &nSp45, pPap, NS_sprm::PWHeightAbs::val ); // height
1711 SetValSprm( &nSp28, pPap, NS_sprm::PDxaWidth::val ); // width
1712 SetValSprm( &nLeMgn, pPap, NS_sprm::PDxaFromText::val ); // L-border
1713 SetValSprm( &nRiMgn, pPap, NS_sprm::PDxaFromText::val ); // R-border
1714 SetValSprm( &nUpMgn, pPap, NS_sprm::PDyaFromText::val ); // U-border
1715 SetValSprm( &nLoMgn, pPap, NS_sprm::PDyaFromText::val ); // D-border
1717 SprmResult aS = pPap->HasSprm(NS_sprm::PWr::val); // wrapping
1718 if (aS.pSprm && aS.nRemainingData >= 1)
1719 nSp37 = *aS.pSprm;
1722 if( ::lcl_ReadBorders( bVer67, brc, pPap )) // borders
1723 bBorderLines = ::lcl_IsBorder( brc );
1726 #i8798#
1727 Appears that with no dyaAbs set then the actual vert anchoring set is
1728 ignored and we remain relative to text, so if that is the case we are 0
1729 from para anchor, so we update the frame to have explicitly this type of
1730 anchoring
1732 if (!mbVertSet)
1733 nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1734 else
1735 nSp29 = nOrigSp29;
1738 void WW8FlyPara::ReadFull(sal_uInt8 nOrigSp29, SwWW8ImplReader* pIo)
1740 std::shared_ptr<WW8PLCFMan> xPlcxMan = pIo->m_xPlcxMan;
1741 WW8PLCFx_Cp_FKP* pPap = xPlcxMan->GetPapPLCF();
1743 Read(nOrigSp29, pPap); // read Apo parameter
1745 do{ // block for quick exit
1746 if( nSp45 != 0 /* || nSp28 != 0 */ )
1747 break; // bGrafApo only automatic for height
1748 if( pIo->m_xWwFib->m_fComplex )
1749 break; // (*pPap)++ does not work for FastSave
1750 // -> for FastSave, no test for graphics APO
1751 SvStream* pIoStrm = pIo->m_pStrm;
1752 sal_uLong nPos = pIoStrm->Tell();
1753 WW8PLCFxSave1 aSave;
1754 xPlcxMan->GetPap()->Save( aSave );
1755 bGrafApo = false;
1757 do{ // block for quick exit
1758 sal_uInt8 nText[2];
1760 if (!checkRead(*pIoStrm, nText, 2)) // read text
1761 break;
1763 if( nText[0] != 0x01 || nText[1] != 0x0d )// only graphics + CR?
1764 break; // no
1766 pPap->advance(); // next line
1768 // in APO ?
1769 //sprmPPc
1770 SprmResult aS = pPap->HasSprm( bVer67 ? NS_sprm::v6::sprmPPc : NS_sprm::PPc::val);
1772 // no -> graphics Apo
1773 if (!aS.pSprm || aS.nRemainingData < 1)
1775 bGrafApo = true;
1776 break; // end of APO
1779 ww::WordVersion eVer = pIo->GetFib().GetFIBVersion();
1780 WW8FlyPara *pNowStyleApo=nullptr;
1781 sal_uInt16 nColl = pPap->GetIstd();
1782 ww::sti eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc( static_cast< sal_uInt8 >(nColl) ) : static_cast<ww::sti>(nColl);
1783 while (eSti != ww::stiNil && sal::static_int_cast<size_t>(nColl) < pIo->m_vColl.size() && nullptr == (pNowStyleApo = pIo->m_vColl[nColl].m_xWWFly.get()))
1785 nColl = pIo->m_vColl[nColl].m_nBase;
1786 eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc( static_cast< sal_uInt8 >(nColl) ) : static_cast<ww::sti>(nColl);
1789 WW8FlyPara aF(bVer67, pNowStyleApo);
1790 // new FlaPara for comparison
1791 aF.Read(*aS.pSprm, pPap); // WWPara for new Para
1792 if( !( aF == *this ) ) // same APO? (or a new one?)
1793 bGrafApo = true; // no -> 1-line APO
1794 // -> graphics APO
1796 while( false ); // block for quick exit
1798 xPlcxMan->GetPap()->Restore( aSave );
1799 pIoStrm->Seek( nPos );
1800 }while( false ); // block for quick exit
1803 // read for Apo definitions in Styledefs
1804 void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8RStyle const * pStyle)
1806 if (bVer67)
1808 SetValSprm( &nSp26, pStyle, NS_sprm::v6::sprmPDxaAbs ); // X-position
1809 //set in me or in parent style
1810 mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::v6::sprmPDyaAbs); // Y-position
1811 SetValSprm( &nSp45, pStyle, NS_sprm::v6::sprmPWHeightAbs ); // height
1812 SetValSprm( &nSp28, pStyle, NS_sprm::v6::sprmPDxaWidth ); // width
1813 SetValSprm( &nLeMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // L-border
1814 SetValSprm( &nRiMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // R-border
1815 SetValSprm( &nUpMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // U-border
1816 SetValSprm( &nLoMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // D-border
1818 SprmResult aS = pStyle->HasParaSprm( NS_sprm::v6::sprmPWr ); // wrapping
1819 if (aS.pSprm && aS.nRemainingData >= 1)
1820 nSp37 = *aS.pSprm;
1822 else
1824 SetValSprm( &nSp26, pStyle, NS_sprm::PDxaAbs::val ); // X-position
1825 //set in me or in parent style
1826 mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::PDyaAbs::val); // Y-position
1827 SetValSprm( &nSp45, pStyle, NS_sprm::PWHeightAbs::val ); // height
1828 SetValSprm( &nSp28, pStyle, NS_sprm::PDxaWidth::val ); // width
1829 SetValSprm( &nLeMgn, pStyle, NS_sprm::PDxaFromText::val ); // L-border
1830 SetValSprm( &nRiMgn, pStyle, NS_sprm::PDxaFromText::val ); // R-border
1831 SetValSprm( &nUpMgn, pStyle, NS_sprm::PDyaFromText::val ); // U-border
1832 SetValSprm( &nLoMgn, pStyle, NS_sprm::PDyaFromText::val ); // D-border
1834 SprmResult aS = pStyle->HasParaSprm( NS_sprm::PWr::val ); // wrapping
1835 if (aS.pSprm && aS.nRemainingData >= 1)
1836 nSp37 = *aS.pSprm;
1839 if (::lcl_ReadBorders(bVer67, brc, nullptr, pStyle)) // border
1840 bBorderLines = ::lcl_IsBorder(brc);
1843 #i8798#
1844 Appears that with no dyaAbs set then the actual vert anchoring set is
1845 ignored and we remain relative to text, so if that is the case we are 0
1846 from para anchor, so we update the frame to have explicitly this type of
1847 anchoring
1849 if (!mbVertSet)
1850 nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1851 else
1852 nSp29 = nOrigSp29;
1855 bool WW8FlyPara::IsEmpty() const
1857 WW8FlyPara aEmpty(bVer67);
1859 wr of 0 like 2 appears to me to be equivalent for checking here. See
1860 #107103# if wrong, so given that the empty is 2, if we are 0 then set
1861 empty to 0 to make 0 equiv to 2 for empty checking
1863 OSL_ENSURE(aEmpty.nSp37 == 2, "this is not what we expect for nSp37");
1864 if (this->nSp37 == 0)
1865 aEmpty.nSp37 = 0;
1866 return aEmpty == *this;
1869 // #i18732# - changes made on behalf of CMC
1870 WW8SwFlyPara::WW8SwFlyPara( SwPaM& rPaM,
1871 SwWW8ImplReader& rIo,
1872 WW8FlyPara& rWW,
1873 const sal_uInt32 nWWPgTop,
1874 const sal_uInt32 nPgWidth,
1875 const sal_Int32 nIniFlyDx,
1876 const sal_Int32 nIniFlyDy ):
1877 pFlyFormat(nullptr),
1878 nXPos(0),
1879 nYPos(0),
1880 nLeMgn(rWW.nLeMgn),
1881 nRiMgn(rWW.nRiMgn),
1882 nUpMgn(rWW.nUpMgn),
1883 nLoMgn(rWW.nLoMgn),
1884 nWidth(rWW.nSp28),
1885 nHeight(rWW.nSp45),
1886 nNetWidth(rWW.nSp28),
1887 eHeightFix(SwFrameSize::Fixed),
1888 eHRel(text::RelOrientation::PAGE_FRAME),
1889 eVRel(text::RelOrientation::FRAME),
1890 eVAlign(text::VertOrientation::NONE),
1891 eHAlign(text::HoriOrientation::NONE),
1892 eSurround(( rWW.nSp37 > 1 ) ? css::text::WrapTextMode_DYNAMIC : css::text::WrapTextMode_NONE),
1893 nXBind(( rWW.nSp29 & 0xc0 ) >> 6),
1894 nYBind(( rWW.nSp29 & 0x30 ) >> 4),
1895 nNewNetWidth(MINFLY),
1896 nLineSpace(0),
1897 bAutoWidth(false),
1898 bTogglePos(false)
1900 //#i119466 mapping "Around" wrap setting to "Parallel" for table
1901 const bool bIsTable = rIo.m_xPlcxMan->HasParaSprm(NS_sprm::PFInTable::val).pSprm;
1902 if (bIsTable && rWW.nSp37 == 2)
1903 eSurround = css::text::WrapTextMode_PARALLEL;
1906 #95905#, #83307# seems to have gone away now, so re-enable parallel
1907 wrapping support for frames in headers/footers. I don't know if we truly
1908 have an explicitly specified behaviour for these circumstances.
1911 if( nHeight & 0x8000 )
1913 nHeight &= 0x7fff;
1914 eHeightFix = SwFrameSize::Minimum;
1917 if( nHeight <= MINFLY )
1918 { // no data, or bad data
1919 eHeightFix = SwFrameSize::Minimum;
1920 nHeight = MINFLY;
1923 if( nWidth <= 10 ) // auto width
1925 bAutoWidth = true;
1926 nWidth = nNetWidth =
1927 msword_cast<sal_Int16>(nPgWidth ? nPgWidth : 2268); // 4 cm
1929 if( nWidth <= MINFLY )
1930 nWidth = nNetWidth = MINFLY; // minimum width
1933 See issue #i9178# for the 9 anchoring options, and make sure they stay
1934 working if you modify the anchoring logic here.
1937 // If the Fly is aligned left, right, up, or down,
1938 // the outer text distance will be ignored, because otherwise
1939 // the Fly will end up in the wrong position.
1940 // The only problem is with inside/outside.
1942 //#i53725# - absolute positioned objects have to be
1943 // anchored at-paragraph to assure its correct anchor position.
1944 rIo.m_pLastAnchorPos.reset( new SwPosition(*rPaM.GetPoint()));
1946 switch (nYBind)
1948 case 0: //relative to margin
1949 eVRel = text::RelOrientation::PAGE_PRINT_AREA;
1950 break;
1951 case 1: //relative to page
1952 eVRel = text::RelOrientation::PAGE_FRAME;
1953 break;
1954 default: //relative to text
1955 // put in initialization part eVRel = text::RelOrientation::FRAME;
1956 break;
1959 // #i18732#
1960 switch( rWW.nSp27 ) // particular Y-positions ?
1962 case -4:
1963 eVAlign = text::VertOrientation::TOP;
1964 if (nYBind < 2)
1965 nUpMgn = 0;
1966 break; // up
1967 case -8:
1968 eVAlign = text::VertOrientation::CENTER;
1969 break; // centered
1970 case -12:
1971 eVAlign = text::VertOrientation::BOTTOM;
1972 if (nYBind < 2)
1973 nLoMgn = 0;
1974 break; // down
1975 default:
1976 nYPos = rWW.nSp27 + static_cast<short>(nIniFlyDy);
1977 break; // corrections from ini file
1980 switch( rWW.nSp26 ) // particular X-positions ?
1982 case 0:
1983 eHAlign = text::HoriOrientation::LEFT;
1984 nLeMgn = 0;
1985 break; // left
1986 case -4:
1987 eHAlign = text::HoriOrientation::CENTER;
1988 break; // centered
1989 case -8:
1990 eHAlign = text::HoriOrientation::RIGHT;
1991 nRiMgn = 0;
1992 break; // right
1993 case -12:
1994 eHAlign = text::HoriOrientation::LEFT;
1995 bTogglePos = true;
1996 break; // inside
1997 case -16:
1998 eHAlign = text::HoriOrientation::RIGHT;
1999 bTogglePos = true;
2000 break; // outside
2001 default:
2002 nXPos = rWW.nSp26 + static_cast<short>(nIniFlyDx);
2003 break; // corrections from ini file
2006 // #i18732#
2007 switch (nXBind) // X - binding -> transform coordinates
2009 case 0: //relative to column
2010 eHRel = text::RelOrientation::FRAME;
2011 break;
2012 case 1: //relative to margin
2013 eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2014 break;
2015 default: //relative to page
2016 // put in initialization part eHRel= text::RelOrientation::PAGE_FRAME;
2017 break;
2020 // #i36649# - adjustments for certain horizontal alignments
2021 // Note: These special adjustments found by an investigation of documents
2022 // containing frames with different left/right border distances and
2023 // distances to text. The outcome is somehow strange.
2024 // Note: These adjustments causes wrong horizontal positions for frames,
2025 // which are aligned inside|outside to page|margin on even pages,
2026 // the left and right border distances are different.
2027 // no adjustments possible, if frame has automatic width.
2028 // determine left border distance
2029 sal_Int16 nLeBorderMgn( 0 );
2030 if ( !bAutoWidth )
2032 WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2033 sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeBorderMgn);
2034 nLeBorderMgn = nLeBorderMgn + nTemp;
2036 // determine right border distance
2037 sal_Int16 nRiBorderMgn( 0 );
2038 if ( !bAutoWidth )
2040 WW8_BRCVer9 &rBrc = rWW.brc[WW8_RIGHT];
2041 sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nRiBorderMgn);
2042 nRiBorderMgn = nRiBorderMgn + nTemp;
2044 if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_FRAME )
2046 // convert 'left to page' to
2047 // 'from left -<width>-<2*left border distance>-<right wrap distance>
2048 // to page text area'
2049 eHAlign = text::HoriOrientation::NONE;
2050 eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2051 nXPos = -nWidth - (2*nLeBorderMgn) - rWW.nRiMgn;
2052 // re-set left wrap distance
2053 nLeMgn = rWW.nLeMgn;
2055 else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_FRAME )
2057 // convert 'right to page' to
2058 // 'from left <right border distance-left border distance>+<left wrap distance>
2059 // to right page border'
2060 eHAlign = text::HoriOrientation::NONE;
2061 eHRel = text::RelOrientation::PAGE_RIGHT;
2062 nXPos = ( nRiBorderMgn - nLeBorderMgn ) + rWW.nLeMgn;
2063 // re-set right wrap distance
2064 nRiMgn = rWW.nRiMgn;
2066 else if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2068 // convert 'left to margin' to
2069 // 'from left -<left border distance> to page text area'
2070 eHAlign = text::HoriOrientation::NONE;
2071 eHRel = text::RelOrientation::PAGE_PRINT_AREA;
2072 nXPos = -nLeBorderMgn;
2073 // re-set left wrap distance
2074 nLeMgn = rWW.nLeMgn;
2076 else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
2078 // convert 'right to margin' to
2079 // 'from left -<width>-<left border distance> to right page border'
2080 eHAlign = text::HoriOrientation::NONE;
2081 eHRel = text::RelOrientation::PAGE_RIGHT;
2082 nXPos = -nWidth - nLeBorderMgn;
2083 // re-set right wrap distance
2084 nRiMgn = rWW.nRiMgn;
2086 else if (rWW.bBorderLines)
2089 #i582#
2090 Word has a curious bug where the offset stored do not take into
2091 account the internal distance from the corner both
2093 WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
2094 sal_Int16 nLeLMgn = 0;
2095 sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeLMgn);
2096 nLeLMgn = nLeLMgn + nTemp;
2098 if (nLeLMgn)
2100 if (eHAlign == text::HoriOrientation::LEFT)
2101 eHAlign = text::HoriOrientation::NONE;
2102 nXPos = nXPos - nLeLMgn;
2106 // adjustments for certain vertical alignments
2107 if ( eVAlign == text::VertOrientation::NONE && eVRel == text::RelOrientation::PAGE_PRINT_AREA )
2109 // convert "<X> from top page text area" to
2110 // "<X + page top margin> from page"
2111 eVRel = text::RelOrientation::PAGE_FRAME;
2112 nYPos = static_cast< sal_Int16 >( nYPos + nWWPgTop );
2115 FlySecur1( nWidth, rWW.bBorderLines ); // Do the borders match ?
2116 FlySecur1( nHeight, rWW.bBorderLines );
2120 // If a Fly in WW has automatic width, this has to be simulated
2121 // by modifying the Fly width (fixed in SW) afterwards.
2122 // This can increase or decrease the Fly width, because the default value
2123 // is set without knowledge of the contents.
2124 void WW8SwFlyPara::BoxUpWidth( tools::Long nInWidth )
2126 if( bAutoWidth && nInWidth > nNewNetWidth )
2127 nNewNetWidth = nInWidth;
2130 // The class WW8FlySet is derived from SfxItemSet and does not
2131 // provide more, but is easier to handle for me.
2132 // WW8FlySet-ctor for Apos and graphics Apos
2133 WW8FlySet::WW8FlySet(SwWW8ImplReader& rReader, const WW8FlyPara* pFW,
2134 const WW8SwFlyPara* pFS, bool bGraf)
2135 : SfxItemSet(rReader.m_rDoc.GetAttrPool(),svl::Items<RES_FRMATR_BEGIN,RES_FRMATR_END-1>{})
2137 Reader::ResetFrameFormatAttrs(*this); // remove distance/border
2138 // position
2139 Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2141 /*Below can all go when we have from left in rtl mode*/
2142 SwTwips nXPos = pFS->nXPos;
2143 sal_Int16 eHRel = pFS->eHRel;
2144 rReader.MiserableRTLGraphicsHack(nXPos, pFS->nWidth, pFS->eHAlign, eHRel);
2145 /*Above can all go when we have from left in rtl mode*/
2146 Put( SwFormatHoriOrient(nXPos, pFS->eHAlign, pFS->eHRel, pFS->bTogglePos ));
2147 Put( SwFormatVertOrient( pFS->nYPos, pFS->eVAlign, pFS->eVRel ) );
2149 if (pFS->nLeMgn || pFS->nRiMgn) // set borders
2150 Put(SvxLRSpaceItem(pFS->nLeMgn, pFS->nRiMgn, 0, 0, RES_LR_SPACE));
2152 if (pFS->nUpMgn || pFS->nLoMgn)
2153 Put(SvxULSpaceItem(pFS->nUpMgn, pFS->nLoMgn, RES_UL_SPACE));
2155 //we no longer need to hack around the header/footer problems
2156 SwFormatSurround aSurround(pFS->eSurround);
2157 if ( pFS->eSurround == css::text::WrapTextMode_DYNAMIC )
2158 aSurround.SetAnchorOnly( true );
2159 Put( aSurround );
2161 short aSizeArray[5]={0};
2162 SwWW8ImplReader::SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
2164 // the 5th parameter is always 0, thus we lose nothing due to the cast
2166 // #i27767#
2167 // #i35017# - constant name has changed
2168 Put( SwFormatWrapInfluenceOnObjPos(
2169 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) );
2171 if( bGraf )
2172 return;
2174 Put( SwFormatAnchor(WW8SwFlyPara::eAnchor) );
2175 // adjust size
2177 //Ordinarily with frames, the border width and spacing is
2178 //placed outside the frame, making it larger. With these
2179 //types of frames, the left right thickness and space makes
2180 //it wider, but the top bottom spacing and border thickness
2181 //is placed inside.
2182 Put( SwFormatFrameSize( pFS->eHeightFix, pFS->nWidth +
2183 aSizeArray[WW8_LEFT] + aSizeArray[WW8_RIGHT],
2184 pFS->nHeight));
2187 // WW8FlySet-ctor for character bound graphics
2188 WW8FlySet::WW8FlySet( SwWW8ImplReader& rReader, const SwPaM* pPaM,
2189 const WW8_PIC& rPic, tools::Long nWidth, tools::Long nHeight )
2190 : SfxItemSet(rReader.m_rDoc.GetAttrPool(),svl::Items<RES_FRMATR_BEGIN,RES_FRMATR_END-1>{})
2192 Init(rReader, pPaM);
2194 Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2196 short aSizeArray[5]={0};
2198 If we have set borders then in word the graphic is displaced from the left
2199 and top the width of the borders of those sides, and then the shadow
2200 itself is drawn to the bottom and right of the displaced graphic. In word
2201 the total size is that of the graphic plus the borders, plus the total
2202 shadow around all edges, for this translation the top and left shadow
2203 region is translated spacing around the graphic to those sides, and the
2204 bottom and right shadow size is added to the graphic size.
2206 WW8_BRCVer9 brcVer9[4];
2207 for (int i = 0; i < 4; i++)
2208 brcVer9[i] = WW8_BRCVer9(rPic.rgbrc[i]);
2209 if (SwWW8ImplReader::SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
2211 Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, 0, RES_LR_SPACE ) );
2212 Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
2213 aSizeArray[WW8_RIGHT]*=2;
2214 aSizeArray[WW8_BOT]*=2;
2217 Put( SwFormatFrameSize( SwFrameSize::Fixed, nWidth+aSizeArray[WW8_LEFT]+
2218 aSizeArray[WW8_RIGHT], nHeight+aSizeArray[WW8_TOP]
2219 + aSizeArray[WW8_BOT]) );
2222 void WW8FlySet::Init(const SwWW8ImplReader& rReader, const SwPaM* pPaM)
2224 Reader::ResetFrameFormatAttrs(*this); // remove distance/borders
2226 Put(SvxLRSpaceItem(RES_LR_SPACE)); //inline writer ole2 objects start with 0.2cm l/r
2227 SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
2229 aAnchor.SetAnchor(pPaM->GetPoint());
2230 Put(aAnchor);
2232 //The horizontal default is on the baseline, the vertical is centered
2233 //around the character center it appears
2234 if (rReader.m_aSectionManager.CurrentSectionIsVertical())
2235 Put(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER,text::RelOrientation::CHAR));
2236 else
2237 Put(SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME));
2240 WW8DupProperties::WW8DupProperties(SwDoc &rDoc, SwWW8FltControlStack *pStack)
2241 : pCtrlStck(pStack),
2242 aChrSet(rDoc.GetAttrPool(), svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>{} ),
2243 aParSet(rDoc.GetAttrPool(), svl::Items<RES_PARATR_BEGIN, RES_PARATR_END - 1>{} )
2245 //Close any open character properties and duplicate them inside the
2246 //first table cell
2247 size_t nCnt = pCtrlStck->size();
2248 for (size_t i=0; i < nCnt; ++i)
2250 const SwFltStackEntry& rEntry = (*pCtrlStck)[ i ];
2251 if (rEntry.bOpen)
2253 if (isCHRATR(rEntry.pAttr->Which()))
2255 aChrSet.Put( *rEntry.pAttr );
2258 else if (isPARATR(rEntry.pAttr->Which()))
2260 aParSet.Put( *rEntry.pAttr );
2266 void WW8DupProperties::Insert(const SwPosition &rPos)
2268 for (const SfxItemSet* pSet : {&aChrSet, &aParSet})
2270 if( pSet->Count() )
2272 SfxItemIter aIter( *pSet );
2273 const SfxPoolItem* pItem = aIter.GetCurItem();
2276 pCtrlStck->NewAttr(rPos, *pItem);
2277 } while ((pItem = aIter.NextItem()));
2282 void SwWW8ImplReader::MoveInsideFly(const SwFrameFormat *pFlyFormat)
2284 WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2286 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2288 // set Pam in FlyFrame
2289 const SwFormatContent& rContent = pFlyFormat->GetContent();
2290 OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
2291 m_pPaM->GetPoint()->nNode = rContent.GetContentIdx()->GetIndex() + 1;
2292 m_pPaM->GetPoint()->nContent.Assign( m_pPaM->GetContentNode(), 0 );
2294 aDup.Insert(*m_pPaM->GetPoint());
2297 SwTwips SwWW8ImplReader::MoveOutsideFly(SwFrameFormat *pFlyFormat,
2298 const SwPosition &rPos, bool bTableJoin)
2300 SwTwips nRetWidth = 0;
2301 if (!pFlyFormat)
2302 return nRetWidth;
2303 // Close all attributes, because otherwise attributes can appear
2304 // that extend out of Flys
2305 WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2306 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2309 #i1291
2310 If this fly frame consists entirely of one table inside a frame
2311 followed by an empty paragraph then we want to delete the empty
2312 paragraph so as to get the frame to autoshrink to the size of the
2313 table to emulate words behaviour closer.
2315 if (bTableJoin)
2317 const SwNodeIndex* pNodeIndex = pFlyFormat->GetContent().
2318 GetContentIdx();
2319 if (pNodeIndex)
2321 SwNodeIndex aIdx( *pNodeIndex, 1 ),
2322 aEnd( *pNodeIndex->GetNode().EndOfSectionNode() );
2324 if (aIdx < aEnd)
2326 if(aIdx.GetNode().IsTableNode())
2328 SwTableNode *pTable = aIdx.GetNode().GetTableNode();
2329 aIdx = *aIdx.GetNode().EndOfSectionNode();
2330 ++aIdx;
2331 if ( (aIdx < aEnd) && aIdx.GetNode().IsTextNode() )
2333 SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2334 ++aIdx;
2335 if (aIdx == aEnd && pNd && pNd->GetText().isEmpty())
2337 //An extra pre-created by writer unused paragraph
2339 //delete after import is complete rather than now
2340 //to avoid the complication of managing uncommitted
2341 //ctrlstack properties that refer to it.
2342 m_aExtraneousParas.insert(pNd);
2344 SwTable& rTable = pTable->GetTable();
2345 SwFrameFormat* pTableFormat = rTable.GetFrameFormat();
2347 if (pTableFormat)
2349 SwFormatFrameSize aSize = pTableFormat->GetFrameSize();
2350 aSize.SetHeightSizeType(SwFrameSize::Minimum);
2351 aSize.SetHeight(MINLAY);
2352 pFlyFormat->SetFormatAttr(aSize);
2353 SwFormatHoriOrient aHori = pTableFormat->GetHoriOrient();
2354 // passing the table orientation of
2355 // LEFT_AND_WIDTH to the frame seems to
2356 // work better than FULL, especially if the
2357 // table width exceeds the page width, however
2358 // I am not brave enough to set it in all
2359 // instances
2360 pTableFormat->SetFormatAttr( SwFormatHoriOrient(0, ( aHori.GetHoriOrient() == text::HoriOrientation::LEFT_AND_WIDTH ) ? ::text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::FULL ) );
2361 nRetWidth = aSize.GetWidth();
2370 *m_pPaM->GetPoint() = rPos;
2371 aDup.Insert(*m_pPaM->GetPoint());
2372 return nRetWidth;
2375 std::unique_ptr<WW8FlyPara> SwWW8ImplReader::ConstructApo(const ApoTestResults &rApo,
2376 const WW8_TablePos *pTabPos)
2378 OSL_ENSURE(rApo.HasFrame() || pTabPos,
2379 "If no frame found, *MUST* be in a table");
2381 std::unique_ptr<WW8FlyPara> pRet(new WW8FlyPara(m_bVer67, rApo.mpStyleApo));
2383 // find APO parameter and test for bGrafApo
2384 if (rApo.HasFrame())
2385 pRet->ReadFull(rApo.m_nSprm29, this);
2387 pRet->ApplyTabPos(pTabPos);
2389 if (pRet->IsEmpty())
2391 pRet.reset();
2393 return pRet;
2396 bool SwWW8ImplReader::IsDropCap() const
2398 // Find the DCS (Drop Cap Specifier) for the paragraph
2399 // if does not exist or if the first three bits are 0
2400 // then there is no dropcap on the paragraph
2401 WW8PLCFx_Cp_FKP *pPap = m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr;
2402 if (pPap)
2404 SprmResult aDCS;
2405 if (m_bVer67)
2406 aDCS = pPap->HasSprm(NS_sprm::v6::sprmPDcs);
2407 else
2408 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PDcs::val);
2409 if (aDCS.pSprm && aDCS.nRemainingData >= 2)
2412 fdct short :3 0007 drop cap type
2413 0 no drop cap
2414 1 normal drop cap
2415 2 drop cap in margin
2417 short nDCS = SVBT16ToUInt16(aDCS.pSprm);
2418 if (nDCS & 7)
2419 return true;
2422 return false;
2425 bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *pTabPos)
2427 m_xWFlyPara = ConstructApo(rApo, pTabPos);
2428 if (!m_xWFlyPara)
2429 return false;
2431 // <WW8SwFlyPara> constructor has changed - new 4th parameter
2432 // containing WW8 page top margin.
2433 m_xSFlyPara.reset(new WW8SwFlyPara( *m_pPaM, *this, *m_xWFlyPara,
2434 m_aSectionManager.GetWWPageTopMargin(),
2435 m_aSectionManager.GetTextAreaWidth(),
2436 m_nIniFlyDx, m_nIniFlyDy));
2438 // If this paragraph is a Dropcap set the flag and we will deal with it later
2439 if (IsDropCap())
2441 m_bDropCap = true;
2442 m_xCurrentItemSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), svl::Items<RES_CHRATR_BEGIN, RES_PARATR_END - 1>{}));
2443 return false;
2446 if (!m_xWFlyPara->bGrafApo)
2449 // Within the GrafApo text attributes have to be ignored, because
2450 // they would apply to the following lines. The frame is only inserted
2451 // if it is not merely positioning a single image. If it is an image
2452 // frame, pWFlyPara and pSFlyPara are retained and the resulting
2453 // attributes applied to the image when inserting the image.
2455 WW8FlySet aFlySet(*this, m_xWFlyPara.get(), m_xSFlyPara.get(), false);
2457 if (pTabPos && pTabPos->bNoFly)
2459 m_xSFlyPara->pFlyFormat = nullptr;
2461 else
2463 m_xSFlyPara->pFlyFormat = m_rDoc.MakeFlySection(WW8SwFlyPara::eAnchor,
2464 m_pPaM->GetPoint(), &aFlySet);
2465 OSL_ENSURE(m_xSFlyPara->pFlyFormat->GetAnchor().GetAnchorId() ==
2466 WW8SwFlyPara::eAnchor, "Not the anchor type requested!");
2469 if (m_xSFlyPara->pFlyFormat)
2471 if (!m_pDrawModel)
2472 GrafikCtor();
2474 SdrObject* pOurNewObject = CreateContactObject(m_xSFlyPara->pFlyFormat);
2475 m_xWWZOrder->InsertTextLayerObject(pOurNewObject);
2478 if (RndStdIds::FLY_AS_CHAR != WW8SwFlyPara::eAnchor && m_xSFlyPara->pFlyFormat)
2480 m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), m_xSFlyPara->pFlyFormat);
2483 // remember Pos in body text
2484 m_xSFlyPara->xMainTextPos.reset(new SwPosition(*m_pPaM->GetPoint()));
2486 //remove fltanchors, otherwise they will be closed inside the
2487 //frame, which makes no sense, restore them after the frame is
2488 //closed
2489 m_xSFlyPara->xOldAnchorStck = std::move(m_xAnchorStck);
2490 m_xAnchorStck.reset(new SwWW8FltAnchorStack(m_rDoc, m_nFieldFlags));
2492 if (m_xSFlyPara->pFlyFormat)
2493 MoveInsideFly(m_xSFlyPara->pFlyFormat);
2495 // 1) ReadText() is not called recursively because the length of
2496 // the Apo is unknown at that time, and ReadText() needs it.
2497 // 2) the CtrlStck is not re-created.
2498 // the Char attributes continue (trouble with Sw-attributes)
2499 // Para attributes must be reset at the end of every paragraph,
2500 // i.e. at the end of a paragraph there must not be para attributes
2501 // on the stack
2503 return true;
2506 void wwSectionManager::JoinNode(const SwPosition &rPos, const SwNode &rNode)
2508 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2509 maSegments.back().maStart.Assign(rNode);
2512 bool SwWW8ImplReader::JoinNode(SwPaM &rPam, bool bStealAttr)
2514 bool bRet = false;
2515 rPam.GetPoint()->nContent = 0; // go to start of paragraph
2517 SwNodeIndex aPref(rPam.GetPoint()->nNode, -1);
2519 if (SwTextNode* pNode = aPref.GetNode().GetTextNode())
2521 m_aSectionManager.JoinNode(*rPam.GetPoint(), aPref.GetNode());
2522 rPam.GetPoint()->nNode = aPref;
2523 rPam.GetPoint()->nContent.Assign(pNode, pNode->GetText().getLength());
2524 if (bStealAttr)
2525 m_xCtrlStck->StealAttr(rPam.GetPoint()->nNode);
2527 if (m_pLastAnchorPos || m_pPreviousNode || (m_xSFlyPara && m_xSFlyPara->xMainTextPos))
2529 SwNodeIndex aToBeJoined(aPref, 1);
2531 if (m_pLastAnchorPos)
2533 //If the last anchor pos is here, then clear the anchor pos.
2534 //This "last anchor pos" is only used for fixing up the
2535 //positions of things anchored to page breaks and here
2536 //we are removing the last paragraph of a frame, so there
2537 //cannot be a page break at this point so we can
2538 //safely reset m_pLastAnchorPos to avoid any dangling
2539 //SwIndex's pointing into the deleted paragraph
2540 SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2541 if (aLastAnchorPos == aToBeJoined)
2542 m_pLastAnchorPos.reset();
2545 if (m_pPreviousNode)
2547 //If the drop character start pos is here, then clear it.
2548 SwNodeIndex aDropCharPos(*m_pPreviousNode);
2549 if (aDropCharPos == aToBeJoined)
2550 m_pPreviousNode = nullptr;
2553 if (m_xSFlyPara && m_xSFlyPara->xMainTextPos)
2555 // If an open apo pos is here, then clear it before
2556 // JoinNext destroys it
2557 SwNodeIndex aOpenApoPos(m_xSFlyPara->xMainTextPos->nNode);
2558 if (aOpenApoPos == aToBeJoined)
2559 m_xSFlyPara->xMainTextPos.reset();
2563 pNode->JoinNext();
2565 bRet = true;
2567 return bRet;
2570 //In auto-width word frames negative after-indent values are ignored
2571 void SwWW8ImplReader::StripNegativeAfterIndent(SwFrameFormat const *pFlyFormat)
2573 const SwNodeIndex* pSttNd = pFlyFormat->GetContent().GetContentIdx();
2574 if (!pSttNd)
2575 return;
2577 SwNodeIndex aIdx(*pSttNd, 1);
2578 SwNodeIndex aEnd(*pSttNd->GetNode().EndOfSectionNode());
2579 while (aIdx < aEnd)
2581 SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2582 if (pNd)
2584 const SvxLRSpaceItem& rLR = ItemGet<SvxLRSpaceItem>(*pNd, RES_LR_SPACE);
2585 if (rLR.GetRight() < 0)
2587 SvxLRSpaceItem aLR(rLR);
2588 aLR.SetRight(0);
2589 pNd->SetAttr(aLR);
2592 ++aIdx;
2596 void SwWW8ImplReader::StopApo()
2598 OSL_ENSURE(m_xWFlyPara, "no pWFlyPara to close");
2599 if (!m_xWFlyPara)
2600 return;
2601 if (m_xWFlyPara->bGrafApo)
2603 // image frame that has not been inserted: delete empty paragraph + attr
2604 JoinNode(*m_pPaM, true);
2607 else
2609 if (!m_xSFlyPara->xMainTextPos)
2611 OSL_ENSURE(m_xSFlyPara->xMainTextPos, "StopApo: xMainTextPos is nullptr");
2612 return;
2616 What we are doing with this temporary nodeindex is as follows: The
2617 stack of attributes normally only places them into the document when
2618 the current insertion point has passed them by. Otherwise the end
2619 point of the attribute gets pushed along with the insertion point. The
2620 insertion point is moved and the properties committed during
2621 MoveOutsideFly. We also may want to remove the final paragraph in the
2622 frame, but we need to wait until the properties for that frame text
2623 have been committed otherwise they will be lost. So we first get a
2624 handle to the last the filter inserted. After the attributes are
2625 committed, if that paragraph exists we join it with the para after it
2626 that comes with the frame by default so that as normal we don't end up
2627 with one more paragraph than we wanted.
2629 SwNodeIndex aPref(m_pPaM->GetPoint()->nNode, -1);
2631 SwTwips nNewWidth =
2632 MoveOutsideFly(m_xSFlyPara->pFlyFormat, *m_xSFlyPara->xMainTextPos);
2633 if (nNewWidth)
2634 m_xSFlyPara->BoxUpWidth(nNewWidth);
2636 Color aBg(0xFE, 0xFF, 0xFF, 0xFF); //Transparent by default
2638 SwTextNode* pNd = aPref.GetNode().GetTextNode();
2639 SwTextNode* pJoinNext = nullptr;
2640 if (pNd && m_xSFlyPara->pFlyFormat)
2643 #i582#
2644 Take the last paragraph background colour and fill the frame with
2645 it. Otherwise, make it transparent, this appears to be how MSWord
2646 works
2648 const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_BACKGROUND);
2649 const SvxBrushItem &rBrush = static_cast<const SvxBrushItem&>(rItm);
2650 if (rBrush.GetColor() != COL_AUTO)
2651 aBg = rBrush.GetColor();
2653 if (m_pLastAnchorPos)
2655 //If the last anchor pos is here, then clear the anchor pos.
2656 //This "last anchor pos" is only used for fixing up the
2657 //positions of things anchored to page breaks and here
2658 //we are removing the last paragraph of a frame, so there
2659 //cannot be a page break at this point so we can
2660 //safely reset m_pLastAnchorPos to avoid any dangling
2661 //SwIndex's pointing into the deleted paragraph
2662 SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2663 SwNodeIndex aToBeJoined(aPref, 1);
2664 if (aLastAnchorPos == aToBeJoined)
2665 m_pLastAnchorPos.reset();
2668 //Get rid of extra empty paragraph
2669 pJoinNext = pNd;
2672 if (m_xSFlyPara->pFlyFormat)
2673 m_xSFlyPara->pFlyFormat->SetFormatAttr(SvxBrushItem(aBg, RES_BACKGROUND));
2675 DeleteAnchorStack();
2676 if (pJoinNext)
2677 pJoinNext->JoinNext();
2679 m_xAnchorStck = std::move(m_xSFlyPara->xOldAnchorStck);
2681 // When inserting a graphic into the fly frame using the auto
2682 // function, the extension of the SW-fly has to be set
2683 // manually as the SW fly has no auto function to adjust the
2684 // frame´s size.
2685 if (m_xSFlyPara->nNewNetWidth > MINFLY && m_xSFlyPara->pFlyFormat) // BoxUpWidth ?
2687 tools::Long nW = m_xSFlyPara->nNewNetWidth;
2688 nW += m_xSFlyPara->nWidth - m_xSFlyPara->nNetWidth; // border for it
2689 m_xSFlyPara->pFlyFormat->SetFormatAttr(
2690 SwFormatFrameSize(m_xSFlyPara->eHeightFix, nW, m_xSFlyPara->nHeight));
2693 Word set *no* width meaning it's an automatic width. The
2694 SwFlyPara reader will have already set a fallback width of the
2695 printable regions width, so we should reuse it. Despite the related
2696 problems with layout addressed with a hack in WW8FlyPara's constructor
2697 #i27204# Added AutoWidth setting. Left the old CalculateFlySize in place
2698 so that if the user unselects autowidth, the width doesn't max out
2700 else if (!m_xWFlyPara->nSp28 && m_xSFlyPara->pFlyFormat)
2702 using namespace sw::util;
2703 SfxItemSet aFlySet( m_xSFlyPara->pFlyFormat->GetAttrSet() );
2705 SwFormatFrameSize aSize(ItemGet<SwFormatFrameSize>(aFlySet, RES_FRM_SIZE));
2707 aFlySet.ClearItem(RES_FRM_SIZE);
2709 CalculateFlySize(aFlySet, m_xSFlyPara->xMainTextPos->nNode,
2710 m_xSFlyPara->nWidth);
2712 nNewWidth = ItemGet<SwFormatFrameSize>(aFlySet, RES_FRM_SIZE).GetWidth();
2714 aSize.SetWidth(nNewWidth);
2715 aSize.SetWidthSizeType(SwFrameSize::Variable);
2717 m_xSFlyPara->pFlyFormat->SetFormatAttr(aSize);
2720 m_xSFlyPara->xMainTextPos.reset();
2721 // To create the SwFrames when inserting into an existing document, fltshell.cxx
2722 // will call pFlyFrame->MakeFrames() when setting the FltAnchor attribute
2726 //#i8062#
2727 if (m_xSFlyPara && m_xSFlyPara->pFlyFormat)
2728 m_xFormatOfJustInsertedApo.reset(new FrameDeleteWatch(m_xSFlyPara->pFlyFormat));
2730 m_xSFlyPara.reset();
2731 m_xWFlyPara.reset();
2734 // TestSameApo() returns if it's the same Apo or a different one
2735 bool SwWW8ImplReader::TestSameApo(const ApoTestResults &rApo,
2736 const WW8_TablePos *pTabPos)
2738 if (!m_xWFlyPara)
2740 OSL_ENSURE(m_xWFlyPara, " Where is my pWFlyPara ? ");
2741 return true;
2744 // We need to a full comparison (excepting borders) to identify all
2745 // combinations style/hard correctly. For this reason we create a
2746 // temporary WW8FlyPara (depending on if style or not), apply the
2747 // hard attributes and then compare.
2749 // For comparison
2750 WW8FlyPara aF(m_bVer67, rApo.mpStyleApo);
2751 // WWPara for current para
2752 if (rApo.HasFrame())
2753 aF.Read(rApo.m_nSprm29, m_xPlcxMan->GetPapPLCF());
2754 aF.ApplyTabPos(pTabPos);
2756 return aF == *m_xWFlyPara;
2759 void SwWW8ImplReader::NewAttr( const SfxPoolItem& rAttr,
2760 const bool bFirstLineOfStSet,
2761 const bool bLeftIndentSet )
2763 if( m_bNoAttrImport ) // for ignoring styles during doc inserts
2764 return;
2766 if (m_pCurrentColl)
2768 OSL_ENSURE(rAttr.Which() != RES_FLTR_REDLINE, "redline in style!");
2769 m_pCurrentColl->SetFormatAttr(rAttr);
2771 else if (m_xCurrentItemSet)
2773 m_xCurrentItemSet->Put(rAttr);
2775 else if (rAttr.Which() == RES_FLTR_REDLINE)
2777 m_xRedlineStack->open(*m_pPaM->GetPoint(), rAttr);
2779 else
2781 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), rAttr);
2782 // #i103711#
2783 if ( bFirstLineOfStSet )
2785 const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2786 m_aTextNodesHavingFirstLineOfstSet.insert( pNd );
2788 // #i105414#
2789 if ( bLeftIndentSet )
2791 const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2792 m_aTextNodesHavingLeftIndentSet.insert( pNd );
2796 if (m_pPostProcessAttrsInfo && m_pPostProcessAttrsInfo->mbCopy)
2797 m_pPostProcessAttrsInfo->mItemSet.Put(rAttr);
2800 // fetches attribute from FormatColl / Stack / Doc
2801 const SfxPoolItem* SwWW8ImplReader::GetFormatAttr( sal_uInt16 nWhich )
2803 const SfxPoolItem* pRet = nullptr;
2804 if (m_pCurrentColl)
2805 pRet = &(m_pCurrentColl->GetFormatAttr(nWhich));
2806 else if (m_xCurrentItemSet)
2808 pRet = m_xCurrentItemSet->GetItem(nWhich);
2809 if (!pRet)
2810 pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2811 if (!pRet)
2812 pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2814 else if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2816 pRet = m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), nWhich);
2817 if (!pRet)
2819 if (m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_pFormat &&
2820 m_vColl[m_nCurrentColl].m_bColl)
2822 pRet = &(m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(nWhich));
2825 if (!pRet)
2826 pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
2827 if (!pRet)
2828 pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
2830 else
2831 pRet = m_xCtrlStck->GetFormatAttr(*m_pPaM->GetPoint(), nWhich);
2832 return pRet;
2835 // The methods get as parameters the token id and the length of the following
2836 // parameters according to the table in WWScan.cxx.
2837 void SwWW8ImplReader::Read_Special(sal_uInt16, const sal_uInt8* pData, short nLen)
2839 if (nLen < 1)
2841 m_bSpec = false;
2842 return;
2844 m_bSpec = ( *pData != 0 );
2847 // Read_Obj is used for fObj and for fOle2 !
2848 void SwWW8ImplReader::Read_Obj(sal_uInt16 , const sal_uInt8* pData, short nLen)
2850 if (nLen < 1)
2851 m_bObj = false;
2852 else
2854 m_bObj = 0 != *pData;
2856 if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2858 if (!m_aFieldStack.empty() && m_aFieldStack.back().mnFieldId == 56)
2860 // For LINK fields, store the nObjLocFc value in the field entry
2861 m_aFieldStack.back().mnObjLocFc = m_nPicLocFc;
2863 else
2865 m_nObjLocFc = m_nPicLocFc;
2871 void SwWW8ImplReader::Read_PicLoc(sal_uInt16 , const sal_uInt8* pData, short nLen )
2873 if (nLen < 4)
2875 m_nPicLocFc = 0;
2876 m_bSpec = false; // Is this always correct?
2878 else
2880 m_nPicLocFc = SVBT32ToUInt32( pData );
2881 m_bSpec = true;
2883 if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
2884 m_nObjLocFc = m_nPicLocFc;
2888 void SwWW8ImplReader::Read_POutLvl(sal_uInt16, const sal_uInt8* pData, short nLen )
2890 if (nLen < 0)
2892 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_OUTLINELEVEL);
2893 return;
2896 if (m_pCurrentColl != nullptr)
2898 SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
2899 if (pSI && pSI->m_bColl && pSI->m_pFormat)
2901 pSI->mnWW8OutlineLevel =
2902 static_cast< sal_uInt8 >( ( (pData && nLen >= 1) ? *pData : 0 ) );
2903 auto nLevel = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(pSI->mnWW8OutlineLevel);
2904 if (nLevel == 0)
2906 SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pSI->m_pFormat);
2907 pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
2909 NewAttr(SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nLevel));
2912 else if (m_pPaM != nullptr)
2914 const sal_uInt8 nOutlineLevel
2915 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
2916 static_cast<sal_uInt8>(((pData && nLen >= 1) ? *pData : 0)));
2917 NewAttr(SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
2921 void SwWW8ImplReader::Read_Symbol(sal_uInt16, const sal_uInt8* pData, short nLen )
2923 if( m_bIgnoreText )
2924 return;
2926 if (nLen < (m_bVer67 ? 3 : 4))
2928 //otherwise disable after we print the char
2929 if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
2930 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
2931 m_bSymbol = false;
2933 else
2935 // Make new Font-Attribute
2936 // (will be closed in SwWW8ImplReader::ReadChars() )
2938 //Will not be added to the charencoding stack, for styles the real
2939 //font setting will be put in as the styles charset, and for plain
2940 //text encoding for symbols is moot. Drawing boxes will check bSymbol
2941 //themselves so they don't need to add it to the stack either.
2942 if (SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_FONT))
2944 SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CJK_FONT);
2945 SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CTL_FONT);
2946 if( m_bVer67 )
2948 //convert single byte from MS1252 to Unicode
2949 m_cSymbol = OUString(
2950 reinterpret_cast<const char*>(pData+2), 1,
2951 RTL_TEXTENCODING_MS_1252).toChar();
2953 else
2955 //already is Unicode
2956 m_cSymbol = SVBT16ToUInt16( pData+2 );
2958 m_bSymbol = true;
2963 SwWW8StyInf *SwWW8ImplReader::GetStyle(sal_uInt16 nColl) const
2965 return const_cast<SwWW8StyInf *>(nColl < m_vColl.size() ? &m_vColl[nColl] : nullptr);
2968 // Read_BoldUsw for italic, bold, small caps, majuscule, struck out,
2969 // contour and shadow
2970 void SwWW8ImplReader::Read_BoldUsw( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
2972 const int nContiguousWestern = 8;
2973 const int nWestern = nContiguousWestern + 1;
2974 const int nEastern = 2;
2975 const int nCTL = 2;
2976 const int nIds = nWestern + nEastern + nCTL;
2977 static const sal_uInt16 nEndIds[ nIds ] =
2979 RES_CHRATR_WEIGHT, RES_CHRATR_POSTURE,
2980 RES_CHRATR_CROSSEDOUT, RES_CHRATR_CONTOUR,
2981 RES_CHRATR_SHADOWED, RES_CHRATR_CASEMAP,
2982 RES_CHRATR_CASEMAP, RES_CHRATR_HIDDEN,
2984 RES_CHRATR_CROSSEDOUT,
2986 RES_CHRATR_CJK_WEIGHT, RES_CHRATR_CJK_POSTURE,
2988 RES_CHRATR_CTL_WEIGHT, RES_CHRATR_CTL_POSTURE
2991 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
2993 sal_uInt8 nI;
2994 // the attribute number for "double strike-through" breaks rank
2995 if (NS_sprm::CFDStrike::val == nId)
2996 nI = nContiguousWestern; // The out of sequence western id
2997 else
2999 // The contiguous western ids
3000 if (eVersion <= ww::eWW2)
3001 nI = static_cast< sal_uInt8 >(nId - 60);
3002 else if (eVersion < ww::eWW8)
3003 nI = static_cast< sal_uInt8 >(nId - NS_sprm::v6::sprmCFBold);
3004 else
3005 nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBold::val);
3008 sal_uInt16 nMask = 1 << nI;
3010 if (nLen < 1)
3012 if (nI < 2)
3014 if (eVersion <= ww::eWW6)
3016 // reset the CTL Weight and Posture, because they are the same as their
3017 // western equivalents in ww6
3018 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nEastern + nI ] );
3020 // reset the CJK Weight and Posture, because they are the same as their
3021 // western equivalents in word
3022 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nI ] );
3024 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nI ] );
3025 m_xCtrlStck->SetToggleAttr(nI, false);
3026 return;
3028 // value: 0 = off, 1 = on, 128 = like style, 129 contrary to style
3029 bool bOn = *pData & 1;
3030 SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
3031 if (m_xPlcxMan && eVersion > ww::eWW2)
3033 SprmResult aCharIstd =
3034 m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3035 if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3036 pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3039 if( m_pCurrentColl ) // StyleDef -> remember flags
3041 if (pSI)
3043 // The style based on has Bit 7 set ?
3044 if (
3045 pSI->m_nBase < m_vColl.size() && (*pData & 0x80) &&
3046 (m_vColl[pSI->m_nBase].m_n81Flags & nMask)
3049 bOn = !bOn; // invert
3052 if (bOn)
3053 pSI->m_n81Flags |= nMask; // set flag
3054 else
3055 pSI->m_n81Flags &= ~nMask; // delete flag
3058 else
3061 // in text -> look at flags
3062 if( *pData & 0x80 ) // bit 7 set?
3064 if (pSI && pSI->m_n81Flags & nMask) // and in StyleDef at ?
3065 bOn = !bOn; // then invert
3066 // remember on stack that this is a toggle-attribute
3067 m_xCtrlStck->SetToggleAttr(nI, true);
3071 SetToggleAttr( nI, bOn );
3074 void SwWW8ImplReader::Read_Bidi(sal_uInt16, const sal_uInt8* pData, short nLen)
3076 if (nLen < 1) //Property end
3078 m_bBidi = false;
3079 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),RES_CHRATR_BIDIRTL);
3081 else //Property start
3083 m_bBidi = true;
3084 sal_uInt8 nBidi = *pData;
3085 NewAttr( SfxInt16Item( RES_CHRATR_BIDIRTL, (nBidi!=0)? 1 : 0 ) );
3090 tdf#91916, #i8726, #i42685# there is an ambiguity
3091 around certain properties as to what they mean,
3092 which appears to be a problem with different versions
3093 of the file format where properties conflict, i.e.
3095 ooo40606-2.doc, magic is a699
3096 : 0x6f 0x4 0x0 0x71 0x4 0x0
3097 ooo40635-1.doc, magic is a699
3098 : 0x6f 0x4 0x0 0x71 0x4 0x0
3099 ooo31093/SIMPCHIN.doc, magic is a699
3100 : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3101 : 0x6f 0x5 0x0 0x70 0x5 0x0
3102 ooo31093/TRADCHIN.doc, magic is a699
3103 : 0x6f 0x1 0x0 0x70 0x0 0x0 0x71 0x1 0x0
3104 ooo31093/JAPANESE.doc, magic is a697
3105 : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3106 ooo31093/KOREAN.doc, magic is a698
3107 : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
3108 ooo31093-1.doc, magic is a698
3109 : 0x6f 0x5 0x0 0x70 0x5 0x0
3110 ooo31093-1.doc, magic is a698
3111 : 0x6f 0x5 0x0 0x70 0x5 0x0
3113 meanwhile...
3115 ooo27954-1.doc, magic is a5dc
3116 : 0x6f 0x1 0x81 0x71 0x2 0x4 0x0 0x74 0x2 0x20 0x0
3118 ooo33251-1.doc, magic is a5dc
3119 : 0x6f 0x1 0x81 0x71 0x2 0x3 0x0 0x74 0x2 0x1c 0x0
3123 So we have the same sprm values, but different payloads, where
3124 the a5dc versions appear to use a len argument, followed by len
3125 bytes, while the a698<->a699 versions use a 2byte argument
3127 commit c2213db9ed70c1fd546482d22e36e4029c10aa45
3129 INTEGRATION: CWS tl28 (1.169.24); FILE MERGED
3130 2006/10/25 13:40:41 tl 1.169.24.2: RESYNC: (1.169-1.170); FILE MERGED
3131 2006/09/20 11:55:50 hbrinkm 1.169.24.1: #i42685# applied patch
3133 changed 0x6f and 0x70 from Read_BoldBiDiUsw to Read_FontCode for all versions.
3135 In the Word for Window 2 spec we have...
3136 78 //sprmCMajority
3137 80 //sprmCFBoldBi
3138 81 //sprmCFItalicBi
3139 82 //sprmCFtcBi
3140 83 //sprmClidBi
3141 84 //sprmCIcoBi
3142 85 //sprmCHpsBi
3143 as see in GetWW2SprmDispatcher, different numbers, but the sequence starts with
3144 the same sprmCMajority as appears before 0x6f in word 6/95
3146 I think the easiest explanation is that the CJK Word for Window 95, or whatever
3147 the product was went rogue, and did their own things with at least first three
3148 slots after sprmCMajority to do a different thing. I have no reason to think Tono
3149 was wrong with what they do in the a698<->a699 versions, but with magic
3150 a5dc they probably did mean sprmCFBoldBi, sprmCFItalicBi cause they have that 0x81
3151 pattern which has significance for those types of properties.
3153 void SwWW8ImplReader::Read_AmbiguousSPRM(sal_uInt16 nId, const sal_uInt8* pData,
3154 short nLen)
3156 if (m_xWwFib->m_wIdent >= 0xa697 && m_xWwFib->m_wIdent <= 0xa699)
3158 Read_FontCode(nId, pData, nLen);
3160 else
3162 Read_BoldBiDiUsw(nId, pData, nLen);
3166 // Read_BoldUsw for BiDi Italic, Bold
3167 void SwWW8ImplReader::Read_BoldBiDiUsw(sal_uInt16 nId, const sal_uInt8* pData,
3168 short nLen)
3170 static const sal_uInt16 nEndIds[2] =
3172 RES_CHRATR_CTL_WEIGHT, RES_CHRATR_CTL_POSTURE,
3175 sal_uInt8 nI;
3176 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3177 if (eVersion <= ww::eWW2)
3178 nI = static_cast< sal_uInt8 >(nId - 80);
3179 else if (eVersion < ww::eWW8)
3180 nI = static_cast< sal_uInt8 >(nId - 111);
3181 else
3182 nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBoldBi::val);
3184 OSL_ENSURE(nI <= 1, "not happening");
3185 if (nI > 1)
3186 return;
3188 sal_uInt16 nMask = 1 << nI;
3190 if (nLen < 1)
3192 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),nEndIds[nI]);
3193 m_xCtrlStck->SetToggleBiDiAttr(nI, false);
3194 return;
3196 bool bOn = *pData & 1;
3197 SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
3198 if (m_xPlcxMan)
3200 SprmResult aCharIstd =
3201 m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
3202 if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
3203 pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
3206 if (m_pCurrentColl && eVersion > ww::eWW2) // StyleDef -> remember flags
3208 if (pSI)
3210 if( pSI->m_nBase < m_vColl.size() // Style Based on
3211 && ( *pData & 0x80 ) // bit 7 set?
3212 && ( m_vColl[pSI->m_nBase].m_n81BiDiFlags & nMask ) ) // base mask?
3213 bOn = !bOn; // invert
3215 if( bOn )
3216 pSI->m_n81BiDiFlags |= nMask; // set flag
3217 else
3218 pSI->m_n81BiDiFlags &= ~nMask; // delete flag
3221 else
3224 // in text -> look at flags
3225 if (*pData & 0x80) // Bit 7 set?
3227 if (pSI && pSI->m_n81BiDiFlags & nMask) // and in StyleDef at ?
3228 bOn = !bOn; // then invert
3229 // remember on stack that this is a toggle-attribute
3230 m_xCtrlStck->SetToggleBiDiAttr(nI, true);
3234 SetToggleBiDiAttr(nI, bOn);
3237 void SwWW8ImplReader::SetToggleBiDiAttr(sal_uInt8 nAttrId, bool bOn)
3239 switch (nAttrId)
3241 case 0:
3243 SvxWeightItem aAttr( bOn ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT );
3244 aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3245 NewAttr( aAttr );
3247 break;
3248 case 1:
3250 SvxPostureItem aAttr( bOn ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE );
3251 aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3252 NewAttr( aAttr );
3254 break;
3255 default:
3256 OSL_ENSURE(false, "Unhandled unknown bidi toggle attribute");
3257 break;
3262 void SwWW8ImplReader::SetToggleAttr(sal_uInt8 nAttrId, bool bOn)
3264 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3266 switch (nAttrId)
3268 case 0:
3270 SvxWeightItem aAttr( bOn ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT );
3271 NewAttr( aAttr );
3272 aAttr.SetWhich( RES_CHRATR_CJK_WEIGHT );
3273 NewAttr( aAttr );
3274 if (eVersion <= ww::eWW6)
3276 aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
3277 NewAttr( aAttr );
3280 break;
3281 case 1:
3283 SvxPostureItem aAttr( bOn ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE );
3284 NewAttr( aAttr );
3285 aAttr.SetWhich( RES_CHRATR_CJK_POSTURE );
3286 NewAttr( aAttr );
3287 if (eVersion <= ww::eWW6)
3289 aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
3290 NewAttr( aAttr );
3293 break;
3294 case 2:
3295 NewAttr(SvxCrossedOutItem(bOn ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT));
3296 break;
3297 case 3:
3298 NewAttr( SvxContourItem( bOn, RES_CHRATR_CONTOUR ) );
3299 break;
3300 case 4:
3301 NewAttr( SvxShadowedItem( bOn, RES_CHRATR_SHADOWED ) );
3302 break;
3303 case 5:
3304 NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::SmallCaps
3305 : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3306 break;
3307 case 6:
3308 NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::Uppercase
3309 : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
3310 break;
3311 case 7:
3312 NewAttr(SvxCharHiddenItem(bOn, RES_CHRATR_HIDDEN));
3313 break;
3314 case 8:
3315 NewAttr( SvxCrossedOutItem( bOn ? STRIKEOUT_DOUBLE
3316 : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ) );
3317 break;
3318 default:
3319 OSL_ENSURE(false, "Unhandled unknown toggle attribute");
3320 break;
3324 void SwWW8ImplReader::ChkToggleAttr_( sal_uInt16 nOldStyle81Mask,
3325 sal_uInt16 nNewStyle81Mask )
3327 sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleAttrFlags();
3328 for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3330 if (
3331 (i & nToggleAttrFlags) &&
3332 ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3335 SetToggleAttr(n, (i & nOldStyle81Mask));
3340 void SwWW8ImplReader::ChkToggleBiDiAttr_( sal_uInt16 nOldStyle81Mask,
3341 sal_uInt16 nNewStyle81Mask )
3343 sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleBiDiAttrFlags();
3344 for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
3346 if (
3347 (i & nToggleAttrFlags) &&
3348 ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
3351 SetToggleBiDiAttr(n, (i & nOldStyle81Mask));
3356 void SwWW8ImplReader::Read_SubSuper( sal_uInt16, const sal_uInt8* pData, short nLen )
3358 if (nLen < 1)
3360 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ESCAPEMENT );
3361 return;
3364 short nEs;
3365 sal_uInt8 nProp;
3366 switch( *pData )
3368 case 1:
3369 nEs = DFLT_ESC_AUTO_SUPER;
3370 nProp = DFLT_ESC_PROP;
3371 break;
3372 case 2:
3373 nEs = DFLT_ESC_AUTO_SUB;
3374 nProp = DFLT_ESC_PROP;
3375 break;
3376 default:
3377 nEs = 0;
3378 nProp = 100;
3379 break;
3381 NewAttr( SvxEscapementItem( nEs, nProp, RES_CHRATR_ESCAPEMENT ) );
3384 SwFrameFormat *SwWW8ImplReader::ContainsSingleInlineGraphic(const SwPaM &rRegion)
3387 For inline graphics and objects word has a hacked in feature to use
3388 subscripting to force the graphic into a centered position on the line, so
3389 we must check when applying sub/super to see if it the subscript range
3390 contains only a single graphic, and if that graphic is anchored as
3391 RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3393 SwFrameFormat *pRet=nullptr;
3394 SwNodeIndex aBegin(rRegion.Start()->nNode);
3395 const sal_Int32 nBegin(rRegion.Start()->nContent.GetIndex());
3396 SwNodeIndex aEnd(rRegion.End()->nNode);
3397 const sal_Int32 nEnd(rRegion.End()->nContent.GetIndex());
3398 const SwTextNode* pTNd;
3399 const SwTextAttr* pTFlyAttr;
3400 if (
3401 aBegin == aEnd && nBegin == nEnd - 1 &&
3402 nullptr != (pTNd = aBegin.GetNode().GetTextNode()) &&
3403 nullptr != (pTFlyAttr = pTNd->GetTextAttrForCharAt(nBegin, RES_TXTATR_FLYCNT))
3406 const SwFormatFlyCnt& rFly = pTFlyAttr->GetFlyCnt();
3407 SwFrameFormat *pFlyFormat = rFly.GetFrameFormat();
3408 if (pFlyFormat &&
3409 (RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()))
3411 pRet = pFlyFormat;
3414 return pRet;
3417 bool SwWW8ImplReader::ConvertSubToGraphicPlacement()
3420 For inline graphics and objects word has a hacked in feature to use
3421 subscripting to force the graphic into a centered position on the line, so
3422 we must check when applying sub/super to see if it the subscript range
3423 contains only a single graphic, and if that graphic is anchored as
3424 RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
3426 bool bIsGraphicPlacementHack = false;
3427 sal_uInt16 nPos;
3428 if (m_xCtrlStck->GetFormatStackAttr(RES_CHRATR_ESCAPEMENT, &nPos))
3430 SwPaM aRegion(*m_pPaM->GetPoint());
3432 SwFltPosition aMkPos((*m_xCtrlStck)[nPos].m_aMkPos);
3433 SwFltPosition aPtPos(*m_pPaM->GetPoint());
3435 SwFrameFormat *pFlyFormat = nullptr;
3436 if (SwFltStackEntry::MakeRegion(m_rDoc, aRegion, SwFltStackEntry::RegionMode::NoCheck, aMkPos, aPtPos)
3437 && nullptr != (pFlyFormat = ContainsSingleInlineGraphic(aRegion)))
3439 m_xCtrlStck->DeleteAndDestroy(nPos);
3440 pFlyFormat->SetFormatAttr(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER, text::RelOrientation::CHAR));
3441 bIsGraphicPlacementHack = true;
3444 return bIsGraphicPlacementHack;
3447 void SwWW8ImplReader::Read_SubSuperProp( sal_uInt16, const sal_uInt8* pData, short nLen )
3449 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3451 if (nLen < (eVersion <= ww::eWW2 ? 1 : 2))
3453 if (!ConvertSubToGraphicPlacement())
3454 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ESCAPEMENT );
3455 return;
3458 // if the fontsize for these characters is specified, make sure it is updated first
3459 if ( m_xPlcxMan )
3461 const sal_uInt16 nFontsizeID = m_bVer67 ? NS_sprm::v6::sprmCHps : NS_sprm::CHps::val;
3462 const SprmResult aFontsize = m_xPlcxMan->GetChpPLCF()->HasSprm( nFontsizeID, /*bFindFirst=*/false );
3463 if ( aFontsize.pSprm && aFontsize.nRemainingData )
3464 Read_FontSize(nFontsizeID, aFontsize.pSprm, aFontsize.nRemainingData);
3467 // font position in HalfPoints
3468 short nPos = eVersion <= ww::eWW2 ? static_cast< sal_Int8 >( *pData ) : SVBT16ToInt16( pData );
3469 sal_Int32 nPos2 = nPos * ( 10 * 100 ); // HalfPoints in 100 * tw
3470 const SvxFontHeightItem* pF
3471 = static_cast<const SvxFontHeightItem*>(GetFormatAttr(RES_CHRATR_FONTSIZE));
3472 OSL_ENSURE(pF, "Expected to have the fontheight available here");
3474 // #i59022: Check ensure nHeight != 0. Div by zero otherwise.
3475 sal_Int32 nHeight = 240;
3476 if (pF != nullptr && pF->GetHeight() != 0)
3477 nHeight = pF->GetHeight();
3478 nPos2 /= nHeight; // ... now in % (rounded)
3479 if( nPos2 > MAX_ESC_POS )
3480 nPos2 = MAX_ESC_POS;
3481 if( nPos2 < -MAX_ESC_POS )
3482 nPos2 = -MAX_ESC_POS;
3483 SvxEscapementItem aEs( static_cast<short>(nPos2), 100, RES_CHRATR_ESCAPEMENT );
3484 NewAttr( aEs );
3487 void SwWW8ImplReader::Read_Underline( sal_uInt16, const sal_uInt8* pData, short nLen )
3489 FontLineStyle eUnderline = LINESTYLE_NONE;
3490 bool bWordLine = false;
3491 if (pData && nLen)
3493 // Parameter: 0 = none, 1 = single, 2 = by Word,
3494 // 3 = double, 4 = dotted, 5 = hidden
3495 // 6 = thick, 7 = dash, 8 = dot(not used)
3496 // 9 = dotdash 10 = dotdotdash 11 = wave
3497 switch( *pData )
3499 case 2: bWordLine = true;
3500 [[fallthrough]];
3501 case 1: eUnderline = LINESTYLE_SINGLE; break;
3502 case 3: eUnderline = LINESTYLE_DOUBLE; break;
3503 case 4: eUnderline = LINESTYLE_DOTTED; break;
3504 case 7: eUnderline = LINESTYLE_DASH; break;
3505 case 9: eUnderline = LINESTYLE_DASHDOT; break;
3506 case 10:eUnderline = LINESTYLE_DASHDOTDOT; break;
3507 case 6: eUnderline = LINESTYLE_BOLD; break;
3508 case 11:eUnderline = LINESTYLE_WAVE; break;
3509 case 20:eUnderline = LINESTYLE_BOLDDOTTED; break;
3510 case 23:eUnderline = LINESTYLE_BOLDDASH; break;
3511 case 39:eUnderline = LINESTYLE_LONGDASH; break;
3512 case 55:eUnderline = LINESTYLE_BOLDLONGDASH; break;
3513 case 25:eUnderline = LINESTYLE_BOLDDASHDOT; break;
3514 case 26:eUnderline = LINESTYLE_BOLDDASHDOTDOT;break;
3515 case 27:eUnderline = LINESTYLE_BOLDWAVE; break;
3516 case 43:eUnderline = LINESTYLE_DOUBLEWAVE; break;
3520 // if necessary, mix up stack and exit!
3521 if (nLen < 1)
3523 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE );
3524 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_WORDLINEMODE );
3526 else
3528 NewAttr( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ));
3529 if( bWordLine )
3530 NewAttr(SvxWordLineModeItem(true, RES_CHRATR_WORDLINEMODE));
3535 //The last three vary, measurements, rotation ? ?
3536 NoBracket 78 CA 06 - 02 00 00 02 34 52
3537 () 78 CA 06 - 02 01 00 02 34 52
3538 [] 78 CA 06 - 02 02 00 02 34 52
3539 <> 78 CA 06 - 02 03 00 02 34 52
3540 {} 78 CA 06 - 02 04 00 02 34 52
3542 void SwWW8ImplReader::Read_DoubleLine_Rotate( sal_uInt16, const sal_uInt8* pData,
3543 short nLen )
3545 if (nLen < 0) // close the tag
3547 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_TWO_LINES );
3548 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ROTATE );
3550 else if( pData && 6 == nLen )
3552 switch( *pData )
3554 case 2: // double line
3556 sal_Unicode cStt = 0, cEnd = 0;
3557 switch( SVBT16ToUInt16( pData+1 ) )
3559 case 1: cStt = '('; cEnd = ')'; break;
3560 case 2: cStt = '['; cEnd = ']'; break;
3561 case 3: cStt = '<'; cEnd = '>'; break;
3562 case 4: cStt = '{'; cEnd = '}'; break;
3564 NewAttr( SvxTwoLinesItem( true, cStt, cEnd, RES_CHRATR_TWO_LINES ));
3566 break;
3568 case 1: // rotated characters
3570 bool bFitToLine = 0 != *(pData+1);
3571 NewAttr( SvxCharRotateItem( Degree10(900), bFitToLine, RES_CHRATR_ROTATE ));
3573 break;
3578 void SwWW8ImplReader::Read_TextColor( sal_uInt16, const sal_uInt8* pData, short nLen )
3580 //Has newer colour variant, ignore this old variant
3581 if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CCv::val).pSprm)
3582 return;
3584 if (nLen < 1)
3585 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3586 else
3588 sal_uInt8 b = *pData; // parameter: 0 = Auto, 1..16 colors
3590 if( b > 16 ) // unknown -> Black
3591 b = 0;
3593 NewAttr( SvxColorItem(GetCol(b), RES_CHRATR_COLOR));
3594 if (m_pCurrentColl && m_xStyles)
3595 m_xStyles->mbTextColChanged = true;
3599 void SwWW8ImplReader::Read_TextForeColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3601 if (nLen < 4)
3602 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
3603 else
3605 Color aColor(msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)));
3607 // At least when transparency is 0xff and the color is black, Word renders that as black.
3608 if (aColor.GetTransparency() && aColor != COL_AUTO)
3610 aColor.SetTransparency(0);
3613 NewAttr(SvxColorItem(aColor, RES_CHRATR_COLOR));
3614 if (m_pCurrentColl && m_xStyles)
3615 m_xStyles->mbTextColChanged = true;
3619 void SwWW8ImplReader::Read_UnderlineColor(sal_uInt16, const sal_uInt8* pData, short nLen)
3621 if (nLen < 0)
3623 //because the UnderlineColor is not a standalone attribute in SW, it belongs to the underline attribute.
3624 //And, the .doc file stores attributes separately, this attribute ends here, the "underline"
3625 //attribute also terminates (if the character next owns underline, that will be a new underline attribute).
3626 //so nothing is left to be done here.
3627 return;
3629 else
3631 if ( m_pCurrentColl ) //importing style
3633 if( SfxItemState::SET == m_pCurrentColl->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3635 if (nLen >= 4)
3637 const SwAttrSet& aSet = m_pCurrentColl->GetAttrSet();
3638 std::unique_ptr<SvxUnderlineItem> pUnderline(aSet.Get(RES_CHRATR_UNDERLINE, false).Clone());
3639 pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3640 m_pCurrentColl->SetFormatAttr( *pUnderline );
3644 else if (m_xCurrentItemSet)
3646 if ( SfxItemState::SET == m_xCurrentItemSet->GetItemState( RES_CHRATR_UNDERLINE, false ) )
3648 if (nLen >= 4)
3650 std::unique_ptr<SvxUnderlineItem> pUnderline(m_xCurrentItemSet->Get(RES_CHRATR_UNDERLINE, false).Clone());
3651 pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
3652 m_xCurrentItemSet->Put( std::move(pUnderline) );
3656 else
3658 SvxUnderlineItem* pUnderlineAttr = const_cast<SvxUnderlineItem*>(static_cast<const SvxUnderlineItem*>(m_xCtrlStck->GetOpenStackAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE )));
3659 if (pUnderlineAttr && nLen >= 4)
3660 pUnderlineAttr->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32( pData ) ));
3664 bool SwWW8ImplReader::GetFontParams( sal_uInt16 nFCode, FontFamily& reFamily,
3665 OUString& rName, FontPitch& rePitch, rtl_TextEncoding& reCharSet )
3667 // the definitions that are the base for these tables are in windows.h
3668 static const FontPitch ePitchA[] =
3670 PITCH_DONTKNOW, PITCH_FIXED, PITCH_VARIABLE, PITCH_DONTKNOW
3673 static const FontFamily eFamilyA[] =
3675 FAMILY_DONTKNOW, FAMILY_ROMAN, FAMILY_SWISS, FAMILY_MODERN,
3676 FAMILY_SCRIPT, FAMILY_DECORATIVE, FAMILY_DONTKNOW, FAMILY_DONTKNOW
3679 const WW8_FFN* pF = m_xFonts->GetFont( nFCode ); // Info for it
3680 if( !pF ) // font number unknown ?
3681 return false; // then ignore
3683 rName = pF->sFontname;
3685 // pF->prg : Pitch
3686 rePitch = ePitchA[pF->aFFNBase.prg];
3688 // pF->chs: Charset
3689 if( 77 == pF->aFFNBase.chs ) // Mac font in Mac Charset or
3690 reCharSet = m_eTextCharSet; // translated to ANSI charset
3691 else
3693 // #i52786#, for word 67 we'll assume that ANSI is basically invalid,
3694 // might be true for (above) mac as well, but would need a mac example
3695 // that exercises this to be sure
3696 if (m_bVer67 && pF->aFFNBase.chs == 0)
3697 reCharSet = RTL_TEXTENCODING_DONTKNOW;
3698 else
3699 reCharSet = rtl_getTextEncodingFromWindowsCharset(pF->aFFNBase.chs);
3702 // make sure Font Family Code is set correctly
3703 // at least for the most important fonts
3704 // ( might be set wrong when Doc was not created by
3705 // Winword but by third party program like Applixware... )
3706 if (rName.startsWithIgnoreAsciiCase("Tms Rmn") ||
3707 rName.startsWithIgnoreAsciiCase("Timmons") ||
3708 rName.startsWithIgnoreAsciiCase("CG Times") ||
3709 rName.startsWithIgnoreAsciiCase("MS Serif") ||
3710 rName.startsWithIgnoreAsciiCase("Garamond") ||
3711 rName.startsWithIgnoreAsciiCase("Times Roman") ||
3712 rName.startsWithIgnoreAsciiCase("Times New Roman"))
3714 reFamily = FAMILY_ROMAN;
3716 else if (rName.startsWithIgnoreAsciiCase("Helv") ||
3717 rName.startsWithIgnoreAsciiCase("Arial") ||
3718 rName.startsWithIgnoreAsciiCase("Univers") ||
3719 rName.startsWithIgnoreAsciiCase("LinePrinter") ||
3720 rName.startsWithIgnoreAsciiCase("Lucida Sans") ||
3721 rName.startsWithIgnoreAsciiCase("Small Fonts") ||
3722 rName.startsWithIgnoreAsciiCase("MS Sans Serif"))
3724 reFamily = FAMILY_SWISS;
3726 else
3728 reFamily = eFamilyA[pF->aFFNBase.ff];
3731 return true;
3734 bool SwWW8ImplReader::SetNewFontAttr(sal_uInt16 nFCode, bool bSetEnums,
3735 sal_uInt16 nWhich)
3737 FontFamily eFamily;
3738 OUString aName;
3739 FontPitch ePitch;
3740 rtl_TextEncoding eSrcCharSet;
3742 if( !GetFontParams( nFCode, eFamily, aName, ePitch, eSrcCharSet ) )
3744 //If we fail (and are not doing a style) then put something into the
3745 //character encodings stack anyway so that the property end that pops
3746 //off the stack will keep in sync
3747 if (!m_pCurrentColl && IsListOrDropcap())
3749 if (nWhich == RES_CHRATR_CJK_FONT)
3751 if (!m_aFontSrcCJKCharSets.empty())
3753 eSrcCharSet = m_aFontSrcCJKCharSets.top();
3755 else
3757 eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3760 m_aFontSrcCJKCharSets.push(eSrcCharSet);
3762 else
3764 if (!m_aFontSrcCharSets.empty())
3766 eSrcCharSet = m_aFontSrcCharSets.top();
3768 else
3770 eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
3773 m_aFontSrcCharSets.push(eSrcCharSet);
3776 return false;
3779 rtl_TextEncoding eDstCharSet = eSrcCharSet;
3781 SvxFontItem aFont( eFamily, aName, OUString(), ePitch, eDstCharSet, nWhich);
3783 if( bSetEnums )
3785 if( m_pCurrentColl && m_nCurrentColl < m_vColl.size() ) // StyleDef
3787 switch(nWhich)
3789 default:
3790 case RES_CHRATR_FONT:
3791 m_vColl[m_nCurrentColl].m_eLTRFontSrcCharSet = eSrcCharSet;
3792 break;
3793 case RES_CHRATR_CTL_FONT:
3794 m_vColl[m_nCurrentColl].m_eRTLFontSrcCharSet = eSrcCharSet;
3795 break;
3796 case RES_CHRATR_CJK_FONT:
3797 m_vColl[m_nCurrentColl].m_eCJKFontSrcCharSet = eSrcCharSet;
3798 break;
3801 else if (IsListOrDropcap())
3803 //Add character text encoding to stack
3804 if (nWhich == RES_CHRATR_CJK_FONT)
3805 m_aFontSrcCJKCharSets.push(eSrcCharSet);
3806 else
3807 m_aFontSrcCharSets.push(eSrcCharSet);
3811 NewAttr( aFont ); // ...and insert
3813 return true;
3816 void SwWW8ImplReader::ResetCharSetVars()
3818 OSL_ENSURE(!m_aFontSrcCharSets.empty(),"no charset to remove");
3819 if (!m_aFontSrcCharSets.empty())
3820 m_aFontSrcCharSets.pop();
3823 void SwWW8ImplReader::ResetCJKCharSetVars()
3825 OSL_ENSURE(!m_aFontSrcCJKCharSets.empty(),"no charset to remove");
3826 if (!m_aFontSrcCJKCharSets.empty())
3827 m_aFontSrcCJKCharSets.pop();
3830 void SwWW8ImplReader::openFont(sal_uInt16 nFCode, sal_uInt16 nId)
3832 if (SetNewFontAttr(nFCode, true, nId) && m_pCurrentColl && m_xStyles)
3834 // remember for simulating default font
3835 if (RES_CHRATR_CJK_FONT == nId)
3836 m_xStyles->mbCJKFontChanged = true;
3837 else if (RES_CHRATR_CTL_FONT == nId)
3838 m_xStyles->mbCTLFontChanged = true;
3839 else
3840 m_xStyles->mbFontChanged = true;
3844 void SwWW8ImplReader::closeFont(sal_uInt16 nId)
3846 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3847 if (nId == RES_CHRATR_CJK_FONT)
3848 ResetCJKCharSetVars();
3849 else
3850 ResetCharSetVars();
3854 Turn font on or off:
3856 void SwWW8ImplReader::Read_FontCode( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3858 //Note: this function needs to be able to run multiple times on the same data.
3859 //It is called by Read_SubSuperProp to ensure that the current fontsize is known.
3861 if (m_bSymbol) // if bSymbol, the symbol's font
3862 return;
3864 // (see sprmCSymbol) is valid!
3865 switch( nId )
3867 case 113: //WW7
3868 case NS_sprm::CRgFtc2::val: //"Other" font, override with BiDi if it exists
3869 case NS_sprm::CFtcBi::val: //BiDi Font
3870 nId = RES_CHRATR_CTL_FONT;
3871 break;
3872 case NS_sprm::v6::sprmCFtc: //WW6
3873 case 111: //WW7
3874 case NS_sprm::CRgFtc0::val:
3875 nId = RES_CHRATR_FONT;
3876 break;
3877 case 112: //WW7
3878 case NS_sprm::CRgFtc1::val:
3879 nId = RES_CHRATR_CJK_FONT;
3880 break;
3881 default:
3882 return ;
3885 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3887 if (nLen < 2) // end of attribute
3889 if (eVersion <= ww::eWW6)
3891 closeFont(RES_CHRATR_CTL_FONT);
3892 closeFont(RES_CHRATR_CJK_FONT);
3894 closeFont(nId);
3896 else
3898 sal_uInt16 nFCode = SVBT16ToUInt16( pData ); // font number
3899 openFont(nFCode, nId);
3900 if (eVersion <= ww::eWW6)
3902 openFont(nFCode, RES_CHRATR_CJK_FONT);
3903 openFont(nFCode, RES_CHRATR_CTL_FONT);
3908 void SwWW8ImplReader::Read_FontSize( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3910 switch( nId )
3912 case 74: // WW2
3913 case NS_sprm::v6::sprmCHps:
3914 case NS_sprm::CHps::val:
3915 nId = RES_CHRATR_FONTSIZE;
3916 break;
3917 case 85: //WW2
3918 case 116: //WW7
3919 case NS_sprm::CHpsBi::val:
3920 nId = RES_CHRATR_CTL_FONTSIZE;
3921 break;
3922 default:
3923 return ;
3926 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
3928 if (nLen < (eVersion <= ww::eWW2 ? 1 : 2)) // end of attribute
3930 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
3931 if (eVersion <= ww::eWW6) // reset additionally the CTL size
3932 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CTL_FONTSIZE );
3933 if (RES_CHRATR_FONTSIZE == nId) // reset additionally the CJK size
3934 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CJK_FONTSIZE );
3936 else
3938 // Font-Size in half points e.g. 10 = 1440 / ( 72 * 2 )
3939 sal_uLong nFSize = eVersion <= ww::eWW2 ? *pData : SVBT16ToUInt16(pData);
3940 nFSize*= 10;
3942 SvxFontHeightItem aSz( nFSize, 100, nId );
3943 NewAttr( aSz );
3944 if (RES_CHRATR_FONTSIZE == nId) // set additionally the CJK size
3946 aSz.SetWhich( RES_CHRATR_CJK_FONTSIZE );
3947 NewAttr( aSz );
3949 if (eVersion <= ww::eWW6) // set additionally the CTL size
3951 aSz.SetWhich( RES_CHRATR_CTL_FONTSIZE );
3952 NewAttr( aSz );
3954 if (m_pCurrentColl && m_xStyles) // Style-Def ?
3956 // remember for simulating default font size
3957 if (nId == RES_CHRATR_CTL_FONTSIZE)
3958 m_xStyles->mbFCTLSizeChanged = true;
3959 else
3961 m_xStyles->mbFSizeChanged = true;
3962 if (eVersion <= ww::eWW6)
3963 m_xStyles->mbFCTLSizeChanged= true;
3969 void SwWW8ImplReader::Read_CharSet(sal_uInt16 , const sal_uInt8* pData, short nLen)
3971 if (nLen < 1)
3972 { // end of attribute
3973 m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
3974 return;
3976 sal_uInt8 nfChsDiff = *pData;
3978 if (nfChsDiff && nLen >= 2)
3979 m_eHardCharSet = rtl_getTextEncodingFromWindowsCharset( *(pData + 1) );
3980 else
3981 m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
3984 void SwWW8ImplReader::Read_Language( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
3986 switch( nId )
3988 case NS_sprm::v6::sprmCLid:
3989 case NS_sprm::CRgLid0_80::val:
3990 case NS_sprm::CRgLid0::val:
3991 nId = RES_CHRATR_LANGUAGE;
3992 break;
3993 case NS_sprm::CRgLid1_80::val:
3994 case NS_sprm::CRgLid1::val:
3995 nId = RES_CHRATR_CJK_LANGUAGE;
3996 break;
3997 case 83: // WW2
3998 case 114: // WW7
3999 case NS_sprm::CLidBi::val:
4000 nId = RES_CHRATR_CTL_LANGUAGE;
4001 break;
4002 default:
4003 return;
4006 if (nLen < 2) // end of attribute
4007 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4008 else
4010 sal_uInt16 nLang = SVBT16ToUInt16( pData ); // Language-Id
4011 NewAttr(SvxLanguageItem(LanguageType(nLang), nId));
4016 Turn on character style:
4018 void SwWW8ImplReader::Read_CColl( sal_uInt16, const sal_uInt8* pData, short nLen )
4020 if (nLen < 2) // end of attribute
4022 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_TXTATR_CHARFMT );
4023 m_nCharFormat = -1;
4024 return;
4026 sal_uInt16 nId = SVBT16ToUInt16( pData ); // Style-Id (NOT Sprm-Id!)
4028 if( nId >= m_vColl.size() || !m_vColl[nId].m_pFormat // invalid Id?
4029 || m_vColl[nId].m_bColl ) // or paragraph style?
4030 return; // then ignore
4032 // if current on loading a TOX field, and current trying to apply a hyperlink character style,
4033 // just ignore. For the hyperlinks inside TOX in MS Word is not same with a common hyperlink
4034 // Character styles: without underline and blue font color. And such type style will be applied in others
4035 // processes.
4036 if (m_bLoadingTOXCache && m_vColl[nId].GetWWStyleId() == ww::stiHyperlink)
4038 return;
4041 NewAttr( SwFormatCharFormat( static_cast<SwCharFormat*>(m_vColl[nId].m_pFormat) ) );
4042 m_nCharFormat = static_cast<short>(nId);
4046 Narrower or wider than normal:
4048 void SwWW8ImplReader::Read_Kern( sal_uInt16, const sal_uInt8* pData, short nLen )
4050 if (nLen < 2) // end of attribute
4052 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_KERNING );
4053 return;
4055 sal_Int16 nKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4056 NewAttr( SvxKerningItem( nKern, RES_CHRATR_KERNING ) );
4059 void SwWW8ImplReader::Read_FontKern( sal_uInt16, const sal_uInt8* pData, short nLen )
4061 if (nLen < 2) // end of attribute
4063 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_AUTOKERN );
4064 return;
4066 sal_Int16 nAutoKern = SVBT16ToUInt16( pData ); // Kerning in Twips
4067 NewAttr(SvxAutoKernItem(static_cast<bool>(nAutoKern), RES_CHRATR_AUTOKERN));
4070 void SwWW8ImplReader::Read_CharShadow( sal_uInt16, const sal_uInt8* pData, short nLen )
4072 //Has newer colour variant, ignore this old variant
4073 if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CShd::val).pSprm)
4074 return;
4076 if (nLen < 2)
4078 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BACKGROUND );
4080 else
4082 WW8_SHD aSHD;
4083 aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4084 SwWW8Shade aSh( m_bVer67, aSHD );
4086 NewAttr( SvxBrushItem( aSh.aColor, RES_CHRATR_BACKGROUND ));
4088 // Add a marker to the grabbag indicating that character background was imported from MSO shading
4089 SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4090 std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4091 rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::makeAny(true)));
4092 NewAttr(aGrabBag);
4096 void SwWW8ImplReader::Read_TextBackColor(sal_uInt16, const sal_uInt8* pData, short nLen )
4098 if (nLen <= 0)
4100 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BACKGROUND );
4102 else
4104 OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4105 if (nLen != 10)
4106 return;
4107 Color aColour(ExtractColour(pData, m_bVer67));
4108 NewAttr(SvxBrushItem(aColour, RES_CHRATR_BACKGROUND));
4110 // Add a marker to the grabbag indicating that character background was imported from MSO shading
4111 SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
4112 std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
4113 rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::makeAny(true)));
4114 NewAttr(aGrabBag);
4118 void SwWW8ImplReader::Read_CharHighlight(sal_uInt16, const sal_uInt8* pData, short nLen)
4120 if (nLen < 1)
4122 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_HIGHLIGHT );
4124 else
4126 sal_uInt8 b = *pData; // Parameter: 0 = Auto, 1..16 colors
4128 if( b > 16 ) // invalid -> Black
4129 b = 0; // Auto -> Black
4131 Color aCol(GetCol(b));
4132 NewAttr( SvxBrushItem( aCol , RES_CHRATR_HIGHLIGHT ));
4136 void SwWW8ImplReader::Read_NoLineNumb(sal_uInt16 , const sal_uInt8* pData, short nLen)
4138 if (nLen < 0) // end of attribute
4140 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_LINENUMBER );
4141 return;
4143 SwFormatLineNumber aLN;
4144 if (const SwFormatLineNumber* pLN
4145 = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
4147 aLN.SetStartValue( pLN->GetStartValue() );
4150 aLN.SetCountLines(pData && nLen >= 1 && (0 == *pData));
4151 NewAttr( aLN );
4154 static bool lcl_HasExplicitLeft(const WW8PLCFMan *pPlcxMan, bool bVer67)
4156 WW8PLCFx_Cp_FKP *pPap = pPlcxMan ? pPlcxMan->GetPapPLCF() : nullptr;
4157 if (pPap)
4159 if (bVer67)
4160 return pPap->HasSprm(NS_sprm::v6::sprmPDxaLeft).pSprm;
4161 else
4162 return (pPap->HasSprm(NS_sprm::PDxaLeft80::val).pSprm || pPap->HasSprm(NS_sprm::PDxaLeft::val).pSprm);
4164 return false;
4167 // Sprm 16, 17
4168 void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4170 if (nLen < 2) // end of attribute
4172 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LR_SPACE);
4173 return;
4176 short nPara = SVBT16ToUInt16( pData );
4178 std::shared_ptr<SvxLRSpaceItem> aLR(std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE));
4179 const SfxPoolItem* pLR = GetFormatAttr(RES_LR_SPACE);
4180 if( pLR )
4181 aLR.reset(static_cast<SvxLRSpaceItem*>(pLR->Clone()));
4183 // Fix the regression issue: #i99822#: Discussion?
4184 // Since the list level formatting doesn't apply into paragraph style
4185 // for list levels of mode LABEL_ALIGNMENT.(see ww8par3.cxx
4186 // W8ImplReader::RegisterNumFormatOnTextNode).
4187 // Need to apply the list format to the paragraph here.
4188 SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode();
4189 if( pTextNode && pTextNode->AreListLevelIndentsApplicable() )
4191 SwNumRule * pNumRule = pTextNode->GetNumRule();
4192 if( pNumRule )
4194 sal_uInt8 nLvl = static_cast< sal_uInt8 >(pTextNode->GetActualListLevel());
4195 const SwNumFormat* pFormat = pNumRule->GetNumFormat( nLvl );
4196 if ( pFormat && pFormat->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
4198 aLR->SetTextLeft( pFormat->GetIndentAt() );
4199 aLR->SetTextFirstLineOffset( static_cast<short>(pFormat->GetFirstLineIndent()) );
4200 // make paragraph have hard-set indent attributes
4201 pTextNode->SetAttr( *aLR );
4207 The older word sprms mean left/right, while the new ones mean before/after.
4208 Writer now also works with before after, so when we see old left/right and
4209 we're RTL. We swap them
4211 if (IsRightToLeft())
4213 switch (nId)
4215 //Left becomes after;
4216 case NS_sprm::v6::sprmPDxaLeft:
4217 nId = NS_sprm::v6::sprmPDxaRight;
4218 break;
4219 case NS_sprm::PDxaLeft80::val:
4220 nId = NS_sprm::PDxaRight80::val;
4221 break;
4222 //Right becomes before;
4223 case NS_sprm::v6::sprmPDxaRight:
4224 nId = NS_sprm::v6::sprmPDxaLeft;
4225 break;
4226 case NS_sprm::PDxaRight80::val:
4227 nId = NS_sprm::PDxaLeft80::val;
4228 break;
4232 bool bFirstLinOfstSet( false ); // #i103711#
4233 bool bLeftIndentSet( false ); // #i105414#
4235 switch (nId)
4237 //sprmPDxaLeft
4238 case NS_sprm::v6::sprmPDxaLeft:
4239 case NS_sprm::PDxaLeft80::val:
4240 case NS_sprm::PDxaLeft::val:
4241 aLR->SetTextLeft( nPara );
4242 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4244 m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4246 bLeftIndentSet = true; // #i105414#
4247 break;
4248 //sprmPDxaLeft1
4249 case NS_sprm::v6::sprmPDxaLeft1:
4250 case NS_sprm::PDxaLeft180::val:
4251 case NS_sprm::PDxaLeft1::val:
4253 As part of an attempt to break my spirit ww 8+ formats can contain
4254 ww 7- lists. If they do and the list is part of the style, then
4255 when removing the list from a paragraph of that style there
4256 appears to be a bug where the hanging indent value which the list
4257 set is still factored into the left indent of the paragraph. Its
4258 not listed in the winword dialogs, but it is clearly there. So if
4259 our style has a broken ww 7- list and we know that the list has
4260 been removed then we will factor the original list applied hanging
4261 into our calculation.
4263 if (m_xPlcxMan && m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_bHasBrokenWW6List)
4265 SprmResult aIsZeroed = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PIlfo::val);
4266 if (aIsZeroed.pSprm && aIsZeroed.nRemainingData >= 1 && *aIsZeroed.pSprm == 0)
4268 const SvxLRSpaceItem &rLR =
4269 ItemGet<SvxLRSpaceItem>(*(m_vColl[m_nCurrentColl].m_pFormat),
4270 RES_LR_SPACE);
4271 nPara = nPara - rLR.GetTextFirstLineOffset();
4275 aLR->SetTextFirstLineOffset(nPara);
4277 if (!m_pCurrentColl)
4279 if (const SwTextNode* pNode = m_pPaM->GetNode().GetTextNode())
4281 if ( const SwNumFormat *pNumFormat = GetNumFormatFromTextNode(*pNode) )
4283 if (!lcl_HasExplicitLeft(m_xPlcxMan.get(), m_bVer67))
4285 aLR->SetTextLeft(pNumFormat->GetIndentAt());
4287 // If have not explicit left, set number format list tab position is doc default tab
4288 const SvxTabStopItem *pDefaultStopItem = m_rDoc.GetAttrPool().GetPoolDefaultItem(RES_PARATR_TABSTOP);
4289 if ( pDefaultStopItem && pDefaultStopItem->Count() > 0 )
4290 const_cast<SwNumFormat*>(pNumFormat)->SetListtabPos( const_cast<SvxTabStop&>((*pDefaultStopItem)[0]).GetTabPos() );
4295 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4297 m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
4299 bFirstLinOfstSet = true; // #i103711#
4300 break;
4301 //sprmPDxaRight
4302 case NS_sprm::v6::sprmPDxaRight:
4303 case NS_sprm::PDxaRight80::val:
4304 case NS_sprm::PDxaRight::val:
4305 aLR->SetRight( nPara );
4306 break;
4307 default:
4308 return;
4311 NewAttr( *aLR, bFirstLinOfstSet, bLeftIndentSet ); // #i103711#, #i105414#
4314 // Sprm 20
4315 void SwWW8ImplReader::Read_LineSpace( sal_uInt16, const sal_uInt8* pData, short nLen )
4317 // comment see Read_UL()
4318 if (m_bStyNormal && m_bWWBugNormal)
4319 return;
4321 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
4323 if (nLen < (eVersion <= ww::eWW2 ? 3 : 4))
4325 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_LINESPACING );
4326 if( !( m_nIniFlags & WW8FL_NO_IMPLPASP ) )
4327 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4328 return;
4331 short nSpace = SVBT16ToUInt16( pData );
4332 short nMulti = (eVersion <= ww::eWW2) ? 1 : SVBT16ToUInt16( pData + 2 );
4334 SvxLineSpaceRule eLnSpc;
4335 if( 0 > nSpace )
4337 nSpace = -nSpace;
4338 eLnSpc = SvxLineSpaceRule::Fix;
4340 else
4341 eLnSpc = SvxLineSpaceRule::Min;
4343 // WW has implicit additional paragraph spacing depending on
4344 // the line spacing. It is, for "exactly", 0.8 * line spacing "before"
4345 // and 0.2 * line spacing "after".
4346 // For "at least", it is 1 * line spacing "before" and 0 * line spacing "after".
4347 // For "multiple", it is 0 "before" and min(0cm, FontSize*(nFach-1)) "after".
4349 // SW also has implicit line spacing. It is, for "at least"
4350 // 1 * line spacing "before" and 0 "after".
4351 // For proportional, it is min(0cm, FontSize*(nFach-1)) both "before" and "after".
4353 sal_uInt16 nSpaceTw = 0;
4355 SvxLineSpacingItem aLSpc( LINE_SPACE_DEFAULT_HEIGHT, RES_PARATR_LINESPACING );
4357 if( 1 == nMulti ) // MultilineSpace ( proportional )
4359 tools::Long n = nSpace * 10 / 24; // WW: 240 = 100%, SW: 100 = 100%
4361 // here n is in [0..13653]
4362 aLSpc.SetPropLineSpace( static_cast<sal_uInt16>(n) );
4363 const SvxFontHeightItem* pH = static_cast<const SvxFontHeightItem*>(
4364 GetFormatAttr( RES_CHRATR_FONTSIZE ));
4365 nSpaceTw = static_cast<sal_uInt16>( n * pH->GetHeight() / 100 );
4367 else // Fixed / Minimum
4369 // for negative space, the distance is "exact", otherwise "at least"
4370 nSpaceTw = static_cast<sal_uInt16>(nSpace);
4371 aLSpc.SetLineHeight( nSpaceTw );
4372 aLSpc.SetLineSpaceRule( eLnSpc);
4374 NewAttr( aLSpc );
4375 if (m_xSFlyPara)
4376 m_xSFlyPara->nLineSpace = nSpaceTw; // linespace for graphics APOs
4379 //#i18519# AutoSpace value depends on Dop fDontUseHTMLAutoSpacing setting
4380 sal_uInt16 SwWW8ImplReader::GetParagraphAutoSpace(bool fDontUseHTMLAutoSpacing)
4382 if (fDontUseHTMLAutoSpacing)
4383 return 100; //Seems to be always 5points in this case
4384 else
4385 return 280; //Seems to be always 14points in this case
4388 void SwWW8ImplReader::Read_ParaAutoBefore(sal_uInt16, const sal_uInt8 *pData, short nLen)
4390 if (nLen < 1)
4392 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4393 return;
4396 if (*pData)
4398 SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4399 aUL.SetUpper(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4400 NewAttr(aUL);
4401 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4402 m_vColl[m_nCurrentColl].m_bParaAutoBefore = true;
4403 else
4404 m_bParaAutoBefore = true;
4406 else
4408 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4409 m_vColl[m_nCurrentColl].m_bParaAutoBefore = false;
4410 else
4411 m_bParaAutoBefore = false;
4415 void SwWW8ImplReader::Read_ParaAutoAfter(sal_uInt16, const sal_uInt8 *pData, short nLen)
4417 if (nLen < 1)
4419 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
4420 return;
4423 if (*pData)
4425 SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
4426 aUL.SetLower(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
4427 NewAttr(aUL);
4428 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4429 m_vColl[m_nCurrentColl].m_bParaAutoAfter = true;
4430 else
4431 m_bParaAutoAfter = true;
4433 else
4435 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
4436 m_vColl[m_nCurrentColl].m_bParaAutoAfter = false;
4437 else
4438 m_bParaAutoAfter = false;
4442 // Sprm 21, 22
4443 void SwWW8ImplReader::Read_UL( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4445 // A workaround for an error in WW: For nProduct == 0c03d, usually
4446 // DyaAfter 240 (delta y distance after, comment of the translator)
4447 // is incorrectly inserted into style "Normal", even though it isn't there.
4448 // Using the ini flag WW8FL_NO_STY_DYA you can force this behavior for other
4449 // WW versions as well.
4450 // OSL_ENSURE( !bStyNormal || bWWBugNormal, "+This Document may point to a bug
4451 // in the WW version used for creating it. If the Styles <Standard> resp.
4452 // <Normal> differentiate between WW and SW in paragraph or line spacing,
4453 // then please send this Document to SH.");
4454 // bWWBugNormal is not a sufficient criterion for this distance being wrong.
4456 if (nLen < 2)
4458 // end of attribute
4459 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4460 return;
4462 short nPara = SVBT16ToUInt16( pData );
4463 if( nPara < 0 )
4464 nPara = -nPara;
4466 SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4468 switch( nId )
4470 //sprmPDyaBefore
4471 case NS_sprm::v6::sprmPDyaBefore:
4472 case NS_sprm::PDyaBefore::val:
4473 aUL.SetUpper( nPara );
4474 break;
4475 //sprmPDyaAfter
4476 case NS_sprm::v6::sprmPDyaAfter:
4477 case NS_sprm::PDyaAfter::val:
4478 aUL.SetLower( nPara );
4479 break;
4480 default:
4481 return;
4484 NewAttr( aUL );
4487 void SwWW8ImplReader::Read_ParaContextualSpacing( sal_uInt16, const sal_uInt8* pData, short nLen )
4489 if (nLen < 1)
4491 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
4492 return;
4494 SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
4495 aUL.SetContextValue(*pData != 0);
4496 NewAttr( aUL );
4499 void SwWW8ImplReader::Read_IdctHint( sal_uInt16, const sal_uInt8* pData, short nLen )
4501 // sprmcidcthint (opcode 0x286f) specifies a script bias for the text in the run.
4502 // for unicode characters that are shared between far east and non-far east scripts,
4503 // this property determines what font and language the character will use.
4504 // when this value is 0, text properties bias towards non-far east properties.
4505 // when this value is 1, text properties bias towards far east properties.
4506 // when this value is 2, text properties bias towards complex properties.
4507 if (nLen < 1) //Property end
4509 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),RES_CHRATR_IDCTHINT);
4511 else //Property start
4513 NewAttr(SfxInt16Item(RES_CHRATR_IDCTHINT, *pData));
4517 void SwWW8ImplReader::Read_Justify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4519 if (nLen < 1)
4521 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4522 return;
4525 SvxAdjust eAdjust(SvxAdjust::Left);
4526 bool bDistributed = false;
4527 switch (*pData)
4529 default:
4530 case 0:
4531 break;
4532 case 1:
4533 eAdjust = SvxAdjust::Center;
4534 break;
4535 case 2:
4536 eAdjust = SvxAdjust::Right;
4537 break;
4538 case 3:
4539 eAdjust = SvxAdjust::Block;
4540 break;
4541 case 4:
4542 eAdjust = SvxAdjust::Block;
4543 bDistributed = true;
4544 break;
4546 SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4547 if (bDistributed)
4548 aAdjust.SetLastBlock(SvxAdjust::Block);
4550 NewAttr(aAdjust);
4551 SetRelativeJustify( nId != NS_sprm::PJc80::val );
4554 bool SwWW8ImplReader::IsRightToLeft()
4556 bool bRTL = false;
4557 SprmResult aDir;
4558 if (m_xPlcxMan)
4559 aDir = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PFBiDi::val);
4560 if (aDir.pSprm && aDir.nRemainingData >= 1)
4561 bRTL = *aDir.pSprm != 0;
4562 else
4564 const SvxFrameDirectionItem* pItem=
4565 static_cast<const SvxFrameDirectionItem*>(GetFormatAttr(RES_FRAMEDIR));
4566 if (pItem && (pItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB))
4567 bRTL = true;
4569 return bRTL;
4572 void SwWW8ImplReader::Read_RTLJustify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4574 if (nLen < 1)
4576 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
4577 return;
4580 //If we are in a ltr paragraph this is the same as normal Justify,
4581 //If we are in a rtl paragraph the meaning is reversed.
4582 if (!IsRightToLeft())
4583 Read_Justify(nId, pData, nLen);
4584 else
4586 SvxAdjust eAdjust(SvxAdjust::Right);
4587 bool bDistributed = false;
4588 switch (*pData)
4590 default:
4591 case 0:
4592 break;
4593 case 1:
4594 eAdjust = SvxAdjust::Center;
4595 break;
4596 case 2:
4597 eAdjust = SvxAdjust::Left;
4598 break;
4599 case 3:
4600 eAdjust = SvxAdjust::Block;
4601 break;
4602 case 4:
4603 eAdjust = SvxAdjust::Block;
4604 bDistributed = true;
4605 break;
4607 SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
4608 if (bDistributed)
4609 aAdjust.SetLastBlock(SvxAdjust::Block);
4611 NewAttr(aAdjust);
4612 SetRelativeJustify( true );
4616 void SwWW8ImplReader::Read_BoolItem( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4618 switch( nId )
4620 case NS_sprm::PFKinsoku::val:
4621 nId = RES_PARATR_FORBIDDEN_RULES;
4622 break;
4623 case NS_sprm::PFOverflowPunct::val:
4624 nId = RES_PARATR_HANGINGPUNCTUATION;
4625 break;
4626 case NS_sprm::PFAutoSpaceDE::val:
4627 nId = RES_PARATR_SCRIPTSPACE;
4628 break;
4629 default:
4630 OSL_ENSURE( false, "wrong Id" );
4631 return ;
4634 if (nLen < 1)
4635 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
4636 else
4638 std::unique_ptr<SfxBoolItem> pI(static_cast<SfxBoolItem*>(GetDfltAttr( nId )->Clone()));
4639 pI->SetValue( 0 != *pData );
4640 NewAttr( *pI );
4644 void SwWW8ImplReader::Read_Emphasis( sal_uInt16, const sal_uInt8* pData, short nLen )
4646 if (nLen < 1)
4647 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_EMPHASIS_MARK );
4648 else
4650 LanguageType nLang;
4651 //Check to see if there is an up and coming cjk language property. If
4652 //there is use it, if there is not fall back to the currently set one.
4653 //Only the cjk language setting seems to matter to word, the western
4654 //one is ignored
4655 SprmResult aLang;
4656 if (m_xPlcxMan)
4657 aLang = m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CRgLid1_80::val);
4659 if (aLang.pSprm && aLang.nRemainingData >= 2)
4660 nLang = LanguageType(SVBT16ToUInt16(aLang.pSprm));
4661 else
4663 nLang = static_cast<const SvxLanguageItem *>(
4664 GetFormatAttr(RES_CHRATR_CJK_LANGUAGE))->GetLanguage();
4667 FontEmphasisMark nVal;
4668 switch( *pData )
4670 case 0:
4671 nVal = FontEmphasisMark::NONE;
4672 break;
4673 case 2:
4674 if (MsLangId::isKorean(nLang) || MsLangId::isTraditionalChinese(nLang))
4675 nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4676 else if (nLang == LANGUAGE_JAPANESE)
4677 nVal = (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove);
4678 else
4679 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4680 break;
4681 case 3:
4682 nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
4683 break;
4684 case 4:
4685 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4686 break;
4687 case 1:
4688 if (MsLangId::isSimplifiedChinese(nLang))
4689 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
4690 else
4691 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4692 break;
4693 default:
4694 nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
4695 break;
4698 NewAttr( SvxEmphasisMarkItem( nVal, RES_CHRATR_EMPHASIS_MARK ) );
4702 void SwWW8ImplReader::Read_ScaleWidth( sal_uInt16, const sal_uInt8* pData, short nLen )
4704 if (nLen < 2)
4705 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SCALEW );
4706 else
4708 sal_uInt16 nVal = SVBT16ToUInt16( pData );
4709 //The number must be between 1 and 600
4710 if (nVal < 1 || nVal > 600)
4711 nVal = 100;
4712 NewAttr( SvxCharScaleWidthItem( nVal, RES_CHRATR_SCALEW ) );
4716 void SwWW8ImplReader::Read_Relief( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
4718 if (nLen < 1)
4719 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_RELIEF );
4720 else
4722 if( *pData )
4724 // not so easy because this is also a toggle attribute!
4725 // 2 x emboss on -> no emboss !!!
4726 // the actual value must be searched over the stack / template
4728 const SvxCharReliefItem* pOld = static_cast<const SvxCharReliefItem*>(
4729 GetFormatAttr( RES_CHRATR_RELIEF ));
4730 FontRelief nNewValue = NS_sprm::CFImprint::val == nId ? FontRelief::Engraved
4731 : ( NS_sprm::CFEmboss::val == nId ? FontRelief::Embossed
4732 : FontRelief::NONE );
4733 if( pOld->GetValue() == nNewValue )
4735 if( FontRelief::NONE != nNewValue )
4736 nNewValue = FontRelief::NONE;
4738 NewAttr( SvxCharReliefItem( nNewValue, RES_CHRATR_RELIEF ));
4743 void SwWW8ImplReader::Read_TextAnim(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
4745 if (nLen < 1)
4746 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_BLINK);
4747 else
4749 if (*pData)
4751 bool bBlink;
4753 // The 7 animated text effects available in word all get
4754 // mapped to a blinking text effect in LibreOffice
4755 // 0 no animation 1 Las Vegas lights
4756 // 2 background blink 3 sparkle text
4757 // 4 marching ants 5 marching red ants
4758 // 6 shimmer
4759 bBlink = *pData > 0 && *pData < 7;
4761 NewAttr(SvxBlinkItem(bBlink, RES_CHRATR_BLINK));
4766 SwWW8Shade::SwWW8Shade(bool bVer67, const WW8_SHD& rSHD)
4768 sal_uInt8 b = rSHD.GetFore();
4769 OSL_ENSURE(b < 17, "ww8: colour out of range");
4770 if (b >= 17)
4771 b = 0;
4773 Color nFore(SwWW8ImplReader::GetCol(b));
4775 b = rSHD.GetBack();
4776 OSL_ENSURE(b < 17, "ww8: colour out of range");
4777 if( b >= 17 )
4778 b = 0;
4780 Color nBack(SwWW8ImplReader::GetCol(b));
4782 b = rSHD.GetStyle(bVer67);
4784 SetShade(nFore, nBack, b);
4787 void SwWW8Shade::SetShade(Color nFore, Color nBack, sal_uInt16 nIndex)
4789 static const sal_uLong eMSGrayScale[] =
4791 // Clear-Brush
4792 0, // 0 clear
4793 // Solid-Brush
4794 1000, // 1 solid
4795 // Percent values
4796 50, // 2 pct5
4797 100, // 3 pct10
4798 200, // 4 pct20
4799 250, // 5 pct25
4800 300, // 6 pct30
4801 400, // 7 pct40
4802 500, // 8 pct50
4803 600, // 9 pct60
4804 700, // 10 pct70
4805 750, // 11 pct75
4806 800, // 12 pct80
4807 900, // 13 pct90
4808 // Special cases
4809 333, // 14 Dark Horizontal
4810 333, // 15 Dark Vertical
4811 333, // 16 Dark Forward Diagonal
4812 333, // 17 Dark Backward Diagonal
4813 333, // 18 Dark Cross
4814 333, // 19 Dark Diagonal Cross
4815 333, // 20 Horizontal
4816 333, // 21 Vertical
4817 333, // 22 Forward Diagonal
4818 333, // 23 Backward Diagonal
4819 333, // 24 Cross
4820 333, // 25 Diagonal Cross
4821 // Undefined values in DOC spec-sheet
4822 500, // 26
4823 500, // 27
4824 500, // 28
4825 500, // 29
4826 500, // 30
4827 500, // 31
4828 500, // 32
4829 500, // 33
4830 500, // 34
4831 // Different shading types
4832 25, // 35 [available in DOC, not available in DOCX]
4833 75, // 36 [available in DOC, not available in DOCX]
4834 125, // 37 pct12
4835 150, // 38 pct15
4836 175, // 39 [available in DOC, not available in DOCX]
4837 225, // 40 [available in DOC, not available in DOCX]
4838 275, // 41 [available in DOC, not available in DOCX]
4839 325, // 42 [available in DOC, not available in DOCX]
4840 350, // 43 pct35
4841 375, // 44 pct37
4842 425, // 45 [available in DOC, not available in DOCX]
4843 450, // 46 pct45
4844 475, // 47 [available in DOC, not available in DOCX]
4845 525, // 48 [available in DOC, not available in DOCX]
4846 550, // 49 pct55
4847 575, // 50 [available in DOC, not available in DOCX]
4848 625, // 51 pct62
4849 650, // 52 pct65
4850 675, // 53 [available in DOC, not available in DOCX]
4851 725, // 54 [available in DOC, not available in DOCX]
4852 775, // 55 [available in DOC, not available in DOCX]
4853 825, // 56 [available in DOC, not available in DOCX]
4854 850, // 57 pct85
4855 875, // 58 pct87
4856 925, // 59 [available in DOC, not available in DOCX]
4857 950, // 60 pct95
4858 975 // 61 [available in DOC, not available in DOCX]
4859 };// 62
4861 //NO auto for shading so Foreground: Auto = Black
4862 if (nFore == COL_AUTO)
4863 nFore = COL_BLACK;
4865 //NO auto for shading so background: Auto = White
4866 Color nUseBack = nBack;
4867 if (nUseBack == COL_AUTO)
4868 nUseBack = COL_WHITE;
4870 if( nIndex >= SAL_N_ELEMENTS( eMSGrayScale ) )
4871 nIndex = 0;
4873 sal_uLong nWW8BrushStyle = eMSGrayScale[nIndex];
4875 switch (nWW8BrushStyle)
4877 case 0: // Null-Brush
4878 aColor = nBack;
4879 break;
4880 default:
4882 Color aForeColor(nFore);
4883 Color aBackColor(nUseBack);
4885 sal_uInt32 nRed = aForeColor.GetRed() * nWW8BrushStyle;
4886 sal_uInt32 nGreen = aForeColor.GetGreen() * nWW8BrushStyle;
4887 sal_uInt32 nBlue = aForeColor.GetBlue() * nWW8BrushStyle;
4888 nRed += aBackColor.GetRed() * (1000 - nWW8BrushStyle);
4889 nGreen += aBackColor.GetGreen()* (1000 - nWW8BrushStyle);
4890 nBlue += aBackColor.GetBlue() * (1000 - nWW8BrushStyle);
4892 aColor = Color( nRed/1000, nGreen/1000, nBlue/1000 );
4894 break;
4898 void SwWW8ImplReader::Read_Shade( sal_uInt16, const sal_uInt8* pData, short nLen )
4900 if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PShd::val).pSprm)
4901 return;
4903 if (nLen < 2)
4905 // end of attribute
4906 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
4907 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
4909 else
4911 WW8_SHD aSHD;
4912 aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
4913 SwWW8Shade aSh( m_bVer67, aSHD );
4915 NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
4916 NewAttr( XFillColorItem(OUString(), aSh.aColor) );
4920 void SwWW8ImplReader::Read_ParaBackColor(sal_uInt16, const sal_uInt8* pData, short nLen)
4922 if (nLen <= 0)
4924 // end of attribute
4925 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
4926 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
4928 else
4930 OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
4931 if (nLen != 10)
4932 return;
4934 const Color aColor = ExtractColour(pData, m_bVer67);
4935 NewAttr( XFillColorItem(OUString(), aColor) );
4936 if ( aColor == COL_AUTO )
4937 NewAttr( XFillStyleItem(drawing::FillStyle_NONE) );
4938 else
4939 NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
4943 Color SwWW8ImplReader::ExtractColour(const sal_uInt8* &rpData, bool bVer67)
4945 OSL_ENSURE(!bVer67, "Impossible");
4946 Color nFore = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
4947 rpData+=4;
4948 Color nBack = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
4949 rpData+=4;
4950 sal_uInt16 nIndex = SVBT16ToUInt16(rpData);
4951 rpData+=2;
4952 //Being a transparent background colour doesn't actually show the page
4953 //background through, it merely acts like white
4954 if (nBack == Color(0xFF000000))
4955 nBack = COL_AUTO;
4956 OSL_ENSURE(nBack == COL_AUTO || (nBack.GetTransparency() == 0),
4957 "ww8: don't know what to do with such a transparent bg colour, report");
4958 SwWW8Shade aShade(nFore, nBack, nIndex);
4959 return aShade.aColor;
4962 void SwWW8ImplReader::Read_TextVerticalAdjustment( sal_uInt16, const sal_uInt8* pData, short nLen )
4964 if( nLen <= 0 )
4965 return;
4967 drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
4968 switch( *pData )
4970 case 1:
4971 nVA = drawing::TextVerticalAdjust_CENTER;
4972 break;
4973 case 2: //justify
4974 nVA = drawing::TextVerticalAdjust_BLOCK;
4975 break;
4976 case 3:
4977 nVA = drawing::TextVerticalAdjust_BOTTOM;
4978 break;
4979 default:
4980 break;
4982 m_aSectionManager.SetCurrentSectionVerticalAdjustment( nVA );
4985 void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
4987 if (nLen < 0)
4989 if( m_bHasBorder )
4991 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BOX );
4992 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_SHADOW );
4993 m_bHasBorder = false;
4996 else if( !m_bHasBorder )
4998 // the borders on all four sides are bundled. That
4999 // simplifies the administration, i.e., the box does not have
5000 // to be put on and removed from CtrlStack 4 times.
5001 m_bHasBorder = true;
5003 WW8_BRCVer9_5 aBrcs; // Top, Left, Bottom, Right, Between
5004 sal_uInt8 nBorder;
5006 if( m_pCurrentColl )
5007 nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, nullptr, m_xStyles.get());
5008 else
5009 nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr);
5011 if( nBorder ) // Border
5013 bool bIsB = IsBorder(aBrcs, true);
5014 if (!InLocalApo() || !bIsB || (m_xWFlyPara && !m_xWFlyPara->bBorderLines))
5016 // Do not turn *on* borders in APO, since otherwise
5017 // I get the Fly border twice;
5018 // but only when it is set on in the Fly, skip it;
5019 // otherwise there is none at all!
5021 // even if no border is set, the attribute has to be set,
5022 // otherwise it's not possible to turn off the style attribute.
5023 const SvxBoxItem* pBox
5024 = static_cast<const SvxBoxItem*>(GetFormatAttr( RES_BOX ));
5025 std::shared_ptr<SvxBoxItem> aBox(std::make_shared<SvxBoxItem>(RES_BOX));
5026 if (pBox)
5027 aBox.reset(pBox->Clone());
5028 short aSizeArray[5]={0};
5030 SetBorder(*aBox, aBrcs, &aSizeArray[0], nBorder);
5032 tools::Rectangle aInnerDist;
5033 GetBorderDistance( aBrcs, aInnerDist );
5035 if (nBorder & (1 << WW8_LEFT))
5036 aBox->SetDistance( static_cast<sal_uInt16>(aInnerDist.Left()), SvxBoxItemLine::LEFT );
5038 if (nBorder & (1 << WW8_TOP))
5039 aBox->SetDistance( static_cast<sal_uInt16>(aInnerDist.Top()), SvxBoxItemLine::TOP );
5041 if (nBorder & (1 << WW8_RIGHT))
5042 aBox->SetDistance( static_cast<sal_uInt16>(aInnerDist.Right()), SvxBoxItemLine::RIGHT );
5044 if (nBorder & (1 << WW8_BOT))
5045 aBox->SetDistance( static_cast<sal_uInt16>(aInnerDist.Bottom()), SvxBoxItemLine::BOTTOM );
5047 NewAttr( *aBox );
5049 SvxShadowItem aS(RES_SHADOW);
5050 // Word only allows shadows on visible borders
5051 if ( aBox->CalcLineSpace( SvxBoxItemLine::RIGHT ) )
5052 SetShadow( aS, &aSizeArray[0], aBrcs[WW8_RIGHT] );
5053 NewAttr( aS );
5059 void SwWW8ImplReader::Read_CharBorder(sal_uInt16 nId, const sal_uInt8* pData, short nLen )
5061 //Ignore this old border type
5062 //if (!bVer67 && pPlcxMan && pPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CBrc::val))
5063 // return;
5065 if (nLen < 0)
5067 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BOX );
5068 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SHADOW );
5070 else
5072 const SvxBoxItem* pBox
5073 = static_cast<const SvxBoxItem*>(GetFormatAttr( RES_CHRATR_BOX ));
5074 if( pBox )
5076 std::unique_ptr<SvxBoxItem> aBoxItem(pBox->Clone());
5077 WW8_BRCVer9 aBrc;
5078 int nBrcVer = (nId == NS_sprm::CBrc::val) ? 9 : (m_bVer67 ? 6 : 8);
5080 SetWW8_BRC(nBrcVer, aBrc, pData, nLen);
5082 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::TOP, 0, nullptr, true);
5083 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::BOTTOM, 0, nullptr, true);
5084 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::LEFT, 0, nullptr, true);
5085 Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::RIGHT, 0, nullptr, true);
5086 NewAttr( *aBoxItem );
5088 short aSizeArray[WW8_RIGHT+1]={0}; aSizeArray[WW8_RIGHT] = 1;
5089 SvxShadowItem aShadowItem(RES_CHRATR_SHADOW);
5090 // Word only allows shadows on visible borders
5091 if ( aBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) )
5092 SetShadow( aShadowItem, &aSizeArray[0], aBrc );
5093 NewAttr( aShadowItem );
5098 void SwWW8ImplReader::Read_Hyphenation( sal_uInt16, const sal_uInt8* pData, short nLen )
5100 // set Hyphenation flag
5101 if (nLen < 1)
5102 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_HYPHENZONE );
5103 else
5105 SvxHyphenZoneItem aAttr(
5106 *static_cast<const SvxHyphenZoneItem*>(GetFormatAttr( RES_PARATR_HYPHENZONE ) ));
5108 aAttr.SetHyphen( 0 == *pData ); // sic !
5110 if( !*pData )
5112 aAttr.GetMinLead() = 2;
5113 aAttr.GetMinTrail() = 2;
5114 aAttr.GetMaxHyphens() = 0;
5117 NewAttr( aAttr );
5121 void SwWW8ImplReader::Read_WidowControl( sal_uInt16, const sal_uInt8* pData, short nLen )
5123 if (nLen < 1)
5125 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_WIDOWS );
5126 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ORPHANS );
5128 else
5130 sal_uInt8 nL = ( *pData & 1 ) ? 2 : 0;
5132 NewAttr( SvxWidowsItem( nL, RES_PARATR_WIDOWS ) ); // Off -> nLines = 0
5133 NewAttr( SvxOrphansItem( nL, RES_PARATR_ORPHANS ) );
5135 if( m_pCurrentColl && m_xStyles ) // Style-Def ?
5136 m_xStyles->mbWidowsChanged = true; // save for simulation
5137 // Default-Widows
5141 void SwWW8ImplReader::Read_UsePgsuSettings(sal_uInt16,const sal_uInt8* pData,short nLen)
5143 if (nLen < 1)
5144 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_SNAPTOGRID);
5145 else
5147 if(m_nInTable)
5148 NewAttr( SvxParaGridItem(false, RES_PARATR_SNAPTOGRID) );
5149 else
5150 NewAttr( SvxParaGridItem(*pData, RES_PARATR_SNAPTOGRID) );
5154 void SwWW8ImplReader::Read_AlignFont( sal_uInt16, const sal_uInt8* pData, short nLen )
5156 if (nLen < 2)
5157 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_VERTALIGN);
5158 else
5160 sal_uInt16 nVal = SVBT16ToUInt16( pData );
5161 SvxParaVertAlignItem::Align nAlign;
5162 switch (nVal)
5164 case 0:
5165 nAlign = SvxParaVertAlignItem::Align::Top;
5166 break;
5167 case 1:
5168 nAlign = SvxParaVertAlignItem::Align::Center;
5169 break;
5170 case 2:
5171 nAlign = SvxParaVertAlignItem::Align::Baseline;
5172 break;
5173 case 3:
5174 nAlign = SvxParaVertAlignItem::Align::Bottom;
5175 break;
5176 case 4:
5177 nAlign = SvxParaVertAlignItem::Align::Automatic;
5178 break;
5179 default:
5180 nAlign = SvxParaVertAlignItem::Align::Automatic;
5181 OSL_ENSURE(false,"Unknown paragraph vertical align");
5182 break;
5184 NewAttr( SvxParaVertAlignItem( nAlign, RES_PARATR_VERTALIGN ) );
5188 void SwWW8ImplReader::Read_KeepLines( sal_uInt16, const sal_uInt8* pData, short nLen )
5190 if (nLen < 1)
5191 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_SPLIT );
5192 else
5193 NewAttr( SvxFormatSplitItem( ( *pData & 1 ) == 0, RES_PARATR_SPLIT ) );
5196 void SwWW8ImplReader::Read_KeepParas( sal_uInt16, const sal_uInt8* pData, short nLen )
5198 if (nLen < 1)
5199 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_KEEP );
5200 else
5201 NewAttr( SvxFormatKeepItem( ( *pData & 1 ) != 0 , RES_KEEP) );
5204 void SwWW8ImplReader::Read_BreakBefore( sal_uInt16, const sal_uInt8* pData, short nLen )
5206 if (nLen < 1)
5207 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BREAK );
5208 else
5209 NewAttr( SvxFormatBreakItem(
5210 ( *pData & 1 ) ? SvxBreak::PageBefore : SvxBreak::NONE, RES_BREAK ) );
5213 void SwWW8ImplReader::Read_ApoPPC( sal_uInt16, const sal_uInt8* pData, short )
5215 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // only for Styledef, otherwise solved differently
5217 SwWW8StyInf& rSI = m_vColl[m_nCurrentColl];
5218 if (!rSI.m_xWWFly)
5219 rSI.m_xWWFly = std::make_shared<WW8FlyPara>(m_bVer67);
5220 rSI.m_xWWFly->Read(*pData, m_xStyles.get());
5221 if (rSI.m_xWWFly->IsEmpty())
5223 m_vColl[m_nCurrentColl].m_xWWFly.reset();
5228 bool SwWW8ImplReader::ParseTabPos(WW8_TablePos *pTabPos, WW8PLCFx_Cp_FKP* pPap)
5230 bool bRet = false;
5231 memset(pTabPos, 0, sizeof(WW8_TablePos));
5232 // sprmTPc contains a PositionCodeOperand structure that specifies the origin
5233 // that is used to calculate the table position when it is absolutely positioned
5234 SprmResult aRes = pPap->HasSprm(NS_sprm::TPc::val);
5235 if (aRes.pSprm && aRes.nRemainingData >= 1)
5237 pTabPos->nSp29 = *aRes.pSprm;
5238 pTabPos->nSp37 = 2; //Possible fail area, always parallel wrap
5239 aRes = pPap->HasSprm(NS_sprm::TDxaAbs::val);
5240 if (aRes.pSprm && aRes.nRemainingData >= 2)
5241 pTabPos->nSp26 = SVBT16ToUInt16(aRes.pSprm);
5242 aRes = pPap->HasSprm(NS_sprm::TDyaAbs::val);
5243 if (aRes.pSprm && aRes.nRemainingData >= 2)
5244 pTabPos->nSp27 = SVBT16ToUInt16(aRes.pSprm);
5245 aRes = pPap->HasSprm(NS_sprm::TDxaFromText::val);
5246 if (aRes.pSprm && aRes.nRemainingData >= 2)
5247 pTabPos->nLeMgn = SVBT16ToUInt16(aRes.pSprm);
5248 aRes = pPap->HasSprm(NS_sprm::TDxaFromTextRight::val);
5249 if (aRes.pSprm && aRes.nRemainingData >= 2)
5250 pTabPos->nRiMgn = SVBT16ToUInt16(aRes.pSprm);
5251 aRes = pPap->HasSprm(NS_sprm::TDyaFromText::val);
5252 if (aRes.pSprm && aRes.nRemainingData >= 2)
5253 pTabPos->nUpMgn = SVBT16ToUInt16(aRes.pSprm);
5254 aRes = pPap->HasSprm(NS_sprm::TDyaFromTextBottom::val);
5255 if (aRes.pSprm && aRes.nRemainingData >= 2)
5256 pTabPos->nLoMgn = SVBT16ToUInt16(aRes.pSprm);
5257 pTabPos->bNoFly = !FloatingTableConversion(pPap);
5258 bRet = true;
5260 return bRet;
5263 // page attribute won't be used as attribute anymore
5264 // ( except OLST )
5265 tools::Long SwWW8ImplReader::ImportExtSprm(WW8PLCFManResult* pRes)
5267 // array for reading of the extended ( self-defined ) SPRMs
5268 typedef tools::Long (SwWW8ImplReader::*FNReadRecordExt)(WW8PLCFManResult*);
5270 static const FNReadRecordExt aWwSprmTab[] =
5272 /* 0 (256) */ &SwWW8ImplReader::Read_Footnote, // FootNote
5273 /* 1 (257) */ &SwWW8ImplReader::Read_Footnote, // EndNote
5274 /* 2 (258) */ &SwWW8ImplReader::Read_Field, // Field
5275 /* 3 (259) */ &SwWW8ImplReader::Read_Book, // Bookmark
5276 /* 4 (260) */ &SwWW8ImplReader::Read_And, // Annotation
5277 /* 5 (261) */ &SwWW8ImplReader::Read_AtnBook, // Annotationmark
5278 /* 6 (262) */ &SwWW8ImplReader::Read_FactoidBook // Smart tag bookmark
5281 if( pRes->nSprmId < 280 )
5283 sal_uInt8 nIdx = static_cast< sal_uInt8 >(pRes->nSprmId - eFTN);
5284 if( nIdx < SAL_N_ELEMENTS(aWwSprmTab)
5285 && aWwSprmTab[nIdx] )
5286 return (this->*aWwSprmTab[nIdx])(pRes);
5287 else
5288 return 0;
5290 else
5291 return 0;
5294 void SwWW8ImplReader::EndExtSprm(sal_uInt16 nSprmId)
5296 typedef sal_uInt16 (SwWW8ImplReader::*FNReadRecordExt)();
5298 static const FNReadRecordExt aWwSprmTab[] =
5300 /* 0 (256) */ &SwWW8ImplReader::End_Footnote, // FootNote
5301 /* 1 (257) */ &SwWW8ImplReader::End_Footnote, // EndNote
5302 /* 2 (258) */ &SwWW8ImplReader::End_Field, // Field
5303 /* 3 (259) */ nullptr, // Bookmark
5304 /* 4 (260) */ nullptr // Annotation
5307 sal_uInt8 nIdx = static_cast< sal_uInt8 >(nSprmId - eFTN);
5308 if( nIdx < SAL_N_ELEMENTS(aWwSprmTab)
5309 && aWwSprmTab[nIdx] )
5310 (this->*aWwSprmTab[nIdx])();
5313 // arrays for reading the SPRMs
5315 // function for reading of SPRMs. Par1: SprmId
5316 typedef void (SwWW8ImplReader::*FNReadRecord)( sal_uInt16, const sal_uInt8*, short );
5318 struct SprmReadInfo
5320 sal_uInt16 nId;
5321 FNReadRecord pReadFnc;
5324 static bool operator<(const SprmReadInfo &rFirst, const SprmReadInfo &rSecond)
5326 return (rFirst.nId < rSecond.nId);
5329 typedef ww::SortedArray<SprmReadInfo> wwSprmDispatcher;
5331 static const wwSprmDispatcher *GetWW2SprmDispatcher()
5333 static SprmReadInfo aSprms[] =
5335 {0, nullptr}, // "0" default resp. error
5336 // will be skipped! ,
5337 {2, &SwWW8ImplReader::Read_StyleCode}, //"sprmPIstd", pap.istd
5338 //(style code)
5339 {3, nullptr}, //"sprmPIstdPermute", pap.istd
5340 //permutation
5341 {4, nullptr}, //"sprmPIncLv1",
5342 //pap.istddifference
5343 {5, &SwWW8ImplReader::Read_Justify}, //"sprmPJc", pap.jc
5344 //(justification)
5345 {6, nullptr}, //"sprmPFSideBySide",
5346 //pap.fSideBySide
5347 {7, &SwWW8ImplReader::Read_KeepLines}, //"sprmPFKeep", pap.fKeep
5348 {8, &SwWW8ImplReader::Read_KeepParas}, //"sprmPFKeepFollow ",
5349 //pap.fKeepFollow
5350 {9, &SwWW8ImplReader::Read_BreakBefore}, //"sprmPPageBreakBefore",
5351 //pap.fPageBreakBefore
5352 {10, nullptr}, //"sprmPBrcl", pap.brcl
5353 {11, nullptr}, //"sprmPBrcp ", pap.brcp
5354 {12, &SwWW8ImplReader::Read_ANLevelDesc}, //"sprmPAnld", pap.anld (ANLD
5355 //structure)
5356 {13, &SwWW8ImplReader::Read_ANLevelNo}, //"sprmPNLvlAnm", pap.nLvlAnm
5357 //nn
5358 {14, &SwWW8ImplReader::Read_NoLineNumb}, //"sprmPFNoLineNumb", ap.fNoLnn
5359 {15, &SwWW8ImplReader::Read_Tab}, //"?sprmPChgTabsPapx",
5360 //pap.itbdMac, ...
5361 {16, &SwWW8ImplReader::Read_LR}, //"sprmPDxaRight", pap.dxaRight
5362 {17, &SwWW8ImplReader::Read_LR}, //"sprmPDxaLeft", pap.dxaLeft
5363 {18, nullptr}, //"sprmPNest", pap.dxaLeft
5364 {19, &SwWW8ImplReader::Read_LR}, //"sprmPDxaLeft1", pap.dxaLeft1
5365 {20, &SwWW8ImplReader::Read_LineSpace}, //"sprmPDyaLine", pap.lspd
5366 //an LSPD
5367 {21, &SwWW8ImplReader::Read_UL}, //"sprmPDyaBefore",
5368 //pap.dyaBefore
5369 {22, &SwWW8ImplReader::Read_UL}, //"sprmPDyaAfter", pap.dyaAfter
5370 {23, nullptr}, //"?sprmPChgTabs", pap.itbdMac,
5371 //pap.rgdxaTab, ...
5372 {24, nullptr}, //"sprmPFInTable", pap.fInTable
5373 {25, &SwWW8ImplReader::Read_TabRowEnd}, //"sprmPTtp", pap.fTtp
5374 {26, nullptr}, //"sprmPDxaAbs", pap.dxaAbs
5375 {27, nullptr}, //"sprmPDyaAbs", pap.dyaAbs
5376 {28, nullptr}, //"sprmPDxaWidth", pap.dxaWidth
5377 {29, &SwWW8ImplReader::Read_ApoPPC}, //"sprmPPc", pap.pcHorz,
5378 //pap.pcVert
5379 {30, nullptr}, //"sprmPBrcTop10", pap.brcTop
5380 //BRC10
5381 {31, nullptr}, //"sprmPBrcLeft10",
5382 //pap.brcLeft BRC10
5383 {32, nullptr}, //"sprmPBrcBottom10",
5384 //pap.brcBottom BRC10
5385 {33, nullptr}, //"sprmPBrcRight10",
5386 //pap.brcRight BRC10
5387 {34, nullptr}, //"sprmPBrcBetween10",
5388 //pap.brcBetween BRC10
5389 {35, nullptr}, //"sprmPBrcBar10", pap.brcBar
5390 //BRC10
5391 {36, nullptr}, //"sprmPFromText10",
5392 //pap.dxaFromText dxa
5393 {37, nullptr}, //"sprmPWr", pap.wr wr
5394 {38, &SwWW8ImplReader::Read_Border}, //"sprmPBrcTop", pap.brcTop BRC
5395 {39, &SwWW8ImplReader::Read_Border}, //"sprmPBrcLeft",
5396 //pap.brcLeft BRC
5397 {40, &SwWW8ImplReader::Read_Border}, //"sprmPBrcBottom",
5398 //pap.brcBottom BRC
5399 {41, &SwWW8ImplReader::Read_Border}, //"sprmPBrcRight",
5400 //pap.brcRight BRC
5401 {42, &SwWW8ImplReader::Read_Border}, //"sprmPBrcBetween",
5402 //pap.brcBetween BRC
5403 {43, nullptr}, //"sprmPBrcBar", pap.brcBar
5404 //BRC word
5405 {44, &SwWW8ImplReader::Read_Hyphenation}, //"sprmPFNoAutoHyph",
5406 //pap.fNoAutoHyph
5407 {45, nullptr}, //"sprmPWHeightAbs",
5408 //pap.wHeightAbs w
5409 {46, nullptr}, //"sprmPDcs", pap.dcs DCS
5410 {47, &SwWW8ImplReader::Read_Shade}, //"sprmPShd", pap.shd SHD
5411 {48, nullptr}, //"sprmPDyaFromText",
5412 //pap.dyaFromText dya
5413 {49, nullptr}, //"sprmPDxaFromText",
5414 //pap.dxaFromText dxa
5415 {50, nullptr}, //"sprmPFLocked", pap.fLocked
5416 //0 or 1 byte
5417 {51, &SwWW8ImplReader::Read_WidowControl}, //"sprmPFWidowControl",
5418 //pap.fWidowControl 0 or 1 byte
5419 {52, nullptr}, //"?sprmPRuler 52",
5420 {53, nullptr}, //"??53",
5421 {54, nullptr}, //"??54",
5422 {55, nullptr}, //"??55",
5423 {56, nullptr}, //"??56",
5424 {57, nullptr}, //"??57",
5425 {58, nullptr}, //"??58",
5426 {59, nullptr}, //"??59",
5428 {60, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFBold", chp.fBold 0,1,
5429 //128, or 129 byte
5430 {61, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFItalic", chp.fItalic
5431 //0,1, 128, or 129 byte
5432 {62, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFStrike", chp.fStrike
5433 //0,1, 128, or 129 byte
5434 {63, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFOutline", chp.fOutline
5435 //0,1, 128, or 129 byte
5436 {64, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFShadow", chp.fShadow
5437 //0,1, 128, or 129 byte
5438 {65, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFSmallCaps",
5439 //chp.fSmallCaps 0,1, 128, or
5440 //129 byte
5441 {66, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFCaps", chp.fCaps 0,1,
5442 //128, or 129 byte
5443 {67, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFVanish", chp.fVanish
5444 //0,1, 128, or 129 byte
5445 {68, &SwWW8ImplReader::Read_FontCode}, //"sprmCFtc", chp.ftc ftc word
5446 {69, &SwWW8ImplReader::Read_Underline}, // "sprmCKul", chp.kul kul byte
5447 {70, nullptr}, //"sprmCSizePos", chp.hps,
5448 //chp.hpsPos 3 bytes
5449 {71, &SwWW8ImplReader::Read_Kern}, //"sprmCDxaSpace",
5450 //chp.dxaSpace dxa word
5451 {72, &SwWW8ImplReader::Read_Language}, //"sprmCLid", chp.lid LID word
5452 {73, &SwWW8ImplReader::Read_TextColor}, //"sprmCIco", chp.ico ico byte
5453 {74, &SwWW8ImplReader::Read_FontSize}, //"sprmCHps", chp.hps hps word!
5454 {75, nullptr}, //"sprmCHpsInc", chp.hps byte
5455 {76, &SwWW8ImplReader::Read_SubSuperProp}, //"sprmCHpsPos", chp.hpsPos
5456 //hps byte
5457 {77, nullptr}, //"sprmCHpsPosAdj", chp.hpsPos
5458 //hps byte
5459 {78, &SwWW8ImplReader::Read_Majority}, //"?sprmCMajority", chp.fBold,
5460 //chp.fItalic, chp.fSmallCaps
5461 {80, &SwWW8ImplReader::Read_BoldBiDiUsw}, //sprmCFBoldBi
5462 {81, &SwWW8ImplReader::Read_BoldBiDiUsw}, //sprmCFItalicBi
5463 {82, &SwWW8ImplReader::Read_FontCode}, //sprmCFtcBi
5464 {83, &SwWW8ImplReader::Read_Language}, //sprmClidBi
5465 {84, &SwWW8ImplReader::Read_TextColor}, //sprmCIcoBi
5466 {85, &SwWW8ImplReader::Read_FontSize}, //sprmCHpsBi
5467 {86, nullptr}, //sprmCFBiDi
5468 {87, nullptr}, //sprmCFDiacColor
5469 {94, nullptr}, //"sprmPicBrcl", pic.brcl brcl
5470 //(see PIC structure
5471 //definition) byte
5472 {95, nullptr}, //"sprmPicScale", pic.mx,
5473 //pic.my, pic.dxaCropleft,
5474 {96, nullptr}, //"sprmPicBrcTop", pic.brcTop
5475 //BRC word
5476 {97, nullptr}, //"sprmPicBrcLeft",
5477 //pic.brcLeft BRC word
5478 {98, nullptr}, //"sprmPicBrcBottom",
5479 //pic.brcBottom BRC word
5480 {99, nullptr} //"sprmPicBrcRight",
5483 static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
5484 return &aSprmSrch;
5487 static const wwSprmDispatcher *GetWW6SprmDispatcher()
5489 static SprmReadInfo aSprms[] =
5491 {0, nullptr}, // "0" default resp. error
5492 // will be skipped!
5493 {NS_sprm::v6::sprmPIstd, &SwWW8ImplReader::Read_StyleCode}, // pap.istd (style code)
5494 {NS_sprm::v6::sprmPIstdPermute, nullptr}, // pap.istd permutation
5495 {NS_sprm::v6::sprmPIncLv1, nullptr}, // pap.istddifference
5496 {NS_sprm::v6::sprmPJc, &SwWW8ImplReader::Read_Justify}, // pap.jc (justification)
5497 {NS_sprm::v6::sprmPFSideBySide, nullptr}, // pap.fSideBySide
5498 {NS_sprm::v6::sprmPFKeep, &SwWW8ImplReader::Read_KeepLines}, // pap.fKeep
5499 {NS_sprm::v6::sprmPFKeepFollow, &SwWW8ImplReader::Read_KeepParas}, // pap.fKeepFollow
5500 {NS_sprm::v6::sprmPPageBreakBefore, &SwWW8ImplReader::Read_BreakBefore}, // pap.fPageBreakBefore
5501 {NS_sprm::v6::sprmPBrcl, nullptr}, // pap.brcl
5502 {NS_sprm::v6::sprmPBrcp, nullptr}, // pap.brcp
5503 {NS_sprm::v6::sprmPAnld, &SwWW8ImplReader::Read_ANLevelDesc}, // pap.anld (ANLD structure)
5504 {NS_sprm::v6::sprmPNLvlAnm, &SwWW8ImplReader::Read_ANLevelNo}, // pap.nLvlAnm nn
5505 {NS_sprm::v6::sprmPFNoLineNumb, &SwWW8ImplReader::Read_NoLineNumb}, // ap.fNoLnn
5506 {NS_sprm::v6::sprmPChgTabsPapx, &SwWW8ImplReader::Read_Tab}, // pap.itbdMac, ...
5507 {NS_sprm::v6::sprmPDxaRight, &SwWW8ImplReader::Read_LR}, // pap.dxaRight
5508 {NS_sprm::v6::sprmPDxaLeft, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft
5509 {NS_sprm::v6::sprmPNest, nullptr}, // pap.dxaLeft
5510 {NS_sprm::v6::sprmPDxaLeft1, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft1
5511 {NS_sprm::v6::sprmPDyaLine, &SwWW8ImplReader::Read_LineSpace}, // pap.lspd an LSPD
5512 {NS_sprm::v6::sprmPDyaBefore, &SwWW8ImplReader::Read_UL}, // pap.dyaBefore
5513 {NS_sprm::v6::sprmPDyaAfter, &SwWW8ImplReader::Read_UL}, // pap.dyaAfter
5514 {NS_sprm::v6::sprmPChgTabs, nullptr}, // pap.itbdMac, pap.rgdxaTab, ...
5515 {NS_sprm::v6::sprmPFInTable, nullptr}, // pap.fInTable
5516 {NS_sprm::v6::sprmPTtp, &SwWW8ImplReader::Read_TabRowEnd}, // pap.fTtp
5517 {NS_sprm::v6::sprmPDxaAbs, nullptr}, // pap.dxaAbs
5518 {NS_sprm::v6::sprmPDyaAbs, nullptr}, // pap.dyaAbs
5519 {NS_sprm::v6::sprmPDxaWidth, nullptr}, // pap.dxaWidth
5520 {NS_sprm::v6::sprmPPc, &SwWW8ImplReader::Read_ApoPPC}, // pap.pcHorz, pap.pcVert
5521 {NS_sprm::v6::sprmPBrcTop10, nullptr}, // pap.brcTop BRC10
5522 {NS_sprm::v6::sprmPBrcLeft10, nullptr}, // pap.brcLeft BRC10
5523 {NS_sprm::v6::sprmPBrcBottom10, nullptr}, // pap.brcBottom BRC10
5524 {NS_sprm::v6::sprmPBrcRight10, nullptr}, // pap.brcRight BRC10
5525 {NS_sprm::v6::sprmPBrcBetween10, nullptr}, // pap.brcBetween BRC10
5526 {NS_sprm::v6::sprmPBrcBar10, nullptr}, // pap.brcBar BRC10
5527 {NS_sprm::v6::sprmPFromText10, nullptr}, // pap.dxaFromText dxa
5528 {NS_sprm::v6::sprmPWr, nullptr}, // pap.wr wr
5529 {NS_sprm::v6::sprmPBrcTop, &SwWW8ImplReader::Read_Border}, // pap.brcTop BRC
5530 {NS_sprm::v6::sprmPBrcLeft, &SwWW8ImplReader::Read_Border}, // pap.brcLeft BRC
5531 {NS_sprm::v6::sprmPBrcBottom, &SwWW8ImplReader::Read_Border}, // pap.brcBottom BRC
5532 {NS_sprm::v6::sprmPBrcRight, &SwWW8ImplReader::Read_Border}, // pap.brcRight BRC
5533 {NS_sprm::v6::sprmPBrcBetween, &SwWW8ImplReader::Read_Border}, // pap.brcBetween BRC
5534 {NS_sprm::v6::sprmPBrcBar, nullptr}, // pap.brcBar BRC word
5535 {NS_sprm::v6::sprmPFNoAutoHyph, &SwWW8ImplReader::Read_Hyphenation}, // pap.fNoAutoHyph
5536 {NS_sprm::v6::sprmPWHeightAbs, nullptr}, // pap.wHeightAbs w
5537 {NS_sprm::v6::sprmPDcs, nullptr}, // pap.dcs DCS
5538 {NS_sprm::v6::sprmPShd, &SwWW8ImplReader::Read_Shade}, // pap.shd SHD
5539 {NS_sprm::v6::sprmPDyaFromText, nullptr}, // pap.dyaFromText dya
5540 {NS_sprm::v6::sprmPDxaFromText, nullptr}, // pap.dxaFromText dxa
5541 {NS_sprm::v6::sprmPFLocked, nullptr}, // pap.fLocked 0 or 1 byte
5542 {NS_sprm::v6::sprmPFWidowControl, &SwWW8ImplReader::Read_WidowControl}, // pap.fWidowControl 0 or 1 byte
5543 {NS_sprm::v6::sprmPRuler, nullptr},
5544 {53, nullptr}, //"??53",
5545 {54, nullptr}, //"??54",
5546 {55, nullptr}, //"??55",
5547 {56, nullptr}, //"??56",
5548 {57, nullptr}, //"??57",
5549 {58, nullptr}, //"??58",
5550 {59, nullptr}, //"??59",
5551 {60, nullptr}, //"??60",
5552 {61, nullptr}, //"??61",
5553 {62, nullptr}, //"??62",
5554 {63, nullptr}, //"??63",
5555 {64, &SwWW8ImplReader::Read_ParaBiDi}, //"rtl bidi ?
5556 {NS_sprm::v6::sprmCFStrikeRM, &SwWW8ImplReader::Read_CFRMarkDel}, // chp.fRMarkDel 1 or 0 bit
5557 {NS_sprm::v6::sprmCFRMark, &SwWW8ImplReader::Read_CFRMark}, // chp.fRMark 1 or 0 bit
5558 {NS_sprm::v6::sprmCFFldVanish, &SwWW8ImplReader::Read_FieldVanish}, // chp.fFieldVanish 1 or 0 bit
5559 {NS_sprm::v6::sprmCPicLocation, &SwWW8ImplReader::Read_PicLoc}, // chp.fcPic and chp.fSpec
5560 {NS_sprm::v6::sprmCIbstRMark, nullptr}, // chp.ibstRMark index into sttbRMark
5561 {NS_sprm::v6::sprmCDttmRMark, nullptr}, // chp.dttm DTTM long
5562 {NS_sprm::v6::sprmCFData, nullptr}, // chp.fData 1 or 0 bit
5563 {NS_sprm::v6::sprmCRMReason, nullptr}, // chp.idslRMReason an index to a table
5564 {NS_sprm::v6::sprmCChse, &SwWW8ImplReader::Read_CharSet}, // chp.fChsDiff and chp.chse 3 bytes
5565 {NS_sprm::v6::sprmCSymbol, &SwWW8ImplReader::Read_Symbol}, // chp.fSpec, chp.chSym and chp.ftcSym
5566 {NS_sprm::v6::sprmCFOle2, &SwWW8ImplReader::Read_Obj}, // chp.fOle2 1 or 0 bit
5567 {76, nullptr}, //"??76",
5568 {77, nullptr}, //"??77",
5569 {78, nullptr}, //"??78",
5570 {79, nullptr}, //"??79",
5571 {NS_sprm::v6::sprmCIstd, &SwWW8ImplReader::Read_CColl}, // chp.istd istd, see stylesheet definition; short
5572 {NS_sprm::v6::sprmCIstdPermute, nullptr}, // chp.istd permutation vector
5573 {NS_sprm::v6::sprmCDefault, nullptr}, // whole CHP none variable length
5574 {NS_sprm::v6::sprmCPlain, nullptr}, // whole CHP none 0
5575 {84, nullptr}, //"??84",
5576 {NS_sprm::v6::sprmCFBold, &SwWW8ImplReader::Read_BoldUsw}, // chp.fBold 0,1, 128, or 129 byte
5577 {NS_sprm::v6::sprmCFItalic, &SwWW8ImplReader::Read_BoldUsw}, // chp.fItalic 0,1, 128, or 129 byte
5578 {NS_sprm::v6::sprmCFStrike, &SwWW8ImplReader::Read_BoldUsw}, // chp.fStrike 0,1, 128, or 129 byte
5579 {NS_sprm::v6::sprmCFOutline, &SwWW8ImplReader::Read_BoldUsw}, // chp.fOutline 0,1, 128, or 129 byte
5580 {NS_sprm::v6::sprmCFShadow, &SwWW8ImplReader::Read_BoldUsw}, // chp.fShadow 0,1, 128, or 129 byte
5581 {NS_sprm::v6::sprmCFSmallCaps, &SwWW8ImplReader::Read_BoldUsw}, // chp.fSmallCaps 0,1, 128, or 129 byte
5582 {NS_sprm::v6::sprmCFCaps, &SwWW8ImplReader::Read_BoldUsw}, // chp.fCaps 0,1, 128, or 129 byte
5583 {NS_sprm::v6::sprmCFVanish, &SwWW8ImplReader::Read_BoldUsw}, // chp.fVanish 0,1, 128, or 129 byte
5584 {NS_sprm::v6::sprmCFtc, &SwWW8ImplReader::Read_FontCode}, // chp.ftc ftc word
5585 {NS_sprm::v6::sprmCKul, &SwWW8ImplReader::Read_Underline}, // chp.kul kul byte
5586 {NS_sprm::v6::sprmCSizePos, nullptr}, // chp.hps, chp.hpsPos 3 bytes
5587 {NS_sprm::v6::sprmCDxaSpace, &SwWW8ImplReader::Read_Kern}, // chp.dxaSpace dxa word
5588 {NS_sprm::v6::sprmCLid, &SwWW8ImplReader::Read_Language}, // chp.lid LID word
5589 {NS_sprm::v6::sprmCIco, &SwWW8ImplReader::Read_TextColor}, // chp.ico ico byte
5590 {NS_sprm::v6::sprmCHps, &SwWW8ImplReader::Read_FontSize}, // chp.hps hps word!
5591 {NS_sprm::v6::sprmCHpsInc, nullptr}, // chp.hps byte
5592 {NS_sprm::v6::sprmCHpsPos, &SwWW8ImplReader::Read_SubSuperProp}, // chp.hpsPos hps byte
5593 {NS_sprm::v6::sprmCHpsPosAdj, nullptr}, // chp.hpsPos hps byte
5594 {NS_sprm::v6::sprmCMajority, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fSmallCaps
5595 {NS_sprm::v6::sprmCIss, &SwWW8ImplReader::Read_SubSuper}, // chp.iss iss byte
5596 {NS_sprm::v6::sprmCHpsNew50, nullptr}, // chp.hps hps variable width, length always recorded as 2
5597 {NS_sprm::v6::sprmCHpsInc1, nullptr}, // chp.hps complex variable width, length always recorded as 2
5598 {NS_sprm::v6::sprmCHpsKern, &SwWW8ImplReader::Read_FontKern}, // chp.hpsKern hps short
5599 {NS_sprm::v6::sprmCMajority50, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fSmallCaps, chp.fVanish, ...
5600 {NS_sprm::v6::sprmCHpsMul, nullptr}, // chp.hps percentage to grow hps short
5601 {NS_sprm::v6::sprmCCondHyhen, nullptr}, // chp.ysri ysri short
5602 {111, &SwWW8ImplReader::Read_AmbiguousSPRM},//sprmCFBoldBi or font code
5603 {112, &SwWW8ImplReader::Read_AmbiguousSPRM},//sprmCFItalicBi or font code
5604 {113, &SwWW8ImplReader::Read_FontCode}, //sprmCFtcBi
5605 {114, &SwWW8ImplReader::Read_Language}, //sprmClidBi
5606 {115, &SwWW8ImplReader::Read_TextColor}, //sprmCIcoBi
5607 {116, &SwWW8ImplReader::Read_FontSize}, //sprmCHpsBi
5608 {NS_sprm::v6::sprmCFSpec, &SwWW8ImplReader::Read_Special}, // chp.fSpec 1 or 0 bit
5609 {NS_sprm::v6::sprmCFObj, &SwWW8ImplReader::Read_Obj}, // chp.fObj 1 or 0 bit
5610 {NS_sprm::v6::sprmPicBrcl, nullptr}, // pic.brcl brcl (see PIC structure definition) byte
5611 {NS_sprm::v6::sprmPicScale, nullptr}, // pic.mx, pic.my, pic.dxaCropleft,
5612 {NS_sprm::v6::sprmPicBrcTop, nullptr}, // pic.brcTop BRC word
5613 {NS_sprm::v6::sprmPicBrcLeft, nullptr}, // pic.brcLeft BRC word
5614 {NS_sprm::v6::sprmPicBrcBottom, nullptr}, // pic.brcBottom BRC word
5615 {NS_sprm::v6::sprmPicBrcRight, nullptr}, // pic.brcRight BRC word
5616 {125, nullptr}, //"??125",
5617 {126, nullptr}, //"??126",
5618 {127, nullptr}, //"??127",
5619 {128, nullptr}, //"??128",
5620 {129, nullptr}, //"??129",
5621 {130, nullptr}, //"??130",
5622 {NS_sprm::v6::sprmSScnsPgn, nullptr}, // sep.cnsPgn cns byte
5623 {NS_sprm::v6::sprmSiHeadingPgn, nullptr}, // sep.iHeadingPgn heading number level byte
5624 {NS_sprm::v6::sprmSOlstAnm, &SwWW8ImplReader::Read_OLST}, // sep.olstAnm OLST variable length
5625 {134, nullptr}, //"??135",
5626 {135, nullptr}, //"??135",
5627 {NS_sprm::v6::sprmSDxaColWidth, nullptr}, // sep.rgdxaColWidthSpacing complex 3 bytes
5628 {NS_sprm::v6::sprmSDxaColSpacing, nullptr}, // sep.rgdxaColWidthSpacing complex 3 bytes
5629 {NS_sprm::v6::sprmSFEvenlySpaced, nullptr}, // sep.fEvenlySpaced 1 or 0 byte
5630 {NS_sprm::v6::sprmSFProtected, nullptr}, // sep.fUnlocked 1 or 0 byte
5631 {NS_sprm::v6::sprmSDmBinFirst, nullptr}, // sep.dmBinFirst word
5632 {NS_sprm::v6::sprmSDmBinOther, nullptr}, // sep.dmBinOther word
5633 {NS_sprm::v6::sprmSBkc, nullptr}, // sep.bkc bkc byte BreakCode
5634 {NS_sprm::v6::sprmSFTitlePage, nullptr}, // sep.fTitlePage 0 or 1 byte
5635 {NS_sprm::v6::sprmSCcolumns, nullptr}, // sep.ccolM1 # of cols - 1 word
5636 {NS_sprm::v6::sprmSDxaColumns, nullptr}, // sep.dxaColumns dxa word
5637 {NS_sprm::v6::sprmSFAutoPgn, nullptr}, // sep.fAutoPgn obsolete byte
5638 {NS_sprm::v6::sprmSNfcPgn, nullptr}, // sep.nfcPgn nfc byte
5639 {NS_sprm::v6::sprmSDyaPgn, nullptr}, // sep.dyaPgn dya short
5640 {NS_sprm::v6::sprmSDxaPgn, nullptr}, // sep.dxaPgn dya short
5641 {NS_sprm::v6::sprmSFPgnRestart, nullptr}, // sep.fPgnRestart 0 or 1 byte
5642 {NS_sprm::v6::sprmSFEndnote, nullptr}, // sep.fEndnote 0 or 1 byte
5643 {NS_sprm::v6::sprmSLnc, nullptr}, // sep.lnc lnc byte
5644 {NS_sprm::v6::sprmSGprfIhdt, nullptr}, // sep.grpfIhdt grpfihdt byte
5645 {NS_sprm::v6::sprmSNLnnMod, nullptr}, // sep.nLnnMod non-neg int. word
5646 {NS_sprm::v6::sprmSDxaLnn, nullptr}, // sep.dxaLnn dxa word
5647 {NS_sprm::v6::sprmSDyaHdrTop, nullptr}, // sep.dyaHdrTop dya word
5648 {NS_sprm::v6::sprmSDyaHdrBottom, nullptr}, // sep.dyaHdrBottom dya word
5649 {NS_sprm::v6::sprmSLBetween, nullptr}, // sep.fLBetween 0 or 1 byte
5650 {NS_sprm::v6::sprmSVjc, nullptr}, // sep.vjc vjc byte
5651 {NS_sprm::v6::sprmSLnnMin, nullptr}, // sep.lnnMin lnn word
5652 {NS_sprm::v6::sprmSPgnStart, nullptr}, // sep.pgnStart pgn word
5653 {NS_sprm::v6::sprmSBOrientation, nullptr}, // sep.dmOrientPage dm byte
5654 {NS_sprm::v6::sprmSBCustomize, nullptr}, // ?
5655 {NS_sprm::v6::sprmSXaPage, nullptr}, // sep.xaPage xa word
5656 {NS_sprm::v6::sprmSYaPage, nullptr}, // sep.yaPage ya word
5657 {NS_sprm::v6::sprmSDxaLeft, nullptr}, // sep.dxaLeft dxa word
5658 {NS_sprm::v6::sprmSDxaRight, nullptr}, // sep.dxaRight dxa word
5659 {NS_sprm::v6::sprmSDyaTop, nullptr}, // sep.dyaTop dya word
5660 {NS_sprm::v6::sprmSDyaBottom, nullptr}, // sep.dyaBottom dya word
5661 {NS_sprm::v6::sprmSDzaGutter, nullptr}, // sep.dzaGutter dza word
5662 {NS_sprm::v6::sprmSDMPaperReq, nullptr}, // sep.dmPaperReq dm word
5663 {172, nullptr}, //"??172",
5664 {173, nullptr}, //"??173",
5665 {174, nullptr}, //"??174",
5666 {175, nullptr}, //"??175",
5667 {176, nullptr}, //"??176",
5668 {177, nullptr}, //"??177",
5669 {178, nullptr}, //"??178",
5670 {179, nullptr}, //"??179",
5671 {180, nullptr}, //"??180",
5672 {181, nullptr}, //"??181",
5673 {NS_sprm::v6::sprmTJc, nullptr}, // tap.jc jc word (low order byte is significant)
5674 {NS_sprm::v6::sprmTDxaLeft, nullptr}, // tap.rgdxaCenter dxa word
5675 {NS_sprm::v6::sprmTDxaGapHalf, nullptr}, // tap.dxaGapHalf, tap.rgdxaCenter dxa word
5676 {NS_sprm::v6::sprmTFCantSplit, nullptr}, // tap.fCantSplit 1 or 0 byte
5677 {NS_sprm::v6::sprmTTableHeader, nullptr}, // tap.fTableHeader 1 or 0 byte
5678 {NS_sprm::v6::sprmTTableBorders, nullptr}, // tap.rgbrcTable complex 12 bytes
5679 {NS_sprm::v6::sprmTDefTable10, nullptr}, // tap.rgdxaCenter, tap.rgtc complex variable length
5680 {NS_sprm::v6::sprmTDyaRowHeight, nullptr}, // tap.dyaRowHeight dya word
5681 {NS_sprm::v6::sprmTDefTable, nullptr}, // tap.rgtc complex
5682 {NS_sprm::v6::sprmTDefTableShd, nullptr}, // tap.rgshd complex
5683 {NS_sprm::v6::sprmTTlp, nullptr}, // tap.tlp TLP 4 bytes
5684 {NS_sprm::v6::sprmTSetBrc, nullptr}, // tap.rgtc[].rgbrc complex 5 bytes
5685 {NS_sprm::v6::sprmTInsert, nullptr}, // tap.rgdxaCenter, tap.rgtc complex 4 bytes
5686 {NS_sprm::v6::sprmTDelete, nullptr}, // tap.rgdxaCenter, tap.rgtc complex word
5687 {NS_sprm::v6::sprmTDxaCol, nullptr}, // tap.rgdxaCenter complex 4 bytes
5688 {NS_sprm::v6::sprmTMerge, nullptr}, // tap.fFirstMerged, tap.fMerged complex word
5689 {NS_sprm::v6::sprmTSplit, nullptr}, // tap.fFirstMerged, tap.fMerged complex word
5690 {NS_sprm::v6::sprmTSetBrc10, nullptr}, // tap.rgtc[].rgbrc complex 5 bytes
5691 {NS_sprm::v6::sprmTSetShd, nullptr}, // tap.rgshd complex 4 bytes
5692 {207, nullptr}, //dunno
5695 static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
5696 return &aSprmSrch;
5699 static const wwSprmDispatcher *GetWW8SprmDispatcher()
5701 static SprmReadInfo aSprms[] =
5703 {0, nullptr}, // "0" default resp. error
5705 {NS_sprm::PIstd::val, &SwWW8ImplReader::Read_StyleCode}, // pap.istd;istd (style code);short;
5706 {NS_sprm::PIstdPermute::val, nullptr}, // pap.istd;permutation vector;
5707 // variable length;
5708 {NS_sprm::PIncLvl::val, nullptr}, // pap.istd, pap.lvl;difference between
5709 // istd of base PAP and istd of
5710 // PAP to be produced;byte;
5711 {NS_sprm::PJc80::val, &SwWW8ImplReader::Read_Justify}, // pap.jc;jc (justification);byte;
5712 {NS_sprm::LN_PFSideBySide, nullptr}, // pap.fSideBySide;0 or 1;byte;
5713 {NS_sprm::PFKeep::val, &SwWW8ImplReader::Read_KeepLines}, // pap.fKeep;0 or 1;byte;
5714 {NS_sprm::PFKeepFollow::val, &SwWW8ImplReader::Read_KeepParas}, // pap.fKeepFollow;0 or 1;byte;
5715 {NS_sprm::PFPageBreakBefore::val, &SwWW8ImplReader::Read_BreakBefore}, // pap.fPageBreakBefore;0 or 1;byte;
5716 {NS_sprm::LN_PBrcl, nullptr}, // pap.brcl;brcl;byte;
5717 {NS_sprm::LN_PBrcp, nullptr}, // pap.brcp;brcp;byte;
5718 {NS_sprm::PIlvl::val, &SwWW8ImplReader::Read_ListLevel}, // pap.ilvl;ilvl;byte;
5719 {NS_sprm::PIlfo::val, &SwWW8ImplReader::Read_LFOPosition}, // pap.ilfo;ilfo (list index);short;
5720 {NS_sprm::PFNoLineNumb::val, &SwWW8ImplReader::Read_NoLineNumb}, // pap.fNoLnn;0 or 1;byte;
5721 {NS_sprm::PChgTabsPapx::val, &SwWW8ImplReader::Read_Tab}, // pap.itbdMac, pap.rgdxaTab, pap.rgtbd;
5722 // complex;variable length
5723 {NS_sprm::PDxaRight80::val, &SwWW8ImplReader::Read_LR}, // pap.dxaRight;dxa;word;
5724 {NS_sprm::PDxaLeft80::val, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft;dxa;word;
5725 {NS_sprm::PNest80::val, nullptr}, // pap.dxaLeft;dxa;word;
5726 {NS_sprm::PDxaLeft180::val, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft1;dxa;word;
5727 {NS_sprm::PDyaLine::val, &SwWW8ImplReader::Read_LineSpace}, // pap.lspd;an LSPD, a long word
5728 // structure consisting of a short
5729 // of dyaLine followed by a short
5730 // of fMultLinespace;long;
5731 {NS_sprm::PDyaBefore::val, &SwWW8ImplReader::Read_UL}, // pap.dyaBefore;dya;word;
5732 {NS_sprm::PDyaAfter::val, &SwWW8ImplReader::Read_UL}, // pap.dyaAfter;dya;word;
5733 {NS_sprm::PChgTabs::val, nullptr}, // pap.itbdMac, pap.rgdxaTab, pap.rgtbd;
5734 // complex;variable length;
5735 {NS_sprm::PFInTable::val, nullptr}, // pap.fInTable;0 or 1;byte;
5736 {NS_sprm::PFTtp::val, &SwWW8ImplReader::Read_TabRowEnd}, // pap.fTtp;0 or 1;byte;
5737 {NS_sprm::PDxaAbs::val, nullptr}, // pap.dxaAbs;dxa;word;
5738 {NS_sprm::PDyaAbs::val, nullptr}, // pap.dyaAbs;dya;word;
5739 {NS_sprm::PDxaWidth::val, nullptr}, // pap.dxaWidth;dxa;word;
5740 {NS_sprm::PPc::val, &SwWW8ImplReader::Read_ApoPPC}, // pap.pcHorz, pap.pcVert;complex;byte;
5741 {NS_sprm::LN_PBrcTop10, nullptr}, // pap.brcTop;BRC10;word;
5742 {NS_sprm::LN_PBrcLeft10, nullptr}, // pap.brcLeft;BRC10;word;
5743 {NS_sprm::LN_PBrcBottom10, nullptr}, // pap.brcBottom;BRC10;word;
5744 {NS_sprm::LN_PBrcRight10, nullptr}, // pap.brcRight;BRC10;word;
5745 {NS_sprm::LN_PBrcBetween10, nullptr}, // pap.brcBetween;BRC10;word;
5746 {NS_sprm::LN_PBrcBar10, nullptr}, // pap.brcBar;BRC10;word;
5747 {NS_sprm::LN_PDxaFromText10, nullptr}, // pap.dxaFromText;dxa;word;
5748 {NS_sprm::PWr::val, nullptr}, // pap.wr;wr;byte;
5749 {NS_sprm::PBrcTop80::val, &SwWW8ImplReader::Read_Border}, // pap.brcTop;BRC;long;
5750 {NS_sprm::PBrcLeft80::val, &SwWW8ImplReader::Read_Border}, // pap.brcLeft;BRC;long;
5751 {NS_sprm::PBrcBottom80::val, &SwWW8ImplReader::Read_Border}, // pap.brcBottom;BRC;long;
5752 {NS_sprm::PBrcRight80::val, &SwWW8ImplReader::Read_Border}, // pap.brcRight;BRC;long;
5753 {NS_sprm::PBrcBetween80::val, &SwWW8ImplReader::Read_Border}, // pap.brcBetween;BRC;long;
5754 {NS_sprm::PBrcBar80::val, nullptr}, // pap.brcBar;BRC;long;
5755 {NS_sprm::PFNoAutoHyph::val, &SwWW8ImplReader::Read_Hyphenation}, // pap.fNoAutoHyph;0 or 1;byte;
5756 {NS_sprm::PWHeightAbs::val, nullptr}, // pap.wHeightAbs;w;word;
5757 {NS_sprm::PDcs::val, nullptr}, // pap.dcs;DCS;short;
5758 {NS_sprm::PShd80::val, &SwWW8ImplReader::Read_Shade}, // pap.shd;SHD;word;
5759 {NS_sprm::PDyaFromText::val, nullptr}, // pap.dyaFromText;dya;word;
5760 {NS_sprm::PDxaFromText::val, nullptr}, // pap.dxaFromText;dxa;word;
5761 {NS_sprm::PFLocked::val, nullptr}, // pap.fLocked;0 or 1;byte;
5762 {NS_sprm::PFWidowControl::val, &SwWW8ImplReader::Read_WidowControl}, // pap.fWidowControl;0 or 1;byte
5763 {NS_sprm::LN_PRuler, nullptr}, // variable length;
5764 {NS_sprm::PFKinsoku::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fKinsoku;0 or 1;byte;
5765 {NS_sprm::PFWordWrap::val, nullptr}, // pap.fWordWrap;0 or 1;byte;
5766 {NS_sprm::PFOverflowPunct::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fOverflowPunct; 0 or 1;byte;
5767 {NS_sprm::PFTopLinePunct::val, nullptr}, // pap.fTopLinePunct;0 or 1;byte
5768 {NS_sprm::PFAutoSpaceDE::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fAutoSpaceDE;0 or 1;byte;
5769 {NS_sprm::PFAutoSpaceDN::val, nullptr}, // pap.fAutoSpaceDN;0 or 1;byte;
5770 {NS_sprm::PWAlignFont::val, &SwWW8ImplReader::Read_AlignFont}, // pap.wAlignFont;iFa;word;
5771 {NS_sprm::PFrameTextFlow::val, nullptr}, // pap.fVertical pap.fBackward
5772 // pap.fRotateFont;complex; word
5773 {NS_sprm::LN_PISnapBaseLine, nullptr}, // obsolete, not applicable in
5774 // Word97 and later versions;;byte;
5775 {NS_sprm::LN_PAnld, &SwWW8ImplReader::Read_ANLevelDesc}, // pap.anld;;variable length;
5776 {NS_sprm::LN_PPropRMark, nullptr}, // pap.fPropRMark;complex;
5777 // variable length;
5778 {NS_sprm::POutLvl::val, &SwWW8ImplReader::Read_POutLvl}, // pap.lvl;has no effect if pap.istd
5779 // is < 1 or is > 9;byte;
5780 {NS_sprm::PFBiDi::val, &SwWW8ImplReader::Read_ParaBiDi}, // ;;byte;
5781 {NS_sprm::PFNumRMIns::val, nullptr}, // pap.fNumRMIns;1 or 0;bit;
5782 {NS_sprm::LN_PCrLf, nullptr}, // ;;byte;
5783 {NS_sprm::PNumRM::val, nullptr}, // pap.numrm;;variable length;
5784 {NS_sprm::LN_PHugePapx, nullptr}, // ;fc in the data stream to locate
5785 // the huge grpprl;long;
5786 {NS_sprm::PHugePapx::val, nullptr}, // ;fc in the data stream to locate
5787 // the huge grpprl;long;
5788 {NS_sprm::PFUsePgsuSettings::val, &SwWW8ImplReader::Read_UsePgsuSettings}, // pap.fUsePgsuSettings;1 or 0;byte;
5789 {NS_sprm::PFAdjustRight::val, nullptr}, // pap.fAdjustRight;1 or 0;byte;
5790 {NS_sprm::CFRMarkDel::val, &SwWW8ImplReader::Read_CFRMarkDel}, // chp.fRMarkDel;1 or 0;bit;
5791 {NS_sprm::CFRMarkIns::val, &SwWW8ImplReader::Read_CFRMark}, // chp.fRMark;1 or 0;bit;
5792 {NS_sprm::CFFldVanish::val, &SwWW8ImplReader::Read_FieldVanish}, // chp.fFieldVanish;1 or 0;bit;
5793 {NS_sprm::CPicLocation::val, &SwWW8ImplReader::Read_PicLoc}, // chp.fcPic and chp.fSpec;variable
5794 // length, length recorded is always 4;
5795 {NS_sprm::CIbstRMark::val, nullptr}, // chp.ibstRMark;index into
5796 // sttbRMark;short;
5797 {NS_sprm::CDttmRMark::val, nullptr}, // chp.dttmRMark;DTTM;long;
5798 {NS_sprm::CFData::val, nullptr}, // chp.fData;1 or 0;bit;
5799 {NS_sprm::CIdslRMark::val, nullptr}, // chp.idslRMReason;an index to
5800 // a table of strings defined in
5801 // Word 6.0 executables;short;
5802 {NS_sprm::LN_CChs, &SwWW8ImplReader::Read_CharSet}, // chp.fChsDiff and chp.chse;3 bytes;
5803 {NS_sprm::CSymbol::val, &SwWW8ImplReader::Read_Symbol}, // chp.fSpec, chp.xchSym and chp.ftcSym;
5804 // variable length, length
5805 // recorded is always 4;
5806 {NS_sprm::CFOle2::val, &SwWW8ImplReader::Read_Obj}, // chp.fOle2;1 or 0;bit;
5807 //NS_sprm::LN_CIdCharType, // obsolete: not applicable in Word97
5808 // and later versions
5809 {NS_sprm::CHighlight::val, &SwWW8ImplReader::Read_CharHighlight}, // chp.fHighlight, chp.icoHighlight;ico
5810 // (fHighlight is set to 1 iff
5811 // ico is not 0);byte;
5812 {NS_sprm::LN_CObjLocation, &SwWW8ImplReader::Read_PicLoc}, // chp.fcObj;FC;long;
5813 //NS_sprm::LN_CFFtcAsciSymb, ? ? ?,
5814 {NS_sprm::CIstd::val, &SwWW8ImplReader::Read_CColl}, // chp.istd;istd,short;
5815 {NS_sprm::CIstdPermute::val, nullptr}, // chp.istd;permutation vector;
5816 // variable length;
5817 {NS_sprm::LN_CDefault, nullptr}, // whole CHP;none;variable length;
5818 {NS_sprm::CPlain::val, nullptr}, // whole CHP;none;length: 0;
5819 {NS_sprm::CKcd::val, &SwWW8ImplReader::Read_Emphasis},
5820 {NS_sprm::CFBold::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fBold;0,1, 128, or 129;byte;
5821 {NS_sprm::CFItalic::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fItalic;0,1, 128, or 129; byte;
5822 {NS_sprm::CFStrike::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fStrike;0,1, 128, or 129; byte;
5823 {NS_sprm::CFOutline::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fOutline;0,1, 128, or 129; byte;
5824 {NS_sprm::CFShadow::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fShadow;0,1, 128, or 129; byte;
5825 {NS_sprm::CFSmallCaps::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fSmallCaps;0,1, 128, or 129;byte;
5826 {NS_sprm::CFCaps::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fCaps;0,1, 128, or 129; byte;
5827 {NS_sprm::CFVanish::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fVanish;0,1, 128, or 129; byte;
5828 //NS_sprm::LN_CFtcDefault, 0, // ftc, only used internally, never
5829 // stored in file;word;
5830 {NS_sprm::CKul::val, &SwWW8ImplReader::Read_Underline}, // chp.kul;kul;byte;
5831 {NS_sprm::LN_CSizePos, nullptr}, // chp.hps, chp.hpsPos;3 bytes;
5832 {NS_sprm::CDxaSpace::val, &SwWW8ImplReader::Read_Kern}, // chp.dxaSpace;dxa;word;
5833 {NS_sprm::LN_CLid, &SwWW8ImplReader::Read_Language}, // ;only used internally, never stored;
5834 // word;
5835 {NS_sprm::CIco::val, &SwWW8ImplReader::Read_TextColor}, // chp.ico;ico;byte;
5836 {NS_sprm::CHps::val, &SwWW8ImplReader::Read_FontSize}, // chp.hps;hps;byte;
5837 {NS_sprm::LN_CHpsInc, nullptr}, // chp.hps;byte;
5838 {NS_sprm::CHpsPos::val, &SwWW8ImplReader::Read_SubSuperProp}, // chp.hpsPos;hps;byte;
5839 {NS_sprm::LN_CHpsPosAdj, nullptr}, // chp.hpsPos;hps;byte;
5840 {NS_sprm::CMajority::val, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fStrike,
5841 // chp.fSmallCaps, chp.fVanish, chp.fCaps,
5842 // chp.hps, chp.hpsPos, chp.dxaSpace,
5843 // chp.kul, chp.ico, chp.rgftc, chp.rglid;
5844 // complex;variable length, length byte
5845 // plus size of following grpprl;
5846 {NS_sprm::CIss::val, &SwWW8ImplReader::Read_SubSuper}, // chp.iss;iss;byte;
5847 {NS_sprm::LN_CHpsNew50, nullptr}, // chp.hps;hps;variable width, length
5848 // always recorded as 2;
5849 {NS_sprm::LN_CHpsInc1, nullptr}, // chp.hps;complex; variable width,
5850 // length always recorded as 2;
5851 {NS_sprm::CHpsKern::val, &SwWW8ImplReader::Read_FontKern}, // chp.hpsKern;hps;short;
5852 {NS_sprm::LN_CMajority50, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fStrike,
5853 // chp.fSmallCaps, chp.fVanish, chp.fCaps,
5854 // chp.ftc, chp.hps, chp.hpsPos, chp.kul,
5855 // chp.dxaSpace, chp.ico;complex;
5856 // variable length;
5857 {NS_sprm::LN_CHpsMul, nullptr}, // chp.hps;percentage to grow hps;short;
5858 {NS_sprm::CHresi::val, nullptr}, // ???? "sprmCYsri" chp.ysri;ysri;short;
5859 {NS_sprm::CRgFtc0::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[0];ftc for ASCII text;short;
5860 {NS_sprm::CRgFtc1::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[1];ftc for Far East text;
5861 // short;
5862 {NS_sprm::CRgFtc2::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[2];ftc for non-Far East text;
5863 // short;
5864 {NS_sprm::CCharScale::val, &SwWW8ImplReader::Read_ScaleWidth},
5865 {NS_sprm::CFDStrike::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fDStrike;;byte;
5866 {NS_sprm::CFImprint::val, &SwWW8ImplReader::Read_Relief}, // chp.fImprint;1 or 0;bit;
5867 {NS_sprm::CFSpec::val, &SwWW8ImplReader::Read_Special}, // chp.fSpec;1 or 0;bit;
5868 {NS_sprm::CFObj::val, &SwWW8ImplReader::Read_Obj}, // chp.fObj;1 or 0;bit;
5869 {NS_sprm::CPropRMark90::val, &SwWW8ImplReader::Read_CPropRMark}, // chp.fPropRMark, chp.ibstPropRMark,
5870 // chp.dttmPropRMark;Complex;variable
5871 // length always recorded as 7 bytes;
5872 {NS_sprm::CFEmboss::val, &SwWW8ImplReader::Read_Relief}, // chp.fEmboss;1 or 0;bit;
5873 {NS_sprm::CSfxText::val, &SwWW8ImplReader::Read_TextAnim}, // chp.sfxtText;text animation;byte;
5874 {NS_sprm::CFBiDi::val, &SwWW8ImplReader::Read_Bidi},
5875 {NS_sprm::LN_CFDiacColor, nullptr},
5876 {NS_sprm::CFBoldBi::val, &SwWW8ImplReader::Read_BoldBiDiUsw},
5877 {NS_sprm::CFItalicBi::val, &SwWW8ImplReader::Read_BoldBiDiUsw},
5878 {NS_sprm::CFtcBi::val, &SwWW8ImplReader::Read_FontCode},
5879 {NS_sprm::CLidBi::val, &SwWW8ImplReader::Read_Language},
5880 //NS_sprm::CIcoBi::val, ? ? ?,
5881 {NS_sprm::CHpsBi::val, &SwWW8ImplReader::Read_FontSize},
5882 {NS_sprm::CDispFldRMark::val, nullptr}, // chp.fDispFieldRMark,
5883 // chp.ibstDispFieldRMark,
5884 // chp.dttmDispFieldRMark;
5885 // Complex;variable length
5886 // always recorded as 39 bytes;
5887 {NS_sprm::CIbstRMarkDel::val, nullptr}, // chp.ibstRMarkDel;index into
5888 // sttbRMark;short;
5889 {NS_sprm::CDttmRMarkDel::val, nullptr}, // chp.dttmRMarkDel;DTTM;long;
5890 {NS_sprm::CBrc80::val, &SwWW8ImplReader::Read_CharBorder}, // chp.brc;BRC;long;
5891 {NS_sprm::CBrc::val, &SwWW8ImplReader::Read_CharBorder}, // chp.brc;BRC;long;
5892 {NS_sprm::CShd80::val, &SwWW8ImplReader::Read_CharShadow}, // chp.shd;SHD;short;
5893 {NS_sprm::CIdslRMarkDel::val, nullptr}, // chp.idslRMReasonDel;an index to
5894 // a table of strings defined in
5895 // Word 6.0 executables;short;
5896 {NS_sprm::CFUsePgsuSettings::val, nullptr}, // chp.fUsePgsuSettings; 1 or 0;bit;
5897 {NS_sprm::LN_CCpg, nullptr}, // ;;word;
5898 {NS_sprm::CRgLid0_80::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[0];
5899 // LID: for non-Far East text;word;
5900 {NS_sprm::CRgLid1_80::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[1];
5901 // LID: for Far East text;word;
5902 {NS_sprm::CIdctHint::val, &SwWW8ImplReader::Read_IdctHint}, // chp.idctHint;IDCT: byte;
5903 {NS_sprm::LN_PicBrcl, nullptr}, // pic.brcl;brcl (see PIC structure
5904 // definition);byte;
5905 {NS_sprm::LN_PicScale, nullptr}, // pic.mx, pic.my, pic.dxaCropleft,
5906 // pic.dyaCropTop pic.dxaCropRight,
5907 // pic.dyaCropBottom;Complex;
5908 // length byte plus 12 bytes;
5909 {NS_sprm::PicBrcTop80::val, nullptr}, // pic.brcTop;BRC;long;
5910 {NS_sprm::PicBrcLeft80::val, nullptr}, // pic.brcLeft;BRC;long;
5911 {NS_sprm::PicBrcBottom80::val, nullptr}, // pic.brcBottom;BRC;long;
5912 {NS_sprm::PicBrcRight80::val, nullptr}, // pic.brcRight;BRC;long;
5913 {NS_sprm::ScnsPgn::val, nullptr}, // sep.cnsPgn;cns;byte;
5914 {NS_sprm::SiHeadingPgn::val, nullptr}, // sep.iHeadingPgn;heading number level;
5915 // byte;
5916 {NS_sprm::LN_SOlstAnm, &SwWW8ImplReader::Read_OLST}, // sep.olstAnm;OLST;variable length;
5917 {NS_sprm::SDxaColWidth::val, nullptr}, // sep.rgdxaColWidthSpacing;complex;
5918 // 3 bytes;
5919 {NS_sprm::SDxaColSpacing::val, nullptr}, // sep.rgdxaColWidthSpacing;complex;
5920 // 3 bytes;
5921 {NS_sprm::SFEvenlySpaced::val, nullptr}, // sep.fEvenlySpaced; 1 or 0;byte;
5922 {NS_sprm::SFProtected::val, nullptr}, // sep.fUnlocked;1 or 0;byte;
5923 {NS_sprm::SDmBinFirst::val, nullptr}, // sep.dmBinFirst;;word;
5924 {NS_sprm::SDmBinOther::val, nullptr}, // sep.dmBinOther;;word;
5925 {NS_sprm::SBkc::val, nullptr}, // sep.bkc;bkc;byte;
5926 {NS_sprm::SFTitlePage::val, nullptr}, // sep.fTitlePage;0 or 1;byte;
5927 {NS_sprm::SCcolumns::val, nullptr}, // sep.ccolM1;# of cols - 1;word;
5928 {NS_sprm::SDxaColumns::val, nullptr}, // sep.dxaColumns;dxa;word;
5929 {NS_sprm::LN_SFAutoPgn, nullptr}, // sep.fAutoPgn;obsolete;byte;
5930 {NS_sprm::SNfcPgn::val, nullptr}, // sep.nfcPgn;nfc;byte;
5931 {NS_sprm::LN_SDyaPgn, nullptr}, // sep.dyaPgn;dya;short;
5932 {NS_sprm::LN_SDxaPgn, nullptr}, // sep.dxaPgn;dya;short;
5933 {NS_sprm::SFPgnRestart::val, nullptr}, // sep.fPgnRestart;0 or 1;byte;
5934 {NS_sprm::SFEndnote::val, nullptr}, // sep.fEndnote;0 or 1;byte;
5935 {NS_sprm::SLnc::val, nullptr}, // sep.lnc;lnc;byte;
5936 {NS_sprm::LN_SGprfIhdt, nullptr}, // sep.grpfIhdt;grpfihdt;byte;
5937 {NS_sprm::SNLnnMod::val, nullptr}, // sep.nLnnMod;non-neg int.;word;
5938 {NS_sprm::SDxaLnn::val, nullptr}, // sep.dxaLnn;dxa;word;
5939 {NS_sprm::SDyaHdrTop::val, nullptr}, // sep.dyaHdrTop;dya;word;
5940 {NS_sprm::SDyaHdrBottom::val, nullptr}, // sep.dyaHdrBottom;dya;word;
5941 {NS_sprm::SLBetween::val, nullptr}, // sep.fLBetween;0 or 1;byte;
5942 {NS_sprm::SVjc::val, &SwWW8ImplReader::Read_TextVerticalAdjustment}, // sep.vjc;vjc;byte;
5943 {NS_sprm::SLnnMin::val, nullptr}, // sep.lnnMin;lnn;word;
5944 {NS_sprm::SPgnStart97::val, nullptr}, // sep.pgnStart;pgn;word;
5945 {NS_sprm::SBOrientation::val, nullptr}, // sep.dmOrientPage;dm;byte;
5946 //NS_sprm::LN_SBCustomize, ? ? ?,
5947 {NS_sprm::SXaPage::val, nullptr}, // sep.xaPage;xa;word;
5948 {NS_sprm::SYaPage::val, nullptr}, // sep.yaPage;ya;word;
5949 {0x2205, nullptr}, // ???? "sprmSDxaLeft" sep.dxaLeft;
5950 // dxa;word;
5951 {NS_sprm::SDxaLeft::val, nullptr}, // sep.dxaLeft;dxa;word;
5952 {NS_sprm::SDxaRight::val, nullptr}, // sep.dxaRight;dxa;word;
5953 {NS_sprm::SDyaTop::val, nullptr}, // sep.dyaTop;dya;word;
5954 {NS_sprm::SDyaBottom::val, nullptr}, // sep.dyaBottom;dya;word;
5955 {NS_sprm::SDzaGutter::val, nullptr}, // sep.dzaGutter;dza;word;
5956 {NS_sprm::SDmPaperReq::val, nullptr}, // sep.dmPaperReq;dm;word;
5957 {NS_sprm::LN_SPropRMark, nullptr}, // sep.fPropRMark, sep.ibstPropRMark,
5958 // sep.dttmPropRMark;complex; variable
5959 // length always recorded as 7 bytes;
5960 //NS_sprm::SFBiDi::val, ? ? ?,
5961 //NS_sprm::LN_SFFacingCol, ? ? ?,
5962 {NS_sprm::SFRTLGutter::val, nullptr}, // set to 1 if gutter is on the right.
5963 {NS_sprm::SBrcTop80::val, nullptr}, // sep.brcTop;BRC;long;
5964 {NS_sprm::SBrcLeft80::val, nullptr}, // sep.brcLeft;BRC;long;
5965 {NS_sprm::SBrcBottom80::val, nullptr}, // sep.brcBottom;BRC;long;
5966 {NS_sprm::SBrcRight80::val, nullptr}, // sep.brcRight;BRC;long;
5967 {NS_sprm::SPgbProp::val, nullptr}, // sep.pgbProp;word;
5968 {NS_sprm::SDxtCharSpace::val, nullptr}, // sep.dxtCharSpace;dxt;long;
5969 {NS_sprm::SDyaLinePitch::val, nullptr}, // sep.dyaLinePitch;dya;
5970 // WRONG:long; RIGHT:short; !
5971 //NS_sprm::SClm::val, ? ? ?,
5972 {NS_sprm::STextFlow::val, nullptr}, // sep.wTextFlow;complex;short
5973 {NS_sprm::TJc90::val, nullptr}, // tap.jc;jc;word
5974 // (low order byte is significant);
5975 {NS_sprm::TDxaLeft::val, nullptr}, // tap.rgdxaCenter;dxa;word;
5976 {NS_sprm::TDxaGapHalf::val, nullptr}, // tap.dxaGapHalf,
5977 // tap.rgdxaCenter;dxa;word;
5978 {NS_sprm::TFCantSplit90::val, nullptr}, // tap.fCantSplit90;1 or 0;byte;
5979 {NS_sprm::TTableHeader::val, nullptr}, // tap.fTableHeader;1 or 0;byte;
5980 {NS_sprm::TFCantSplit::val, nullptr}, // tap.fCantSplit;1 or 0;byte;
5981 {NS_sprm::TTableBorders80::val, nullptr}, // tap.rgbrcTable;complex;24 bytes;
5982 {NS_sprm::LN_TDefTable10, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
5983 // variable length;
5984 {NS_sprm::TDyaRowHeight::val, nullptr}, // tap.dyaRowHeight;dya;word;
5985 {NS_sprm::TDefTable::val, nullptr}, // tap.rgtc;complex
5986 {NS_sprm::TDefTableShd80::val, nullptr}, // tap.rgshd;complex
5987 {NS_sprm::TTlp::val, nullptr}, // tap.tlp;TLP;4 bytes;
5988 //NS_sprm::TFBiDi::val, ? ? ?,
5989 //NS_sprm::LN_THTMLProps, ? ? ?,
5990 {NS_sprm::TSetBrc80::val, nullptr}, // tap.rgtc[].rgbrc;complex;5 bytes;
5991 {NS_sprm::TInsert::val, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
5992 // 4 bytes;
5993 {NS_sprm::TDelete::val, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
5994 // word;
5995 {NS_sprm::TDxaCol::val, nullptr}, // tap.rgdxaCenter;complex;4 bytes;
5996 {NS_sprm::TMerge::val, nullptr}, // tap.fFirstMerged, tap.fMerged;
5997 // complex; word;
5998 {NS_sprm::TSplit::val, nullptr}, // tap.fFirstMerged, tap.fMerged;
5999 // complex;word;
6000 {NS_sprm::LN_TSetBrc10, nullptr}, // tap.rgtc[].rgbrc;complex;5 bytes;
6001 {NS_sprm::LN_TSetShd80, nullptr}, // tap.rgshd;complex;4 bytes;
6002 {NS_sprm::LN_TSetShdOdd80, nullptr}, // tap.rgshd;complex;4 bytes;
6003 {NS_sprm::TTextFlow::val, nullptr}, // tap.rgtc[].fVertical
6004 // tap.rgtc[].fBackward
6005 // tap.rgtc[].fRotateFont
6006 // 0 or 10 or 10 or 1;word;
6007 //NS_sprm::LN_TDiagLine, ? ? ? ,
6008 {NS_sprm::TVertMerge::val, nullptr}, // tap.rgtc[].vertMerge;complex;variable
6009 // length always recorded as 2 bytes;
6010 {NS_sprm::TVertAlign::val, nullptr}, // tap.rgtc[].vertAlign;complex;variable
6011 // length always recorded as 3 bytes;
6012 {NS_sprm::CFELayout::val, &SwWW8ImplReader::Read_DoubleLine_Rotate},
6013 {NS_sprm::PItap::val, nullptr},
6014 {NS_sprm::TTableWidth::val, nullptr}, // recorded as 3 bytes;
6015 {NS_sprm::TDefTableShd::val, nullptr},
6016 {NS_sprm::TTableBorders::val, nullptr},
6017 {NS_sprm::TBrcTopCv::val, nullptr},
6018 {NS_sprm::TBrcLeftCv::val, nullptr},
6019 {NS_sprm::TBrcBottomCv::val, nullptr},
6020 {NS_sprm::TBrcRightCv::val, nullptr},
6021 {NS_sprm::TCellPaddingDefault::val, nullptr},
6022 {NS_sprm::TCellPadding::val, nullptr},
6023 {0xD238, nullptr}, // undocumented sep
6024 {NS_sprm::PBrcTop::val, &SwWW8ImplReader::Read_Border},
6025 {NS_sprm::PBrcLeft::val, &SwWW8ImplReader::Read_Border},
6026 {NS_sprm::PBrcBottom::val, &SwWW8ImplReader::Read_Border},
6027 {NS_sprm::PBrcRight::val, &SwWW8ImplReader::Read_Border},
6028 {NS_sprm::PBrcBetween::val, &SwWW8ImplReader::Read_Border},
6029 {NS_sprm::TWidthIndent::val, nullptr},
6030 {NS_sprm::CRgLid0::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[0];
6031 // LID: for non-Far East text;
6032 {NS_sprm::CRgLid1::val, nullptr}, // chp.rglid[1];
6033 // LID: for Far East text
6034 {0x6463, nullptr}, // undocumented
6035 {NS_sprm::PJc::val, &SwWW8ImplReader::Read_RTLJustify},
6036 {NS_sprm::PDxaLeft::val, &SwWW8ImplReader::Read_LR},
6037 {NS_sprm::PDxaLeft1::val, &SwWW8ImplReader::Read_LR},
6038 {NS_sprm::PDxaRight::val, &SwWW8ImplReader::Read_LR},
6039 {NS_sprm::TFAutofit::val, nullptr},
6040 {NS_sprm::TPc::val, nullptr},
6041 {NS_sprm::TDxaAbs::val, nullptr},
6042 {NS_sprm::TDyaAbs::val, nullptr},
6043 {NS_sprm::TDxaFromText::val, nullptr},
6044 {NS_sprm::SRsid::val, nullptr},
6045 {NS_sprm::SFpc::val, nullptr},
6046 {NS_sprm::PFInnerTableCell::val, &SwWW8ImplReader::Read_TabCellEnd},
6047 {NS_sprm::PFInnerTtp::val, &SwWW8ImplReader::Read_TabRowEnd},
6048 {NS_sprm::CRsidProp::val, nullptr},
6049 {NS_sprm::CRsidText::val, nullptr},
6050 {NS_sprm::CCv::val, &SwWW8ImplReader::Read_TextForeColor},
6051 {NS_sprm::CCvUl::val, &SwWW8ImplReader::Read_UnderlineColor},
6052 {NS_sprm::PShd::val, &SwWW8ImplReader::Read_ParaBackColor},
6053 {NS_sprm::PRsid::val, nullptr},
6054 {NS_sprm::TWidthBefore::val, nullptr},
6055 {NS_sprm::TSetShdTable::val, nullptr},
6056 {NS_sprm::TDefTableShdRaw::val, nullptr},
6057 {NS_sprm::CShd::val, &SwWW8ImplReader::Read_TextBackColor},
6058 {NS_sprm::SRncFtn::val, nullptr},
6059 {NS_sprm::PFDyaBeforeAuto::val, &SwWW8ImplReader::Read_ParaAutoBefore},
6060 {NS_sprm::PFDyaAfterAuto::val, &SwWW8ImplReader::Read_ParaAutoAfter},
6061 {NS_sprm::PFContextualSpacing::val, &SwWW8ImplReader::Read_ParaContextualSpacing},
6064 static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
6065 return &aSprmSrch;
6068 // helper routines : find SPRM
6070 const SprmReadInfo& SwWW8ImplReader::GetSprmReadInfo(sal_uInt16 nId) const
6072 ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
6073 const wwSprmDispatcher *pDispatcher;
6074 if (eVersion <= ww::eWW2)
6075 pDispatcher = GetWW2SprmDispatcher();
6076 else if (eVersion < ww::eWW8)
6077 pDispatcher = GetWW6SprmDispatcher();
6078 else
6079 pDispatcher = GetWW8SprmDispatcher();
6081 SprmReadInfo aSrch = {0, nullptr};
6082 aSrch.nId = nId;
6083 const SprmReadInfo* pFound = pDispatcher->search(aSrch);
6085 if (!pFound)
6087 aSrch.nId = 0;
6088 pFound = pDispatcher->search(aSrch);
6091 return *pFound;
6094 // helper routines : SPRMs
6096 void SwWW8ImplReader::EndSprm( sal_uInt16 nId )
6098 if( ( nId > 255 ) && ( nId < 0x0800 ) ) return;
6100 const SprmReadInfo& rSprm = GetSprmReadInfo( nId );
6102 if (rSprm.pReadFnc)
6103 (this->*rSprm.pReadFnc)( nId, nullptr, -1 );
6106 short SwWW8ImplReader::ImportSprm(const sal_uInt8* pPos, sal_Int32 nMemLen, sal_uInt16 nId)
6108 if (!nId)
6109 nId = m_xSprmParser->GetSprmId(pPos);
6111 OSL_ENSURE( nId != 0xff, "Sprm FF !!!!" );
6113 const SprmReadInfo& rSprm = GetSprmReadInfo(nId);
6115 sal_Int32 nFixedLen = m_xSprmParser->DistanceToData(nId);
6116 sal_Int32 nL = m_xSprmParser->GetSprmSize(nId, pPos, nMemLen);
6118 if (rSprm.pReadFnc)
6119 (this->*rSprm.pReadFnc)(nId, pPos + nFixedLen, nL - nFixedLen);
6121 return nL;
6124 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */