libreoffice module sw (master): ww8par6.cxx source file * file, you can obtain one ... 260 // seem...
TRANSCRIPT
LibreOffice Module sw (master): ww8par6.cxx Source File
LibreOffice Module sw (master) 1
MainPageRelatedPagesModulesNamespacesClassesFilesExamples
FileListFileMembers
swsourcefilterww8
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
21#include
22#include
23#include
24
25#include
26#include
27#include
28#include
29#include
30#include
31#include
32#include
33#include
34#include
35#include
36#include
37#include
38#include
39#include
40#include
41#include
42#include
43#include
44#include
45#include
46#include
47#include
48#include
49#include
50#include
51#include
52#include
53#include
54#include
55#include
56#include
57#include
58#include
59#include
60#include
61#include
62#include
63#include
64#include
65#include
66#include
67#include
68#include
69#include
70#include "sprmids.hxx"
71#include
72#include
73#include
74#include
75#include
76#include
77#include
78#include
79#include
80#include
81#include
82#include
83#include
84#include
85#include
86#include
87#include
88#include
89#include
90#include
91#include
92#include
93#include
94#include
95#include "writerhelper.hxx"
96#include "writerwordglue.hxx"
97#include "ww8scan.hxx"
98#include "ww8par2.hxx"
99#include "ww8graf.hxx"
100
101#include
102
103using namespace sw::util;
104using namespace sw::types;
105using namespace ::com::sun::star;
106using namespace nsHdFtFlags;
107
108// various
109
110#define MM_250 1417 // WW default for horizontal borders: 2.5 cm
111#define MM_200 1134 // WW default for lower border: 2.0 cm
112
113
114static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
115 const WW8RStyle* pSty = nullptr, const WW8PLCFx_SEPX* pSep = nullptr);
116
117Color SwWW8ImplReader::GetCol(sal_uInt8 nIco)
118{
119 static const Color eSwWW8ColA[] =
120 {
121 COL_AUTO, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
122 COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
123 COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
124 COL_LIGHTGRAY
125 };
126 SAL_WARN_IF(
127 nIco >= SAL_N_ELEMENTS(eSwWW8ColA), "sw.ww8",
128 "ico " HasSprm(nId); // sprm here?
143 const sal_uInt8* pS = aRes.pSprm;
144 short nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToShort(pS) : nDefaultVal;
145 return nVal;
146}
147
148static sal_uInt16 ReadUSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
149{
150 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
151 const sal_uInt8* pS = aRes.pSprm;
152 sal_uInt16 nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToShort(pS) : nDefaultVal;
153 return nVal;
154}
155
156static sal_uInt8 ReadBSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, sal_uInt8 nDefaultVal )
157{
158 SprmResult aRes = pSep->HasSprm(nId); // sprm here?
159 const sal_uInt8* pS = aRes.pSprm;
160 sal_uInt8 nVal = (pS && aRes.nRemainingData >= 1) ? *pS : nDefaultVal;
161 return nVal;
162}
163
164void wwSection::SetDirection()
165{
166 //sprmSTextFlow
167 switch (maSep.wTextFlow)
168 {
169 default:
170 OSL_ENSURE(false, "Unknown layout type");
171 SAL_FALLTHROUGH;
172 case 0:
173 meDir=SvxFrameDirection::Horizontal_LR_TB;
174 break;
175 case 1:
176 meDir=SvxFrameDirection::Vertical_RL_TB;
177 break;
178 case 2:
179 //asian letters are not rotated, western are. We can't import
180 //bottom to top going left to right, we can't do this in
181 //pages, (in drawboxes we could partly hack it with a rotated
182 //drawing box, though not frame)
183 meDir=SvxFrameDirection::Vertical_RL_TB;
184 break;
185 case 3:
186 //asian letters are not rotated, western are. We can't import
187 meDir=SvxFrameDirection::Vertical_RL_TB;
188 break;
189 case 4:
190 //asian letters are rotated, western not. We can't import
191 meDir=SvxFrameDirection::Horizontal_LR_TB;
192 break;
193 }
194
195 sal_uInt8 bRTLPgn = maSep.fBiDi;
196 if ((meDir == SvxFrameDirection::Horizontal_LR_TB) && bRTLPgn)
197 meDir = SvxFrameDirection::Horizontal_RL_TB;
198}
199
200bool wwSection::IsVertical() const
201{
202 return meDir == SvxFrameDirection::Vertical_RL_TB || meDir == SvxFrameDirection::Vertical_LR_TB;
203}
204
205/*
206 This is something of festering mapping, I'm open to better ways of doing it,
207 but primarily the grid in writer is different to that in word. In writer the
208 grid elements are squares with ruby rows inbetween. While in word there is no
209 ruby stuff, and the elements are rectangles. By misusing the ruby row I can
210 handle distortions in one direction, but its all a bit of a mess:
211*/
212void SwWW8ImplReader::SetDocumentGrid(SwFrameFormat &rFormat, const wwSection &rSection)
213{
214 if (m_bVer67)
215 return;
216
217 rFormat.SetFormatAttr(SvxFrameDirectionItem(rSection.meDir, RES_FRAMEDIR));
218
219 SwTwips nTextareaHeight = rFormat.GetFrameSize().GetHeight();
220 const SvxULSpaceItem &rUL = ItemGet(rFormat, RES_UL_SPACE);
221 nTextareaHeight -= rUL.GetUpper();
222 nTextareaHeight -= rUL.GetLower();
223
224 SwTwips nTextareaWidth = rFormat.GetFrameSize().GetWidth();
225 const SvxLRSpaceItem &rLR = ItemGet(rFormat, RES_LR_SPACE);
226 nTextareaWidth -= rLR.GetLeft();
227 nTextareaWidth -= rLR.GetRight();
228
229 if (rSection.IsVertical())
230 std::swap(nTextareaHeight, nTextareaWidth);
231
232 SwTextGridItem aGrid;
233 aGrid.SetDisplayGrid(false);
234 aGrid.SetPrintGrid(false);
235 SwTextGrid eType=GRID_NONE;
236
237 switch (rSection.maSep.clm)
238 {
239 case 0:
240 eType = GRID_NONE;
241 break;
242 default:
243 OSL_ENSURE(false, "Unknown grid type");
244 SAL_FALLTHROUGH;
245 case 3:
246 eType = GRID_LINES_CHARS;
247 aGrid.SetSnapToChars(true);
248 break;
249 case 1:
250 eType = GRID_LINES_CHARS;
251 aGrid.SetSnapToChars(false);
252 break;
253 case 2:
254 eType = GRID_LINES_ONLY;
255 break;
256 }
257
258 aGrid.SetGridType(eType);
259
260 // seem to not add external leading in word, or the character would run across
261 // two line in some cases.
262 if (eType != GRID_NONE)
263 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, false);
264
265 //force to set document as standard page mode
266 bool bSquaredMode = false;
267 m_rDoc.SetDefaultPageMode( bSquaredMode );
268 aGrid.SetSquaredMode( bSquaredMode );
269
270 //Get the size of word's default styles font
271 sal_uInt32 nCharWidth=240;
272 for (sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); ++nI)
273 {
274 if (m_vColl[nI].m_bValid && m_vColl[nI].m_pFormat &&
275 m_vColl[nI].IsWW8BuiltInDefaultStyle())
276 {
277 nCharWidth = ItemGet(*(m_vColl[nI].m_pFormat),
278 RES_CHRATR_CJK_FONTSIZE).GetHeight();
279 break;
280 }
281 }
282
283 //dxtCharSpace
284 if (rSection.maSep.dxtCharSpace)
285 {
286 sal_uInt32 nCharSpace = rSection.maSep.dxtCharSpace;
287 //main lives in top 20 bits, and is signed.
288 sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
289 nMain/=0x1000;
290 nCharWidth += nMain*20;
291
292 int nFraction = (nCharSpace & 0x00000FFF);
293 nFraction = (nFraction*20)/0xFFF;
294 nCharWidth += nFraction;
295 }
296
297 aGrid.SetBaseWidth( writer_cast(nCharWidth));
298
299 //sep.dyaLinePitch
300 sal_Int32 nLinePitch = rSection.maSep.dyaLinePitch;
301 if (nLinePitch >= 1 && nLinePitch SetAttr(*m_pPaM->GetPoint(), RES_FRAMEDIR);
316 else
317 {
318 SvxFrameDirection eDir =
319 *pData ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB;
320 NewAttr(SvxFrameDirectionItem(eDir, RES_FRAMEDIR));
321 }
322}
323
324bool wwSectionManager::SetCols(SwFrameFormat &rFormat, const wwSection &rSection,
325 sal_uInt32 nNetWidth)
326{
327 //sprmSCcolumns - number of columns - 1
328 const sal_Int16 nCols = rSection.NoCols();
329
330 if (nCols < 2) //check for no columns or other weird state
331 return false;
332
333 const sal_uInt16 nNetWriterWidth = writer_cast(nNetWidth);
334 if (nNetWriterWidth == 0)
335 return false;
336
337 SwFormatCol aCol; // Create SwFormatCol
338
339 //sprmSDxaColumns - Default distance is 1.25 cm
340 sal_Int32 nColSpace = rSection.StandardColSeparation();
341
342 const SEPr& rSep = rSection.maSep;
343
344 // sprmSLBetween
345 if (rSep.fLBetween)
346 {
347 aCol.SetLineAdj(COLADJ_TOP); // Line
348 aCol.SetLineHeight(100);
349 aCol.SetLineColor(COL_BLACK);
350 aCol.SetLineWidth(1);
351 }
352
353 aCol.Init(nCols, writer_cast(nColSpace), nNetWriterWidth);
354
355 // sprmSFEvenlySpaced
356 if (!rSep.fEvenlySpaced)
357 {
358 aCol.SetOrtho_(false);
359 const sal_uInt16 maxIdx = SAL_N_ELEMENTS(rSep.rgdxaColumnWidthSpacing);
360 for (sal_uInt16 i = 0, nIdx = 1; i < nCols && nIdx < maxIdx; i++, nIdx+=2 )
361 {
362 SwColumn* pCol = &aCol.GetColumns()[i];
363 const sal_Int32 nLeft = rSep.rgdxaColumnWidthSpacing[nIdx-1]/2;
364 const sal_Int32 nRight = rSep.rgdxaColumnWidthSpacing[nIdx+1]/2;
365 const sal_Int32 nWishWidth = rSep.rgdxaColumnWidthSpacing[nIdx]
366 + nLeft + nRight;
367 pCol->SetWishWidth(writer_cast(nWishWidth));
368 pCol->SetLeft(writer_cast(nLeft));
369 pCol->SetRight(writer_cast(nRight));
370 }
371 aCol.SetWishWidth(nNetWriterWidth);
372 }
373 rFormat.SetFormatAttr(aCol);
374 return true;
375}
376
377void wwSectionManager::SetLeftRight(wwSection &rSection)
378{
379 // 3. LR-Margin
380 sal_uInt32 nWWLe = MSRoundTweak(rSection.maSep.dxaLeft);
381 sal_uInt32 nWWRi = MSRoundTweak(rSection.maSep.dxaRight);
382 sal_uInt32 nWWGu = rSection.maSep.dzaGutter;
383
384 /*
385 fRTLGutter is set if the gutter is on the right, the gutter is otherwise
386 placed on the left unless the global dop options are to put it on top, that
387 case is handled in GetPageULData.
388 */
389 if (rSection.maSep.fRTLGutter)
390 nWWRi += nWWGu;
391 else if (!mrReader.m_xWDop->iGutterPos)
392 nWWLe += nWWGu;
393
394 // Left / Right
395 if ((rSection.nPgWidth - nWWLe - nWWRi) < MINLAY)
396 {
397 /*
398 There are some label templates which are "broken", they specify
399 margins which make no sense e.g. Left 16.10cm, Right 16.10cm. So the
400 space left between the margins is less than 0 In word the left margin
401 is honoured and if the right margin would be past the left margin is
402 left at the left margin position.
403
404 Now this will work fine for importing, layout and exporting, *but* the
405 page layout dialog has a hardcoded minimum page width of 0.5cm so it
406 will report a different value than what is actually being used. i.e.
407 it will add up the values to give a wider page than is actually being
408 used.
409 */
410 nWWRi = rSection.nPgWidth - nWWLe - MINLAY;
411 }
412
413 rSection.nPgLeft = nWWLe;
414 rSection.nPgRight = nWWRi;
415}
416
417void wwSectionManager::SetPage(SwPageDesc &rInPageDesc, SwFrameFormat &rFormat,
418 const wwSection &rSection, bool bIgnoreCols)
419{
420 // 1. orientation
421 rInPageDesc.SetLandscape(rSection.IsLandScape());
422
423 // 2. paper size
424 SwFormatFrameSize aSz( rFormat.GetFrameSize() );
425 aSz.SetWidth(rSection.GetPageWidth());
426 aSz.SetHeight(SvxPaperInfo::GetSloppyPaperDimension(rSection.GetPageHeight()));
427 rFormat.SetFormatAttr(aSz);
428
429 rFormat.SetFormatAttr(
430 SvxLRSpaceItem(rSection.GetPageLeft(), rSection.GetPageRight(), 0, 0, RES_LR_SPACE));
431
432 if (!bIgnoreCols)
433 SetCols(rFormat, rSection, rSection.GetTextAreaWidth());
434}
435
436namespace {
437// Returns corrected (ODF) margin size
438long SetBorderDistance(bool bFromEdge, SvxBoxItem& aBox, SvxBoxItemLine eLine, long nMSMargin)
439{
440 const editeng::SvxBorderLine* pLine = aBox.GetLine(eLine);
441 if (!pLine)
442 return nMSMargin;
443 sal_Int32 nNewMargin = nMSMargin;
444 sal_Int32 nNewDist = aBox.GetDistance(eLine);
445 sal_Int32 nLineWidth = pLine->GetScaledWidth();
446
447 editeng::BorderDistanceFromWord(bFromEdge, nNewMargin, nNewDist, nLineWidth);
448 aBox.SetDistance(nNewDist, eLine);
449
450 return nNewMargin;
451}
452}
453
454void SwWW8ImplReader::SetPageBorder(SwFrameFormat &rFormat, const wwSection &rSection)
455{
456 if (!IsBorder(rSection.brc))
457 return;
458
459 SfxItemSet aSet(rFormat.GetAttrSet());
460 short aSizeArray[5]={0};
461 SetFlyBordersShadow(aSet, rSection.brc, &aSizeArray[0]);
462 SvxLRSpaceItem aLR(ItemGet(aSet, RES_LR_SPACE));
463 SvxULSpaceItem aUL(ItemGet(aSet, RES_UL_SPACE));
464 SvxBoxItem aBox(ItemGet(aSet, RES_BOX));
465 bool bFromEdge = rSection.maSep.pgbOffsetFrom == 1;
466
467 aLR.SetLeft(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::LEFT, aLR.GetLeft()));
468 aLR.SetRight(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::RIGHT, aLR.GetRight()));
469 aUL.SetUpper(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::TOP, aUL.GetUpper()));
470 aUL.SetLower(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::BOTTOM, aUL.GetLower()));
471
472 aSet.Put(aBox);
473 aSet.Put(aLR);
474 aSet.Put(aUL);
475 rFormat.SetFormatAttr(aSet);
476}
477
478void wwSectionManager::GetPageULData(const wwSection &rSection,
479 wwSectionManager::wwULSpaceData& rData) const
480{
481 sal_Int32 nWWUp = rSection.maSep.dyaTop;
482 sal_Int32 nWWLo = rSection.maSep.dyaBottom;
483 sal_uInt32 nWWHTop = rSection.maSep.dyaHdrTop;
484 sal_uInt32 nWWFBot = rSection.maSep.dyaHdrBottom;
485
486 /*
487 If there is gutter in 97+ and the dop says put it on top then get the
488 gutter distance and set it to the top margin. When we are "two pages
489 in one" the gutter is put at the top of odd pages, and bottom of
490 even pages, something we cannot do. So we will put it on top of all
491 pages, that way the pages are at least the right size.
492 */
493 if (!mrReader.m_bVer67 && mrReader.m_xWDop->iGutterPos &&
494 rSection.maSep.fRTLGutter)
495 {
496 nWWUp += rSection.maSep.dzaGutter;
497 }
498
499 rData.bHasHeader = (rSection.maSep.grpfIhdt &
500 (WW8_HEADER_EVEN | WW8_HEADER_ODD | WW8_HEADER_FIRST)) != 0;
501
502 if( rData.bHasHeader )
503 {
504 rData.nSwUp = nWWHTop; // Header -> convert
505 // #i19922# - correction:
506 // consider that can be negative, compare only if it's positive
507 if ( nWWUp > 0 &&
508 static_cast(abs(nWWUp)) >= nWWHTop )
509 rData.nSwHLo = nWWUp - nWWHTop;
510 else
511 rData.nSwHLo = 0;
512
513 // #i19922# - minimum page header height is now 1mm
514 // use new constant
515 if (rData.nSwHLo < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
516 rData.nSwHLo = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
517 }
518 else // no header -> just use Up as-is
519 rData.nSwUp = std::abs(nWWUp);
520
521 rData.bHasFooter = (rSection.maSep.grpfIhdt &
522 (WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST)) != 0;
523
524 if( rData.bHasFooter )
525 {
526 rData.nSwLo = nWWFBot; // footer -> convert
527 // #i19922# - correction: consider that can be negative, compare only if it's positive
528 if ( nWWLo > 0 &&
529 static_cast(abs(nWWLo)) >= nWWFBot )
530 rData.nSwFUp = nWWLo - nWWFBot;
531 else
532 rData.nSwFUp = 0;
533
534 // #i19922# - minimum page header height is now 1mm
535 // use new constant
536 if (rData.nSwFUp < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
537 rData.nSwFUp = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
538 }
539 else // no footer -> just use Lo as-is
540 rData.nSwLo = std::abs(nWWLo);
541}
542
543void wwSectionManager::SetPageULSpaceItems(SwFrameFormat &rFormat,
544 wwSectionManager::wwULSpaceData const & rData, const wwSection &rSection)
545{
546 if (rData.bHasHeader) // ... and set Header-Lower
547 {
548 // set header height to minimum
549 if (SwFrameFormat* pHdFormat = const_cast(rFormat.GetHeader().GetHeaderFormat()))
550 {
551 SvxULSpaceItem aHdUL(pHdFormat->GetULSpace());
552 if (!rSection.IsFixedHeightHeader()) //normal
553 {
554 pHdFormat->SetFormatAttr(SwFormatFrameSize(ATT_MIN_SIZE, 0, rData.nSwHLo));
555 // #i19922# - minimum page header height is now 1mm
556 // use new constant
557 aHdUL.SetLower( writer_cast(rData.nSwHLo - cMinHdFtHeight) );
558 pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
559 RES_HEADER_FOOTER_EAT_SPACING, true));
560 }
561 else
562 {
563 // #i48832# - set correct spacing between header and body.
564 const sal_Int32 nHdLowerSpace( std::abs(rSection.maSep.dyaTop) - rData.nSwUp - rData.nSwHLo );
565 pHdFormat->SetFormatAttr(SwFormatFrameSize(ATT_FIX_SIZE, 0, rData.nSwHLo + nHdLowerSpace));
566 aHdUL.SetLower( static_cast< sal_uInt16 >(nHdLowerSpace) );
567 pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
568 RES_HEADER_FOOTER_EAT_SPACING, false));
569 }
570 pHdFormat->SetFormatAttr(aHdUL);
571 }
572 }
573
574 if (rData.bHasFooter) // ... and set footer-upper
575 {
576 if (SwFrameFormat* pFtFormat = const_cast(rFormat.GetFooter().GetFooterFormat()))
577 {
578 SvxULSpaceItem aFtUL(pFtFormat->GetULSpace());
579 if (!rSection.IsFixedHeightFooter()) //normal
580 {
581 pFtFormat->SetFormatAttr(SwFormatFrameSize(ATT_MIN_SIZE, 0, rData.nSwFUp));
582 // #i19922# - minimum page header height is now 1mm
583 // use new constant
584 aFtUL.SetUpper( writer_cast(rData.nSwFUp - cMinHdFtHeight) );
585 pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
586 RES_HEADER_FOOTER_EAT_SPACING, true));
587 }
588 else
589 {
590 // #i48832# - set correct spacing between footer and body.
591 const SwTwips nFtUpperSpace( std::abs(rSection.maSep.dyaBottom) - rData.nSwLo - rData.nSwFUp );
592 pFtFormat->SetFormatAttr(SwFormatFrameSize(ATT_FIX_SIZE, 0, rData.nSwFUp + nFtUpperSpace));
593 aFtUL.SetUpper( static_cast< sal_uInt16 >(nFtUpperSpace) );
594 pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
595 RES_HEADER_FOOTER_EAT_SPACING, false));
596 }
597 pFtFormat->SetFormatAttr(aFtUL);
598 }
599 }
600
601 SvxULSpaceItem aUL(writer_cast(rData.nSwUp),
602 writer_cast(rData.nSwLo), RES_UL_SPACE);
603 rFormat.SetFormatAttr(aUL);
604}
605
606SwSectionFormat *wwSectionManager::InsertSection(
607 SwPaM const & rMyPaM, wwSection &rSection)
608{
609 SwSectionData aSection( CONTENT_SECTION,
610 mrReader.m_rDoc.GetUniqueSectionName() );
611
612 SfxItemSet aSet( mrReader.m_rDoc.GetAttrPool(), aFrameFormatSetRange );
613
614 bool bRTLPgn = !maSegments.empty() && maSegments.back().IsBiDi();
615 aSet.Put(SvxFrameDirectionItem(
616 bRTLPgn ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
617
618 if (2 == mrReader.m_xWDop->fpc)
619 aSet.Put( SwFormatFootnoteAtTextEnd(FTNEND_ATTXTEND));
620 if (0 == mrReader.m_xWDop->epc)
621 aSet.Put( SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
622
623 aSection.SetProtectFlag(SectionIsProtected(rSection));
624
625 rSection.mpSection =
626 mrReader.m_rDoc.InsertSwSection( rMyPaM, aSection, nullptr, & aSet );
627 OSL_ENSURE(rSection.mpSection, "section not inserted!");
628 if (!rSection.mpSection)
629 return nullptr;
630
631 SwPageDesc *pPage = nullptr;
632 mySegrIter aEnd = maSegments.rend();
633 for (mySegrIter aIter = maSegments.rbegin(); aIter != aEnd; ++aIter)
634 {
635 if (nullptr != (pPage = aIter->mpPage))
636 break;
637 }
638
639 OSL_ENSURE(pPage, "no page outside this section!");
640
641 if (!pPage)
642 pPage = &mrReader.m_rDoc.GetPageDesc(0);
643
644 if (!pPage)
645 return nullptr;
646
647 SwSectionFormat *pFormat = rSection.mpSection->GetFormat();
648 OSL_ENSURE(pFormat, "impossible");
649 if (!pFormat)
650 return nullptr;
651
652 SwFrameFormat& rFormat = pPage->GetMaster();
653 const SvxLRSpaceItem& rLR = rFormat.GetLRSpace();
654 long nPageLeft = rLR.GetLeft();
655 long nPageRight = rLR.GetRight();
656 long nSectionLeft = rSection.GetPageLeft() - nPageLeft;
657 long nSectionRight = rSection.GetPageRight() - nPageRight;
658 if ((nSectionLeft != 0) || (nSectionRight != 0))
659 {
660 SvxLRSpaceItem aLR(nSectionLeft, nSectionRight, 0, 0, RES_LR_SPACE);
661 pFormat->SetFormatAttr(aLR);
662 }
663
664 SetCols(*pFormat, rSection, rSection.GetTextAreaWidth());
665 return pFormat;
666}
667
668void SwWW8ImplReader::HandleLineNumbering(const wwSection &rSection)
669{
670 // check if Line Numbering must be activated or reset
671 if (m_bNewDoc && rSection.maSep.nLnnMod)
672 {
673 // restart-numbering-mode: 0 per page, 1 per section, 2 never restart
674 bool bRestartLnNumPerSection = (1 == rSection.maSep.lnc);
675
676 if (m_bNoLnNumYet)
677 {
678 SwLineNumberInfo aInfo( m_rDoc.GetLineNumberInfo() );
679
680 aInfo.SetPaintLineNumbers(true);
681
682 aInfo.SetRestartEachPage(rSection.maSep.lnc == 0);
683
684 aInfo.SetPosFromLeft(writer_cast(rSection.maSep.dxaLnn));
685
686 //Paint only for every n line
687 aInfo.SetCountBy(rSection.maSep.nLnnMod);
688
689 // to be defaulted features ( HARDCODED in MS Word 6,7,8,9 )
690 aInfo.SetCountBlankLines(true);
691 aInfo.SetCountInFlys(false);
692 aInfo.SetPos( LINENUMBER_POS_LEFT );
693 SvxNumberType aNumType; // this sets SVX_NUM_ARABIC per default
694 aInfo.SetNumType( aNumType );
695
696 m_rDoc.SetLineNumberInfo( aInfo );
697 m_bNoLnNumYet = false;
698 }
699
700 if (
701 (0 < rSection.maSep.lnnMin) ||
702 (bRestartLnNumPerSection && !m_bNoLnNumYet)
703 )
704 {
705 SwFormatLineNumber aLN;
706 if (const SwFormatLineNumber* pLN
707 = static_cast(GetFormatAttr(RES_LINENUMBER)))
708 {
709 aLN.SetCountLines( pLN->IsCount() );
710 }
711 aLN.SetStartValue(1 + rSection.maSep.lnnMin);
712 NewAttr(aLN);
713 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LINENUMBER);
714 }
715 m_bNoLnNumYet = false;
716 }
717}
718
719wwSection::wwSection(const SwPosition &rPos) : maStart(rPos.nNode)
720 , mpSection(nullptr)
721 , mpPage(nullptr)
722 , meDir(SvxFrameDirection::Horizontal_LR_TB)
723 , nPgWidth(SvxPaperInfo::GetPaperSize(PAPER_A4).Width())
724 , nPgLeft(MM_250)
725 , nPgRight(MM_250)
726 , mnVerticalAdjustment(drawing::TextVerticalAdjust_TOP)
727 , mnBorders(0)
728 , mbHasFootnote(false)
729{
730}
731
732void wwSectionManager::SetNumberingType(const wwSection &rNewSection,
733 SwPageDesc &rPageDesc)
734{
735 // save page number format
736 static const SvxNumType aNumTyp[5] =
737 {
738 SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
739 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N
740 };
741
742 SvxNumberType aType;
743 aType.SetNumberingType( aNumTyp[rNewSection.maSep.nfcPgn] );
744 rPageDesc.SetNumType(aType);
745}
746
747// CreateSep is called for every section change (even at the start of
748// the document. CreateSep also creates the pagedesc(s) and
749// fills it/them with attributes and KF texts.
750// This has become necessary because the translation of the various
751// page attributes is interconnected too much.
752void wwSectionManager::CreateSep(const long nTextPos)
753{
754 /*
755 #i1909# section/page breaks should not occur in tables or subpage
756 elements like frames. Word itself ignores them in this case. The bug is
757 more likely that this filter created such documents in the past!
758 */
759 if (mrReader.m_nInTable || mrReader.m_bTxbxFlySection || mrReader.InLocalApo())
760 return;
761
762 WW8PLCFx_SEPX* pSep = mrReader.m_xPlcxMan->GetSepPLCF();
763 OSL_ENSURE(pSep, "impossible!");
764 if (!pSep)
765 return;
766
767 if (!maSegments.empty() && mrReader.m_pLastAnchorPos.get() && *mrReader.m_pLastAnchorPos == *mrReader.m_pPaM->GetPoint())
768 {
769 bool insert = true;
770 SwPaM pam( *mrReader.m_pLastAnchorPos );
771 if( pam.Move(fnMoveBackward, GoInNode))
772 if( SwTextNode* txtNode = pam.GetPoint()->nNode.GetNode().GetTextNode())
773 if( txtNode->Len() == 0 )
774 insert = false;
775 if( insert )
776 mrReader.AppendTextNode(*mrReader.m_pPaM->GetPoint());
777 }
778
779 ww::WordVersion eVer = mrReader.GetFib().GetFIBVersion();
780
781 // M.M. Create a linked section if the WkbPLCF
782 // has an entry for one at this cp
783 WW8PLCFspecial* pWkb = mrReader.m_xPlcxMan->GetWkbPLCF();
784 if (pWkb && pWkb->SeekPosExact(nTextPos) &&
785 pWkb->Where() == nTextPos)
786 {
787 void* pData;
788 WW8_CP nTest;
789 bool bSuccess = pWkb->Get(nTest, pData);
790 if (!bSuccess)
791 return;
792 OUString sSectionName = mrReader.m_aLinkStringMap[SVBT16ToShort( static_cast(pData)->nLinkId) ];
793 sSectionName = mrReader.ConvertFFileName(sSectionName);
794 SwSectionData aSection(FILE_LINK_SECTION, sSectionName);
795 aSection.SetLinkFileName( sSectionName );
796 aSection.SetProtectFlag(true);
797 // #i19922# - improvement: return value of method not used.
798 mrReader.m_rDoc.InsertSwSection(*mrReader.m_pPaM, aSection, nullptr, nullptr, false);
799 }
800
801 wwSection aLastSection(*mrReader.m_pPaM->GetPoint());
802 if (!maSegments.empty())
803 aLastSection = maSegments.back();
804
805 //Here
806 sal_uInt16 nLIdx = ( ( static_cast(mrReader.m_xWwFib->m_lid) & 0xff ) == 0x9 ) ? 1 : 0;
807
808 //BEGIN read section values
809 wwSection aNewSection(*mrReader.m_pPaM->GetPoint());
810
811 static const sal_uInt16 aVer2Ids0[] =
812 {
813 /*sprmSBkc*/ 117,
814 /*sprmSFTitlePage*/ 118,
815 /*sprmSNfcPgn*/ 122,
816 /*sprmSCcolumns*/ 119,
817 /*sprmSDxaColumns*/ 120,
818 /*sprmSLBetween*/ 133
819 };
820
821 static const sal_uInt16 aVer67Ids0[] =
822 {
823 NS_sprm::v6::sprmSBkc,
824 NS_sprm::v6::sprmSFTitlePage,
825 NS_sprm::v6::sprmSNfcPgn,
826 NS_sprm::v6::sprmSCcolumns,
827 NS_sprm::v6::sprmSDxaColumns,
828 NS_sprm::v6::sprmSLBetween
829 };
830
831 static const sal_uInt16 aVer8Ids0[] =
832 {
833 NS_sprm::sprmSBkc,
834 NS_sprm::sprmSFTitlePage,
835 NS_sprm::sprmSNfcPgn,
836 NS_sprm::sprmSCcolumns,
837 NS_sprm::sprmSDxaColumns,
838 NS_sprm::sprmSLBetween
839 };
840
841 const sal_uInt16* pIds = eVer = 1)
854 aNewSection.maSep.bkc = *pSprmBkc;
855 }
856
857 // Has a table page
858 aNewSection.maSep.fTitlePage =
859 sal_uInt8(0 != ReadBSprm( pSep, pIds[1], 0 ));
860
861 // sprmSNfcPgn
862 aNewSection.maSep.nfcPgn = ReadBSprm( pSep, pIds[2], 0 );
863 if (aNewSection.maSep.nfcPgn > 4)
864 aNewSection.maSep.nfcPgn = 0;
865
866 aNewSection.maSep.fUnlocked = eVer > ww::eWW2 ? ReadBSprm(pSep, (eVer = ww::eWW8 ? ReadBSprm(pSep, NS_sprm::sprmSFBiDi, 0) : 0;
870
871 // Reading section property sprmSCcolumns - one less than the number of columns in the section.
872 // It must be less than MAX_NO_OF_SEP_COLUMNS according the WW8 specification.
873 aNewSection.maSep.ccolM1 = ReadSprm(pSep, pIds[3], 0 );
874 if ( aNewSection.maSep.ccolM1 >= MAX_NO_OF_SEP_COLUMNS )
875 {
876 // clip to max
877 aNewSection.maSep.ccolM1 = MAX_NO_OF_SEP_COLUMNS-1;
878 }
879
880 //sprmSDxaColumns - default distance 1.25 cm
881 aNewSection.maSep.dxaColumns = ReadUSprm( pSep, pIds[4], 708 );
882
883 // sprmSLBetween
884 aNewSection.maSep.fLBetween = ReadBSprm(pSep, pIds[5], 0 );
885
886 if (eVer >= ww::eWW6)
887 {
888 // sprmSFEvenlySpaced
889 aNewSection.maSep.fEvenlySpaced =
890 sal_uInt8(ReadBSprm(pSep, (eVer 0 && !aNewSection.maSep.fEvenlySpaced)
893 {
894 int nColumnDataIdx = 0;
895 aNewSection.maSep.rgdxaColumnWidthSpacing[nColumnDataIdx] = 0;
896
897 const sal_uInt16 nColumnWidthSprmId = ( eVer HasSprm(nColumnWidthSprmId, nColumn);
904 const sal_uInt8* pSW = aSWRes.pSprm;
905
906 OSL_ENSURE( pSW, "+Sprm 136 (resp. 0xF203) (ColWidth) missing" );
907 sal_uInt16 nWidth = (pSW && aSWRes.nRemainingData >= 3) ? SVBT16ToShort(pSW + 1) : 1440;
908
909 aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
910
911 if ( nColumn < nColumnCount - 1 )
912 {
913 //sprmSDxaColSpacing
914 SprmResult aSDRes = pSep->HasSprm(nColumnSpacingSprmId, nColumn);
915 const sal_uInt8* pSD = aSDRes.pSprm;
916
917 OSL_ENSURE( pSD, "+Sprm 137 (resp. 0xF204) (Colspacing) missing" );
918 if (pSD && aSDRes.nRemainingData >= 3)
919 {
920 nWidth = SVBT16ToShort(pSD + 1);
921 aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
922 }
923 }
924 }
925 }
926 }
927
928 static const sal_uInt16 aVer2Ids1[] =
929 {
930 /*sprmSBOrientation*/ 137,
931 /*sprmSXaPage*/ 139,
932 /*sprmSYaPage*/ 140,
933 /*sprmSDxaLeft*/ 141,
934 /*sprmSDxaRight*/ 142,
935 /*sprmSDzaGutter*/ 145,
936 /*sprmSFPgnRestart*/ 125,
937 /*sprmSPgnStart*/ 136,
938 /*sprmSDmBinFirst*/ 115,
939 /*sprmSDmBinOther*/ 116
940 };
941
942 static const sal_uInt16 aVer67Ids1[] =
943 {
944 NS_sprm::v6::sprmSBOrientation,
945 NS_sprm::v6::sprmSXaPage,
946 NS_sprm::v6::sprmSYaPage,
947 NS_sprm::v6::sprmSDxaLeft,
948 NS_sprm::v6::sprmSDxaRight,
949 NS_sprm::v6::sprmSDzaGutter,
950 NS_sprm::v6::sprmSFPgnRestart,
951 NS_sprm::v6::sprmSPgnStart,
952 NS_sprm::v6::sprmSDmBinFirst,
953 NS_sprm::v6::sprmSDmBinOther
954 };
955
956 static const sal_uInt16 aVer8Ids1[] =
957 {
958 NS_sprm::sprmSBOrientation,
959 NS_sprm::sprmSXaPage,
960 NS_sprm::sprmSYaPage,
961 NS_sprm::sprmSDxaLeft,
962 NS_sprm::sprmSDxaRight,
963 NS_sprm::sprmSDzaGutter,
964 NS_sprm::sprmSFPgnRestart,
965 NS_sprm::sprmSPgnStart97,
966 NS_sprm::sprmSDmBinFirst,
967 NS_sprm::sprmSDmBinOther
968 };
969
970 pIds = eVer HasSprm(nId);
1508 if (aS.pSprm && aS.nRemainingData >= 2)
1509 *pVar = static_cast(SVBT16ToShort(aS.pSprm));
1510 return aS.pSprm != nullptr;
1511}
1512
1513inline bool SetValSprm( sal_Int16* pVar, const WW8RStyle* pStyle, sal_uInt16 nId )
1514{
1515 SprmResult aS = pStyle->HasParaSprm(nId);
1516 if (aS.pSprm && aS.nRemainingData >= 2)
1517 *pVar = static_cast(SVBT16ToShort(aS.pSprm));
1518 return aS.pSprm != nullptr;
1519}
1520
1521/*
1522#i1930 revealed that sprm 0x360D (sprmTPc) as used in tables can affect the frame
1523around the table. Its full structure is not fully understood as yet.
1524*/
1525void WW8FlyPara::ApplyTabPos(const WW8_TablePos *pTabPos)
1526{
1527 if (pTabPos)
1528 {
1529 nSp26 = pTabPos->nSp26;
1530 nSp27 = pTabPos->nSp27;
1531 nSp29 = pTabPos->nSp29;
1532 nLeMgn = pTabPos->nLeMgn;
1533 nRiMgn = pTabPos->nRiMgn;
1534 nUpMgn = pTabPos->nUpMgn;
1535 nLoMgn = pTabPos->nLoMgn;
1536 nSp37 = pTabPos->nSp37;
1537 }
1538}
1539
1540WW8FlyPara::WW8FlyPara(bool bIsVer67, const WW8FlyPara* pSrc /* = 0 */)
1541{
1542 if ( pSrc )
1543 memcpy( this, pSrc, sizeof( WW8FlyPara ) ); // Copy-Ctor
1544 else
1545 {
1546 memset( this, 0, sizeof( WW8FlyPara ) ); // Default-Ctor
1547 nSp37 = 2; // Default: wrapping
1548 }
1549 bVer67 = bIsVer67;
1550}
1551
1552bool WW8FlyPara::operator==(const WW8FlyPara& rSrc) const
1553{
1554 /*
1555 Compare the parts that word seems to compare for equivalence.
1556 Interestingly being autoheight or absolute height (the & 0x7fff) doesn't
1557 matter to word
1558 */
1559 return
1560 (
1561 (nSp26 == rSrc.nSp26) &&
1562 (nSp27 == rSrc.nSp27) &&
1563 ((nSp45 & 0x7fff) == (rSrc.nSp45 & 0x7fff)) &&
1564 (nSp28 == rSrc.nSp28) &&
1565 (nLeMgn == rSrc.nLeMgn) &&
1566 (nRiMgn == rSrc.nRiMgn) &&
1567 (nUpMgn == rSrc.nUpMgn) &&
1568 (nLoMgn == rSrc.nLoMgn) &&
1569 (nSp29 == rSrc.nSp29) &&
1570 (nSp37 == rSrc.nSp37)
1571 );
1572}
1573
1574// Read for normal text
1575void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8PLCFx_Cp_FKP* pPap)
1576{
1577 if( bVer67 )
1578 {
1579 SetValSprm( &nSp26, pPap, 26 ); // X-position //sprmPDxaAbs
1580 //set in me or in parent style
1581 mbVertSet |= SetValSprm( &nSp27, pPap, 27 ); // Y-position //sprmPDyaAbs
1582 SetValSprm( &nSp45, pPap, 45 ); // height //sprmPWHeightAbs
1583 SetValSprm( &nSp28, pPap, 28 ); // width //sprmPDxaWidth
1584 SetValSprm( &nLeMgn, pPap, 49 ); // L-border //sprmPDxaFromText
1585 SetValSprm( &nRiMgn, pPap, 49 ); // R-border //sprmPDxaFromText
1586 SetValSprm( &nUpMgn, pPap, 48 ); // U-border //sprmPDyaFromText
1587 SetValSprm( &nLoMgn, pPap, 48 ); // D-border //sprmPDyaFromText
1588
1589 SprmResult aS = pPap->HasSprm(NS_sprm::v6::sprmPWr);
1590 if (aS.pSprm && aS.nRemainingData >= 1)
1591 nSp37 = *aS.pSprm;
1592 }
1593 else
1594 {
1595 SetValSprm( &nSp26, pPap, NS_sprm::sprmPDxaAbs ); // X-position
1596 //set in me or in parent style
1597 mbVertSet |= SetValSprm( &nSp27, pPap, NS_sprm::sprmPDyaAbs ); // Y-position
1598 SetValSprm( &nSp45, pPap, NS_sprm::sprmPWHeightAbs ); // height
1599 SetValSprm( &nSp28, pPap, NS_sprm::sprmPDxaWidth ); // width
1600 SetValSprm( &nLeMgn, pPap, NS_sprm::sprmPDxaFromText ); // L-border
1601 SetValSprm( &nRiMgn, pPap, NS_sprm::sprmPDxaFromText ); // R-border
1602 SetValSprm( &nUpMgn, pPap, NS_sprm::sprmPDyaFromText ); // U-border
1603 SetValSprm( &nLoMgn, pPap, NS_sprm::sprmPDyaFromText ); // D-border
1604
1605 SprmResult aS = pPap->HasSprm(NS_sprm::sprmPWr); // wrapping
1606 if (aS.pSprm && aS.nRemainingData >= 1)
1607 nSp37 = *aS.pSprm;
1608 }
1609
1610 if( ::lcl_ReadBorders( bVer67, brc, pPap )) // borders
1611 bBorderLines = ::lcl_IsBorder( brc );
1612
1613 /*
1614 #i8798#
1615 Appears that with no dyaAbs set then the actual vert anchoring set is
1616 ignored and we remain relative to text, so if that is the case we are 0
1617 from para anchor, so we update the frame to have explicitly this type of
1618 anchoring
1619 */
1620 if (!mbVertSet)
1621 nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1622 else
1623 nSp29 = nOrigSp29;
1624}
1625
1626void WW8FlyPara::ReadFull(sal_uInt8 nOrigSp29, SwWW8ImplReader* pIo)
1627{
1628 std::shared_ptr xPlcxMan = pIo->m_xPlcxMan;
1629 WW8PLCFx_Cp_FKP* pPap = xPlcxMan->GetPapPLCF();
1630
1631 Read(nOrigSp29, pPap); // read Apo parameter
1632
1633 do{ // block for quick exit
1634 if( nSp45 != 0 /* || nSp28 != 0 */ )
1635 break; // bGrafApo only automatic for height
1636 if( pIo->m_xWwFib->m_fComplex )
1637 break; // (*pPap)++ does not work for FastSave
1638 // -> for FastSave, no test for graphics APO
1639 SvStream* pIoStrm = pIo->m_pStrm;
1640 sal_uLong nPos = pIoStrm->Tell();
1641 WW8PLCFxSave1 aSave;
1642 xPlcxMan->GetPap()->Save( aSave );
1643 bGrafApo = false;
1644
1645 do{ // block for quick exit
1646 sal_uInt8 nText[2];
1647
1648 if (!checkRead(*pIoStrm, nText, 2)) // read text
1649 break;
1650
1651 if( nText[0] != 0x01 || nText[1] != 0x0d )// only graphics + CR?
1652 break; // no
1653
1654 pPap->advance(); // next line
1655
1656 // in APO ?
1657 //sprmPPc
1658 SprmResult aS = pPap->HasSprm( bVer67 ? NS_sprm::v6::sprmPPc : NS_sprm::sprmPPc);
1659
1660 // no -> graphics Apo
1661 if (!aS.pSprm || aS.nRemainingData < 1)
1662 {
1663 bGrafApo = true;
1664 break; // end of APO
1665 }
1666
1667 ww::WordVersion eVer = pIo->GetFib().GetFIBVersion();
1668 WW8FlyPara *pNowStyleApo=nullptr;
1669 sal_uInt16 nColl = pPap->GetIstd();
1670 ww::sti eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc( static_cast< sal_uInt8 >(nColl) ) : static_cast(nColl);
1671 while (eSti != ww::stiNil && sal::static_int_cast(nColl) < pIo->m_vColl.size() && nullptr == (pNowStyleApo = pIo->m_vColl[nColl].m_xWWFly.get()))
1672 {
1673 nColl = pIo->m_vColl[nColl].m_nBase;
1674 eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc( static_cast< sal_uInt8 >(nColl) ) : static_cast(nColl);
1675 }
1676
1677 WW8FlyPara aF(bVer67, pNowStyleApo);
1678 // new FlaPara for comparison
1679 aF.Read(*aS.pSprm, pPap); // WWPara for new Para
1680 if( !( aF == *this ) ) // same APO? (or a new one?)
1681 bGrafApo = true; // no -> 1-line APO
1682 // -> graphics APO
1683 }
1684 while( false ); // block for quick exit
1685
1686 xPlcxMan->GetPap()->Restore( aSave );
1687 pIoStrm->Seek( nPos );
1688 }while( false ); // block for quick exit
1689}
1690
1691// read for Apo definitions in Styledefs
1692void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8RStyle const * pStyle)
1693{
1694 if (bVer67)
1695 {
1696 SetValSprm( &nSp26, pStyle, NS_sprm::v6::sprmPDxaAbs ); // X-position
1697 //set in me or in parent style
1698 mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::v6::sprmPDyaAbs); // Y-position
1699 SetValSprm( &nSp45, pStyle, NS_sprm::v6::sprmPWHeightAbs ); // height
1700 SetValSprm( &nSp28, pStyle, NS_sprm::v6::sprmPDxaWidth ); // width
1701 SetValSprm( &nLeMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // L-border
1702 SetValSprm( &nRiMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // R-border
1703 SetValSprm( &nUpMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // U-border
1704 SetValSprm( &nLoMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // D-border
1705
1706 SprmResult aS = pStyle->HasParaSprm( NS_sprm::v6::sprmPWr ); // wrapping
1707 if (aS.pSprm && aS.nRemainingData >= 1)
1708 nSp37 = *aS.pSprm;
1709 }
1710 else
1711 {
1712 SetValSprm( &nSp26, pStyle, NS_sprm::sprmPDxaAbs ); // X-position
1713 //set in me or in parent style
1714 mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::sprmPDyaAbs); // Y-position
1715 SetValSprm( &nSp45, pStyle, NS_sprm::sprmPWHeightAbs ); // height
1716 SetValSprm( &nSp28, pStyle, NS_sprm::sprmPDxaWidth ); // width
1717 SetValSprm( &nLeMgn, pStyle, NS_sprm::sprmPDxaFromText ); // L-border
1718 SetValSprm( &nRiMgn, pStyle, NS_sprm::sprmPDxaFromText ); // R-border
1719 SetValSprm( &nUpMgn, pStyle, NS_sprm::sprmPDyaFromText ); // U-border
1720 SetValSprm( &nLoMgn, pStyle, NS_sprm::sprmPDyaFromText ); // D-border
1721
1722 SprmResult aS = pStyle->HasParaSprm( NS_sprm::sprmPWr ); // wrapping
1723 if (aS.pSprm && aS.nRemainingData >= 1)
1724 nSp37 = *aS.pSprm;
1725 }
1726
1727 if (::lcl_ReadBorders(bVer67, brc, nullptr, pStyle)) // border
1728 bBorderLines = ::lcl_IsBorder(brc);
1729
1730 /*
1731 #i8798#
1732 Appears that with no dyaAbs set then the actual vert anchoring set is
1733 ignored and we remain relative to text, so if that is the case we are 0
1734 from para anchor, so we update the frame to have explicitly this type of
1735 anchoring
1736 */
1737 if (!mbVertSet)
1738 nSp29 = (nOrigSp29 & 0xCF) | 0x20;
1739 else
1740 nSp29 = nOrigSp29;
1741}
1742
1743bool WW8FlyPara::IsEmpty() const
1744{
1745 WW8FlyPara aEmpty(bVer67);
1746 /*
1747 wr of 0 like 2 appears to me to be equivalent for checking here. See
1748 #107103# if wrong, so given that the empty is 2, if we are 0 then set
1749 empty to 0 to make 0 equiv to 2 for empty checking
1750 */
1751 OSL_ENSURE(aEmpty.nSp37 == 2, "this is not what we expect for nSp37");
1752 if (this->nSp37 == 0)
1753 aEmpty.nSp37 = 0;
1754 return aEmpty == *this;
1755}
1756
1757// #i18732# - changes made on behalf of CMC
1758WW8SwFlyPara::WW8SwFlyPara( SwPaM& rPaM,
1759 SwWW8ImplReader& rIo,
1760 WW8FlyPara& rWW,
1761 const sal_uInt32 nWWPgTop,
1762 const sal_uInt32 nPgWidth,
1763 const sal_Int32 nIniFlyDx,
1764 const sal_Int32 nIniFlyDy ):
1765pFlyFormat(nullptr),
1766nXPos(0),
1767nYPos(0),
1768nLeMgn(rWW.nLeMgn),
1769nRiMgn(rWW.nRiMgn),
1770nUpMgn(rWW.nUpMgn),
1771nLoMgn(rWW.nLoMgn),
1772nWidth(rWW.nSp28),
1773nHeight(rWW.nSp45),
1774nNetWidth(rWW.nSp28),
1775eHeightFix(ATT_FIX_SIZE),
1776eHRel(text::RelOrientation::PAGE_FRAME),
1777eVRel(text::RelOrientation::FRAME),
1778eVAlign(text::VertOrientation::NONE),
1779eHAlign(text::HoriOrientation::NONE),
1780eSurround(( rWW.nSp37 > 1 ) ? css::text::WrapTextMode_DYNAMIC : css::text::WrapTextMode_NONE),
1781nXBind(( rWW.nSp29 & 0xc0 ) >> 6),
1782nYBind(( rWW.nSp29 & 0x30 ) >> 4),
1783nNewNetWidth(MINFLY),
1784xMainTextPos(nullptr),
1785nLineSpace(0),
1786bAutoWidth(false),
1787bToggelPos(false)
1788{
1789 //#i119466 mapping "Around" wrap setting to "Parallel" for table
1790 const bool bIsTable = rIo.m_xPlcxMan->HasParaSprm(NS_sprm::sprmPFInTable).pSprm;
1791 if (bIsTable && rWW.nSp37 == 2)
1792 eSurround = css::text::WrapTextMode_PARALLEL;
1793
1794 /*
1795 #95905#, #83307# seems to have gone away now, so re-enable parallel
1796 wrapping support for frames in headers/footers. I don't know if we truly
1797 have an explicitly specified behaviour for these circumstances.
1798 */
1799
1800 if( nHeight & 0x8000 )
1801 {
1802 nHeight &= 0x7fff;
1803 eHeightFix = ATT_MIN_SIZE;
1804 }
1805
1806 if( nHeight ( nYPos + nWWPgTop );
2002 }
2003
2004 FlySecur1( nWidth, rWW.bBorderLines ); // Do the borders match ?
2005 FlySecur1( nHeight, rWW.bBorderLines );
2006
2007}
2008
2009// If a Fly in WW has automatic width, this has to be simulated
2010// by modifying the Fly width (fixed in SW) afterwards.
2011// This can increase or decrease the Fly width, because the default value
2012// is set without knowledge of the contents.
2013void WW8SwFlyPara::BoxUpWidth( long nInWidth )
2014{
2015 if( bAutoWidth && nInWidth > nNewNetWidth )
2016 nNewNetWidth = nInWidth;
2017};
2018
2019// The class WW8FlySet is derived from SfxItemSet and does not
2020// provide more, but is easier to handle for me.
2021// WW8FlySet-ctor for Apos and graphics Apos
2022WW8FlySet::WW8FlySet(SwWW8ImplReader& rReader, const WW8FlyPara* pFW,
2023 const WW8SwFlyPara* pFS, bool bGraf)
2024 : SfxItemSet(rReader.m_rDoc.GetAttrPool(),svl::Items{})
2025{
2026 if (!rReader.m_bNewDoc)
2027 Reader::ResetFrameFormatAttrs(*this); // remove distance/border
2028 // position
2029 Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2030
2031/*Below can all go when we have from left in rtl mode*/
2032 SwTwips nXPos = pFS->nXPos;
2033 sal_Int16 eHRel = pFS->eHRel;
2034 rReader.MiserableRTLGraphicsHack(nXPos, pFS->nWidth, pFS->eHAlign, eHRel);
2035/*Above can all go when we have from left in rtl mode*/
2036 Put( SwFormatHoriOrient(nXPos, pFS->eHAlign, pFS->eHRel, pFS->bToggelPos ));
2037 Put( SwFormatVertOrient( pFS->nYPos, pFS->eVAlign, pFS->eVRel ) );
2038
2039 if (pFS->nLeMgn || pFS->nRiMgn) // set borders
2040 Put(SvxLRSpaceItem(pFS->nLeMgn, pFS->nRiMgn, 0, 0, RES_LR_SPACE));
2041
2042 if (pFS->nUpMgn || pFS->nLoMgn)
2043 Put(SvxULSpaceItem(pFS->nUpMgn, pFS->nLoMgn, RES_UL_SPACE));
2044
2045 //we no longer need to hack around the header/footer problems
2046 SwFormatSurround aSurround(pFS->eSurround);
2047 if ( pFS->eSurround == css::text::WrapTextMode_DYNAMIC )
2048 aSurround.SetAnchorOnly( true );
2049 Put( aSurround );
2050
2051 short aSizeArray[5]={0};
2052 SwWW8ImplReader::SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
2053
2054 // the 5th parameter is always 0, thus we lose nothing due to the cast
2055
2056 // #i27767#
2057 // #i35017# - constant name has changed
2058 Put( SwFormatWrapInfluenceOnObjPos(
2059 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) );
2060
2061 if( !bGraf )
2062 {
2063 Put( SwFormatAnchor(WW8SwFlyPara::eAnchor) );
2064 // adjust size
2065
2066 //Ordinarily with frames, the border width and spacing is
2067 //placed outside the frame, making it larger. With these
2068 //types of frames, the left right thickness and space makes
2069 //it wider, but the top bottom spacing and border thickness
2070 //is placed inside.
2071 Put( SwFormatFrameSize( pFS->eHeightFix, pFS->nWidth +
2072 aSizeArray[WW8_LEFT] + aSizeArray[WW8_RIGHT],
2073 pFS->nHeight));
2074 }
2075}
2076
2077// WW8FlySet-ctor for character bound graphics
2078WW8FlySet::WW8FlySet( SwWW8ImplReader& rReader, const SwPaM* pPaM,
2079 const WW8_PIC& rPic, long nWidth, long nHeight )
2080 : SfxItemSet(rReader.m_rDoc.GetAttrPool(),svl::Items{})
2081{
2082 Init(rReader, pPaM);
2083
2084 Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
2085
2086 short aSizeArray[5]={0};
2087 /*
2088 If we have set borders then in word the graphic is displaced from the left
2089 and top the width of the borders of those sides, and then the shadow
2090 itself is drawn to the bottom and right of the displaced graphic. In word
2091 the total size is that of the graphic plus the borders, plus the total
2092 shadow around all edges, for this translation the top and left shadow
2093 region is translated spacing around the graphic to those sides, and the
2094 bottom and right shadow size is added to the graphic size.
2095 */
2096 WW8_BRCVer9 brcVer9[4];
2097 for (int i = 0; i < 4; i++)
2098 brcVer9[i] = WW8_BRCVer9(rPic.rgbrc[i]);
2099 if (SwWW8ImplReader::SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
2100 {
2101 Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, 0, RES_LR_SPACE ) );
2102 Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
2103 aSizeArray[WW8_RIGHT]*=2;
2104 aSizeArray[WW8_BOT]*=2;
2105 }
2106
2107 Put( SwFormatFrameSize( ATT_FIX_SIZE, nWidth+aSizeArray[WW8_LEFT]+
2108 aSizeArray[WW8_RIGHT], nHeight+aSizeArray[WW8_TOP]
2109 + aSizeArray[WW8_BOT]) );
2110}
2111
2112void WW8FlySet::Init(const SwWW8ImplReader& rReader, const SwPaM* pPaM)
2113{
2114 if (!rReader.m_bNewDoc)
2115 Reader::ResetFrameFormatAttrs(*this); // remove distance/borders
2116
2117 Put(SvxLRSpaceItem(RES_LR_SPACE)); //inline writer ole2 objects start with 0.2cm l/r
2118 SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
2119
2120 aAnchor.SetAnchor(pPaM->GetPoint());
2121 Put(aAnchor);
2122
2123 //The horizontal default is on the baseline, the vertical is centered
2124 //around the character center it appears
2125 if (rReader.m_aSectionManager.CurrentSectionIsVertical())
2126 Put(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER,text::RelOrientation::CHAR));
2127 else
2128 Put(SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME));
2129}
2130
2131WW8DupProperties::WW8DupProperties(SwDoc &rDoc, SwWW8FltControlStack *pStack)
2132 : pCtrlStck(pStack),
2133 aChrSet(rDoc.GetAttrPool(), svl::Items{} ),
2134 aParSet(rDoc.GetAttrPool(), svl::Items{} )
2135{
2136 //Close any open character properties and duplicate them inside the
2137 //first table cell
2138 size_t nCnt = pCtrlStck->size();
2139 for (size_t i=0; i < nCnt; ++i)
2140 {
2141 const SwFltStackEntry& rEntry = (*pCtrlStck)[ i ];
2142 if (rEntry.bOpen)
2143 {
2144 if (isCHRATR(rEntry.pAttr->Which()))
2145 {
2146 aChrSet.Put( *rEntry.pAttr );
2147
2148 }
2149 else if (isPARATR(rEntry.pAttr->Which()))
2150 {
2151 aParSet.Put( *rEntry.pAttr );
2152 }
2153 }
2154 }
2155}
2156
2157void WW8DupProperties::Insert(const SwPosition &rPos)
2158{
2159 for (const SfxItemSet* pSet : {&aChrSet, &aParSet})
2160 {
2161 if( pSet->Count() )
2162 {
2163 SfxItemIter aIter( *pSet );
2164 const SfxPoolItem* pItem = aIter.GetCurItem();
2165 do
2166 {
2167 pCtrlStck->NewAttr(rPos, *pItem);
2168 }while( !aIter.IsAtEnd() && nullptr != ( pItem = aIter.NextItem() ) );
2169 }
2170 }
2171}
2172
2173void SwWW8ImplReader::MoveInsideFly(const SwFrameFormat *pFlyFormat)
2174{
2175 WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2176
2177 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2178
2179 // set Pam in FlyFrame
2180 const SwFormatContent& rContent = pFlyFormat->GetContent();
2181 OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
2182 m_pPaM->GetPoint()->nNode = rContent.GetContentIdx()->GetIndex() + 1;
2183 m_pPaM->GetPoint()->nContent.Assign( m_pPaM->GetContentNode(), 0 );
2184
2185 aDup.Insert(*m_pPaM->GetPoint());
2186}
2187
2188SwTwips SwWW8ImplReader::MoveOutsideFly(SwFrameFormat *pFlyFormat,
2189 const SwPosition &rPos, bool bTableJoin)
2190{
2191 SwTwips nRetWidth = 0;
2192 if (!pFlyFormat)
2193 return nRetWidth;
2194 // Close all attributes, because otherwise attributes can appear
2195 // that extend out of Flys
2196 WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
2197 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
2198
2199 /*
2200 #i1291
2201 If this fly frame consists entirely of one table inside a frame
2202 followed by an empty paragraph then we want to delete the empty
2203 paragraph so as to get the frame to autoshrink to the size of the
2204 table to emulate words behaviour closer.
2205 */
2206 if (bTableJoin)
2207 {
2208 const SwNodeIndex* pNodeIndex = pFlyFormat->GetContent().
2209 GetContentIdx();
2210 if (pNodeIndex)
2211 {
2212 SwNodeIndex aIdx( *pNodeIndex, 1 ),
2213 aEnd( *pNodeIndex->GetNode().EndOfSectionNode() );
2214
2215 if (aIdx < aEnd)
2216 {
2217 if(aIdx.GetNode().IsTableNode())
2218 {
2219 SwTableNode *pTable = aIdx.GetNode().GetTableNode();
2220 aIdx = *aIdx.GetNode().EndOfSectionNode();
2221 ++aIdx;
2222 if ( (aIdx < aEnd) && aIdx.GetNode().IsTextNode() )
2223 {
2224 SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2225 ++aIdx;
2226 if (aIdx == aEnd && pNd && pNd->GetText().isEmpty())
2227 {
2228 //An extra pre-created by writer unused paragraph
2229
2230 //delete after import is complete rather than now
2231 //to avoid the complication of managing uncommitted
2232 //ctrlstack properties that refer to it.
2233 m_aExtraneousParas.insert(pNd);
2234
2235 SwTable& rTable = pTable->GetTable();
2236 SwFrameFormat* pTableFormat = rTable.GetFrameFormat();
2237
2238 if (pTableFormat)
2239 {
2240 SwFormatFrameSize aSize = pTableFormat->GetFrameSize();
2241 aSize.SetHeightSizeType(ATT_MIN_SIZE);
2242 aSize.SetHeight(MINLAY);
2243 pFlyFormat->SetFormatAttr(aSize);
2244 SwFormatHoriOrient aHori = pTableFormat->GetHoriOrient();
2245 // passing the table orientation of
2246 // LEFT_AND_WIDTH to the frame seems to
2247 // work better than FULL, especially if the
2248 // table width exceeds the page width, however
2249 // I am not brave enough to set it in all
2250 // instances
2251 pTableFormat->SetFormatAttr( SwFormatHoriOrient(0, ( aHori.GetHoriOrient() == text::HoriOrientation::LEFT_AND_WIDTH ) ? ::text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::FULL ) );
2252 nRetWidth = aSize.GetWidth();
2253 }
2254 }
2255 }
2256 }
2257 }
2258 }
2259 }
2260
2261 *m_pPaM->GetPoint() = rPos;
2262 aDup.Insert(*m_pPaM->GetPoint());
2263 return nRetWidth;
2264}
2265
2266WW8FlyPara *SwWW8ImplReader::ConstructApo(const ApoTestResults &rApo,
2267 const WW8_TablePos *pTabPos)
2268{
2269 WW8FlyPara *pRet = nullptr;
2270 OSL_ENSURE(rApo.HasFrame() || pTabPos,
2271 "If no frame found, *MUST* be in a table");
2272
2273 pRet = new WW8FlyPara(m_bVer67, rApo.mpStyleApo);
2274
2275 // find APO parameter and test for bGrafApo
2276 if (rApo.HasFrame())
2277 pRet->ReadFull(rApo.m_nSprm29, this);
2278
2279 pRet->ApplyTabPos(pTabPos);
2280
2281 if (pRet->IsEmpty())
2282 {
2283 delete pRet;
2284 pRet = nullptr;
2285 }
2286 return pRet;
2287}
2288
2289bool SwWW8ImplReader::IsDropCap()
2290{
2291 // Find the DCS (Drop Cap Specifier) for the paragraph
2292 // if does not exist or if the first three bits are 0
2293 // then there is no dropcap on the paragraph
2294 WW8PLCFx_Cp_FKP *pPap = m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr;
2295 if (pPap)
2296 {
2297 SprmResult aDCS;
2298 if (m_bVer67)
2299 aDCS = pPap->HasSprm(NS_sprm::v6::sprmPDcs);
2300 else
2301 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::sprmPDcs);
2302 if (aDCS.pSprm && aDCS.nRemainingData >= 2)
2303 {
2304 /*
2305 fdct short :3 0007 drop cap type
2306 0 no drop cap
2307 1 normal drop cap
2308 2 drop cap in margin
2309 */
2310 short nDCS = SVBT16ToShort(aDCS.pSprm);
2311 if (nDCS & 7)
2312 return true;
2313 }
2314 }
2315 return false;
2316}
2317
2318bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *pTabPos)
2319{
2320 m_xWFlyPara.reset(ConstructApo(rApo, pTabPos));
2321 if (!m_xWFlyPara)
2322 return false;
2323
2324 // constructor has changed - new 4th parameter
2325 // containing WW8 page top margin.
2326 m_xSFlyPara.reset(new WW8SwFlyPara( *m_pPaM, *this, *m_xWFlyPara,
2327 m_aSectionManager.GetWWPageTopMargin(),
2328 m_aSectionManager.GetTextAreaWidth(),
2329 m_nIniFlyDx, m_nIniFlyDy));
2330
2331 // If this paragraph is a Dropcap set the flag and we will deal with it later
2332 if (IsDropCap())
2333 {
2334 m_bDropCap = true;
2335 m_xCurrentItemSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), svl::Items{}));
2336 return false;
2337 }
2338
2339 if (!m_xWFlyPara->bGrafApo)
2340 {
2341
2342 // Within the GrafApo text attributes have to be ignored, because
2343 // they would apply to the following lines. The frame is only inserted
2344 // if it is not merely positioning a single image. If it is an image
2345 // frame, pWFlyPara and pSFlyPara are retained and the resulting
2346 // attributes applied to the image when inserting the image.
2347
2348 WW8FlySet aFlySet(*this, m_xWFlyPara.get(), m_xSFlyPara.get(), false);
2349
2350 if (pTabPos && pTabPos->bNoFly)
2351 {
2352 m_xSFlyPara->pFlyFormat = nullptr;
2353 }
2354 else
2355 {
2356 m_xSFlyPara->pFlyFormat = m_rDoc.MakeFlySection(WW8SwFlyPara::eAnchor,
2357 m_pPaM->GetPoint(), &aFlySet);
2358 OSL_ENSURE(m_xSFlyPara->pFlyFormat->GetAnchor().GetAnchorId() ==
2359 WW8SwFlyPara::eAnchor, "Not the anchor type requested!");
2360 }
2361
2362 if (m_xSFlyPara->pFlyFormat)
2363 {
2364 if (!m_pDrawModel)
2365 GrafikCtor();
2366
2367 SdrObject* pOurNewObject = CreateContactObject(m_xSFlyPara->pFlyFormat);
2368 m_xWWZOrder->InsertTextLayerObject(pOurNewObject);
2369 }
2370
2371 if (RndStdIds::FLY_AS_CHAR != WW8SwFlyPara::eAnchor && m_xSFlyPara->pFlyFormat)
2372 {
2373 m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), m_xSFlyPara->pFlyFormat);
2374 }
2375
2376 // remember Pos in body text
2377 m_xSFlyPara->xMainTextPos.reset(new SwPosition(*m_pPaM->GetPoint()));
2378
2379 //remove fltanchors, otherwise they will be closed inside the
2380 //frame, which makes no sense, restore them after the frame is
2381 //closed
2382 m_xSFlyPara->xOldAnchorStck = std::move(m_xAnchorStck);
2383 m_xAnchorStck.reset(new SwWW8FltAnchorStack(&m_rDoc, m_nFieldFlags));
2384
2385 if (m_xSFlyPara->pFlyFormat)
2386 MoveInsideFly(m_xSFlyPara->pFlyFormat);
2387
2388 // 1) ReadText() is not called recursively because the length of
2389 // the Apo is unknown at that time, and ReadText() needs it.
2390 // 2) the CtrlStck is not re-created.
2391 // the Char attributes continue (trouble with Sw-attributes)
2392 // Para attributes must be reset at the end of every paragraph,
2393 // i.e. at the end of a paragraph there must not be para attributes
2394 // on the stack
2395 }
2396 return true;
2397}
2398
2399void wwSectionManager::JoinNode(const SwPosition &rPos, const SwNode &rNode)
2400{
2401 if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
2402 maSegments.back().maStart.Assign(rNode);
2403}
2404
2405bool SwWW8ImplReader::JoinNode(SwPaM &rPam, bool bStealAttr)
2406{
2407 bool bRet = false;
2408 rPam.GetPoint()->nContent = 0; // go to start of paragraph
2409
2410 SwNodeIndex aPref(rPam.GetPoint()->nNode, -1);
2411
2412 if (SwTextNode* pNode = aPref.GetNode().GetTextNode())
2413 {
2414 m_aSectionManager.JoinNode(*rPam.GetPoint(), aPref.GetNode());
2415 rPam.GetPoint()->nNode = aPref;
2416 rPam.GetPoint()->nContent.Assign(pNode, pNode->GetText().getLength());
2417 if (bStealAttr)
2418 m_xCtrlStck->StealAttr(rPam.GetPoint()->nNode);
2419
2420 if (m_pLastAnchorPos || m_pPreviousNode)
2421 {
2422 SwNodeIndex aToBeJoined(aPref, 1);
2423
2424 if (m_pLastAnchorPos)
2425 {
2426 //If the last anchor pos is here, then clear the anchor pos.
2427 //This "last anchor pos" is only used for fixing up the
2428 //positions of things anchored to page breaks and here
2429 //we are removing the last paragraph of a frame, so there
2430 //cannot be a page break at this point so we can
2431 //safely reset m_pLastAnchorPos to avoid any dangling
2432 //SwIndex's pointing into the deleted paragraph
2433 SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2434 if (aLastAnchorPos == aToBeJoined)
2435 m_pLastAnchorPos.reset();
2436 }
2437
2438 if (m_pPreviousNode)
2439 {
2440 //If the drop character start pos is here, then clear it.
2441 SwNodeIndex aDropCharPos(*m_pPreviousNode);
2442 if (aDropCharPos == aToBeJoined)
2443 m_pPreviousNode = nullptr;
2444 }
2445 }
2446
2447 pNode->JoinNext();
2448
2449 bRet = true;
2450 }
2451 return bRet;
2452}
2453
2454//In auto-width word frames negative after-indent values are ignored
2455void SwWW8ImplReader::StripNegativeAfterIndent(SwFrameFormat const *pFlyFormat)
2456{
2457 const SwNodeIndex* pSttNd = pFlyFormat->GetContent().GetContentIdx();
2458 if (!pSttNd)
2459 return;
2460
2461 SwNodeIndex aIdx(*pSttNd, 1);
2462 SwNodeIndex aEnd(*pSttNd->GetNode().EndOfSectionNode());
2463 while (aIdx < aEnd)
2464 {
2465 SwTextNode *pNd = aIdx.GetNode().GetTextNode();
2466 if (pNd)
2467 {
2468 const SvxLRSpaceItem& rLR = ItemGet(*pNd, RES_LR_SPACE);
2469 if (rLR.GetRight() < 0)
2470 {
2471 SvxLRSpaceItem aLR(rLR);
2472 aLR.SetRight(0);
2473 pNd->SetAttr(aLR);
2474 }
2475 }
2476 ++aIdx;
2477 }
2478}
2479
2480void SwWW8ImplReader::StopApo()
2481{
2482 OSL_ENSURE(m_xWFlyPara, "no pWFlyPara to close");
2483 if (!m_xWFlyPara)
2484 return;
2485 if (m_xWFlyPara->bGrafApo)
2486 {
2487 // image frame that has not been inserted: delete empty paragraph + attr
2488 JoinNode(*m_pPaM, true);
2489
2490 }
2491 else
2492 {
2493 if (!m_xSFlyPara->xMainTextPos)
2494 {
2495 OSL_ENSURE(m_xSFlyPara->xMainTextPos.get(), "StopApo: xMainTextPos is nullptr");
2496 return;
2497 }
2498
2499 /*
2500 What we are doing with this temporary nodeindex is as follows: The
2501 stack of attributes normally only places them into the document when
2502 the current insertion point has passed them by. Otherwise the end
2503 point of the attribute gets pushed along with the insertion point. The
2504 insertion point is moved and the properties committed during
2505 MoveOutsideFly. We also may want to remove the final paragraph in the
2506 frame, but we need to wait until the properties for that frame text
2507 have been committed otherwise they will be lost. So we first get a
2508 handle to the last the filter inserted. After the attributes are
2509 committed, if that paragraph exists we join it with the para after it
2510 that comes with the frame by default so that as normal we don't end up
2511 with one more paragraph than we wanted.
2512 */
2513 SwNodeIndex aPref(m_pPaM->GetPoint()->nNode, -1);
2514
2515 SwTwips nNewWidth =
2516 MoveOutsideFly(m_xSFlyPara->pFlyFormat, *m_xSFlyPara->xMainTextPos);
2517 if (nNewWidth)
2518 m_xSFlyPara->BoxUpWidth(nNewWidth);
2519
2520 Color aBg(0xFE, 0xFF, 0xFF, 0xFF); //Transparent by default
2521
2522 SwTextNode* pNd = aPref.GetNode().GetTextNode();
2523 if (pNd && m_xSFlyPara->pFlyFormat)
2524 {
2525 /*
2526 #i582#
2527 Take the last paragraph background colour and fill the frame with
2528 it. Otherwise, make it transparent, this appears to be how MSWord
2529 works
2530 */
2531 const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_BACKGROUND);
2532 const SvxBrushItem &rBrush = static_cast(rItm);
2533 if (rBrush.GetColor() != COL_AUTO)
2534 aBg = rBrush.GetColor();
2535
2536 if (m_pLastAnchorPos.get())
2537 {
2538 //If the last anchor pos is here, then clear the anchor pos.
2539 //This "last anchor pos" is only used for fixing up the
2540 //positions of things anchored to page breaks and here
2541 //we are removing the last paragraph of a frame, so there
2542 //cannot be a page break at this point so we can
2543 //safely reset m_pLastAnchorPos to avoid any dangling
2544 //SwIndex's pointing into the deleted paragraph
2545 SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
2546 SwNodeIndex aToBeJoined(aPref, 1);
2547 if (aLastAnchorPos == aToBeJoined)
2548 m_pLastAnchorPos.reset();
2549 }
2550
2551 //Get rid of extra empty paragraph
2552 pNd->JoinNext();
2553 }
2554
2555 if (m_xSFlyPara->pFlyFormat)
2556 m_xSFlyPara->pFlyFormat->SetFormatAttr(SvxBrushItem(aBg, RES_BACKGROUND));
2557
2558 DeleteAnchorStack();
2559 m_xAnchorStck = std::move(m_xSFlyPara->xOldAnchorStck);
2560
2561 // When inserting a graphic into the fly frame using the auto
2562 // function, the extension of the SW-fly has to be set
2563 // manually as the SW fly has no auto function to adjust the
2564 // frames size.
2565 if (m_xSFlyPara->nNewNetWidth > MINFLY && m_xSFlyPara->pFlyFormat) // BoxUpWidth ?
2566 {
2567 long nW = m_xSFlyPara->nNewNetWidth;
2568 nW += m_xSFlyPara->nWidth - m_xSFlyPara->nNetWidth; // border for it
2569 m_xSFlyPara->pFlyFormat->SetFormatAttr(
2570 SwFormatFrameSize(m_xSFlyPara->eHeightFix, nW, m_xSFlyPara->nHeight));
2571 }
2572 /*
2573 Word set *no* width meaning it's an automatic width. The
2574 SwFlyPara reader will have already set a fallback width of the
2575 printable regions width, so we should reuse it. Despite the related
2576 problems with layout addressed with a hack in WW8FlyPara's constructor
2577 #i27204# Added AutoWidth setting. Left the old CalculateFlySize in place
2578 so that if the user unselects autowidth, the width doesn't max out
2579 */
2580 else if (!m_xWFlyPara->nSp28 && m_xSFlyPara->pFlyFormat)
2581 {
2582 using namespace sw::util;
2583 SfxItemSet aFlySet( m_xSFlyPara->pFlyFormat->GetAttrSet() );
2584
2585 SwFormatFrameSize aSize(ItemGet(aFlySet, RES_FRM_SIZE));
2586
2587 aFlySet.ClearItem(RES_FRM_SIZE);
2588
2589 CalculateFlySize(aFlySet, m_xSFlyPara->xMainTextPos->nNode,
2590 m_xSFlyPara->nWidth);
2591
2592 nNewWidth = ItemGet(aFlySet, RES_FRM_SIZE).GetWidth();
2593
2594 aSize.SetWidth(nNewWidth);
2595 aSize.SetWidthSizeType(ATT_VAR_SIZE);
2596
2597 m_xSFlyPara->pFlyFormat->SetFormatAttr(aSize);
2598 }
2599
2600 m_xSFlyPara->xMainTextPos.reset();
2601// To create the SwFrames when inserting into an existing document, fltshell.cxx
2602// will call pFlyFrame->MakeFrames() when setting the FltAnchor attribute
2603
2604 }
2605
2606 //#i8062#
2607 if (m_xSFlyPara && m_xSFlyPara->pFlyFormat)
2608 m_pFormatOfJustInsertedApo = m_xSFlyPara->pFlyFormat;
2609
2610 m_xSFlyPara.reset();
2611 m_xWFlyPara.reset();
2612}
2613
2614// TestSameApo() returns if it's the same Apo or a different one
2615bool SwWW8ImplReader::TestSameApo(const ApoTestResults &rApo,
2616 const WW8_TablePos *pTabPos)
2617{
2618 if (!m_xWFlyPara)
2619 {
2620 OSL_ENSURE(m_xWFlyPara, " Where is my pWFlyPara ? ");
2621 return true;
2622 }
2623
2624 // We need to a full comparison (excepting borders) to identify all
2625 // combinations style/hard correctly. For this reason we create a
2626 // temporary WW8FlyPara (depending on if style or not), apply the
2627 // hard attributes and then compare.
2628
2629 // For comparison
2630 WW8FlyPara aF(m_bVer67, rApo.mpStyleApo);
2631 // WWPara for current para
2632 if (rApo.HasFrame())
2633 aF.Read(rApo.m_nSprm29, m_xPlcxMan->GetPapPLCF());
2634 aF.ApplyTabPos(pTabPos);
2635
2636 return aF == *m_xWFlyPara;
2637}
2638
2639void SwWW8ImplReader::NewAttr( const SfxPoolItem& rAttr,
2640 const bool bFirstLineOfStSet,
2641 const bool bLeftIndentSet )
2642{
2643 if( !m_bNoAttrImport ) // for ignoring styles during doc inserts
2644 {
2645 if (m_pCurrentColl)
2646 {
2647 OSL_ENSURE(rAttr.Which() != RES_FLTR_REDLINE, "redline in style!");
2648 m_pCurrentColl->SetFormatAttr(rAttr);
2649 }
2650 else if (m_xCurrentItemSet)
2651 {
2652 m_xCurrentItemSet->Put(rAttr);
2653 }
2654 else if (rAttr.Which() == RES_FLTR_REDLINE)
2655 {
2656 m_xRedlineStack->open(*m_pPaM->GetPoint(), rAttr);
2657 }
2658 else
2659 {
2660 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), rAttr);
2661 // #i103711#
2662 if ( bFirstLineOfStSet )
2663 {
2664 const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2665 m_aTextNodesHavingFirstLineOfstSet.insert( pNd );
2666 }
2667 // #i105414#
2668 if ( bLeftIndentSet )
2669 {
2670 const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
2671 m