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