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