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