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