Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx
Warning:line 541, column 21
Forming reference to null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ww8atr.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx
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/*
21 * This file contains methods for the WW8 output
22 * (nodes, attributes, formats and chars).
23 */
24
25
26#include <algorithm>
27#include <hintids.hxx>
28
29#include <o3tl/safeint.hxx>
30#include <vcl/svapp.hxx>
31#include <vcl/settings.hxx>
32#include <sal/log.hxx>
33
34#include <svl/zformat.hxx>
35#include <svl/itemiter.hxx>
36#include <svl/whiter.hxx>
37#include <svl/grabbagitem.hxx>
38#include <editeng/fontitem.hxx>
39#include <editeng/tstpitem.hxx>
40#include <editeng/adjustitem.hxx>
41#include <editeng/spltitem.hxx>
42#include <editeng/widwitem.hxx>
43#include <editeng/lspcitem.hxx>
44#include <editeng/keepitem.hxx>
45#include <editeng/shaditem.hxx>
46#include <editeng/brushitem.hxx>
47#include <editeng/postitem.hxx>
48#include <editeng/wghtitem.hxx>
49#include <editeng/kernitem.hxx>
50#include <editeng/crossedoutitem.hxx>
51#include <editeng/cmapitem.hxx>
52#include <editeng/wrlmitem.hxx>
53#include <editeng/udlnitem.hxx>
54#include <editeng/langitem.hxx>
55#include <editeng/escapementitem.hxx>
56#include <editeng/fhgtitem.hxx>
57#include <editeng/colritem.hxx>
58#include <editeng/hyphenzoneitem.hxx>
59#include <editeng/formatbreakitem.hxx>
60#include <editeng/lrspitem.hxx>
61#include <editeng/ulspitem.hxx>
62#include <editeng/boxitem.hxx>
63#include <editeng/contouritem.hxx>
64#include <editeng/shdditem.hxx>
65#include <editeng/autokernitem.hxx>
66#include <editeng/pbinitem.hxx>
67#include <editeng/emphasismarkitem.hxx>
68#include <editeng/twolinesitem.hxx>
69#include <editeng/charscaleitem.hxx>
70#include <editeng/charrotateitem.hxx>
71#include <editeng/charreliefitem.hxx>
72#include <editeng/paravertalignitem.hxx>
73#include <editeng/pgrditem.hxx>
74#include <editeng/frmdiritem.hxx>
75#include <editeng/blinkitem.hxx>
76#include <editeng/charhiddenitem.hxx>
77#include <editeng/paperinf.hxx>
78#include <svx/xfillit0.hxx>
79#include <svx/xflgrit.hxx>
80#include <fmtfld.hxx>
81#include <fchrfmt.hxx>
82#include <fmtfsize.hxx>
83#include <fmtpdsc.hxx>
84#include <fmtornt.hxx>
85#include <fmtanchr.hxx>
86#include <fmtclds.hxx>
87#include <fmtsrnd.hxx>
88#include <fmtftn.hxx>
89#include <fmtflcnt.hxx>
90#include <frmatr.hxx>
91#include <swtable.hxx>
92#include <fmtinfmt.hxx>
93#include <txtfld.hxx>
94#include <txtftn.hxx>
95#include <poolfmt.hxx>
96#include <doc.hxx>
97#include <IDocumentSettingAccess.hxx>
98#include <IDocumentFieldsAccess.hxx>
99#include <IDocumentStylePoolAccess.hxx>
100#include <IDocumentListsAccess.hxx>
101#include <list.hxx>
102#include <docary.hxx>
103#include <pam.hxx>
104#include <paratr.hxx>
105#include <fldbas.hxx>
106#include <docufld.hxx>
107#include <expfld.hxx>
108#include <pagedesc.hxx>
109#include <ndtxt.hxx>
110#include <swrect.hxx>
111#include <redline.hxx>
112#include <reffld.hxx>
113#include <ftninfo.hxx>
114#include <charfmt.hxx>
115#include <section.hxx>
116#include <fmtline.hxx>
117#include <tox.hxx>
118#include <fmtftntx.hxx>
119#include <breakit.hxx>
120#include <com/sun/star/i18n/ScriptType.hpp>
121#include <com/sun/star/i18n/XBreakIterator.hpp>
122#include <unotools/localedatawrapper.hxx>
123#include <svx/unobrushitemhelper.hxx>
124#include <tgrditem.hxx>
125#include <flddropdown.hxx>
126#include <chpfld.hxx>
127#include <fmthdft.hxx>
128#include <authfld.hxx>
129#include <dbfld.hxx>
130
131#include "sprmids.hxx"
132
133#include <fmtcntnt.hxx>
134#include "writerhelper.hxx"
135#include "writerwordglue.hxx"
136#include "wrtww8.hxx"
137#include "ww8par.hxx"
138#include "ww8attributeoutput.hxx"
139#include "fields.hxx"
140#include <i18nlangtag/languagetag.hxx>
141#include <unotools/fltrcfg.hxx>
142
143
144using ::editeng::SvxBorderLine;
145using namespace ::com::sun::star;
146using namespace nsSwDocInfoSubType;
147using namespace sw::util;
148using namespace sw::types;
149
150bool WW8Export::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
151{
152 bool bRet = true;
153 if ( nScript == i18n::ScriptType::ASIAN )
154 {
155 //for asian in ww8, there is only one fontsize
156 //and one fontstyle (posture/weight) for ww6
157 //there is the additional problem that there
158 //is only one font setting for all three scripts
159 switch ( nWhich )
160 {
161 case RES_CHRATR_FONTSIZE:
162 case RES_CHRATR_POSTURE:
163 case RES_CHRATR_WEIGHT:
164 bRet = false;
165 break;
166 case RES_CHRATR_LANGUAGE:
167 case RES_CHRATR_CTL_FONT:
168 case RES_CHRATR_CTL_FONTSIZE:
169 case RES_CHRATR_CTL_LANGUAGE:
170 case RES_CHRATR_CTL_POSTURE:
171 case RES_CHRATR_CTL_WEIGHT:
172 default:
173 break;
174 }
175 }
176 else if ( nScript == i18n::ScriptType::COMPLEX )
177 {
178 //Complex is ok in ww8, but for ww6 there is only
179 //one font, one fontsize, one fontsize (weight/posture)
180 //and only one language
181 }
182 else
183 {
184 //for western in ww8, there is only one fontsize
185 //and one fontstyle (posture/weight) for ww6
186 //there is the additional problem that there
187 //is only one font setting for all three scripts
188 switch ( nWhich )
189 {
190 case RES_CHRATR_CJK_FONTSIZE:
191 case RES_CHRATR_CJK_POSTURE:
192 case RES_CHRATR_CJK_WEIGHT:
193 bRet = false;
194 break;
195 case RES_CHRATR_CJK_LANGUAGE:
196 case RES_CHRATR_CTL_FONT:
197 case RES_CHRATR_CTL_FONTSIZE:
198 case RES_CHRATR_CTL_LANGUAGE:
199 case RES_CHRATR_CTL_POSTURE:
200 case RES_CHRATR_CTL_WEIGHT:
201 default:
202 break;
203 }
204 }
205 return bRet;
206}
207
208
209void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont, bool bWriteCombChars )
210{
211 for ( const auto& rItem : rItems )
212 {
213 const SfxPoolItem *pItem = rItem.second;
214 sal_uInt16 nWhich = pItem->Which();
215 if ( ( isCHRATR( nWhich ) || isTXTATR( nWhich ) ) && CollapseScriptsforWordOk( nScript, nWhich ) )
216 {
217 //In the id definition, RES_TXTATR_INETFMT must precede RES_TXTATR_CHARFMT, so that link style can overwrite char style.
218 //and in #i24291# it describes "All we want to do is ensure for now is that if a charfmt exist in the character
219 //properties that it rises to the top and is exported first."
220 //In bug 119649, it is in such situation, so we need to ignore the link style when doing ms word filter exports and
221 //add the second judgement for #i24291# definition.
222 if (nWhich == RES_TXTATR_CHARFMT)
223 {
224 const SfxPoolItem* pINetItem = SearchPoolItems(rItems, RES_TXTATR_INETFMT);
225
226 if (pINetItem)
227 {
228 const SwFormatINetFormat& rINet = static_cast<const SwFormatINetFormat&>(*pINetItem);
229 const SwCharFormat* pINetFormat = GetSwCharFormat(rINet, m_rDoc);
230 if (!pINetFormat)
231 continue;
232
233 const SwCharFormat* pFormat = static_cast<const SwFormatCharFormat&>(*pItem).GetCharFormat();
234 ww8::PoolItems aCharItems, aINetItems;
235 GetPoolItems(pFormat->GetAttrSet(), aCharItems, false);
236 GetPoolItems(pINetFormat->GetAttrSet(), aINetItems, false);
237 for (const auto& rCharItem : aCharItems)
238 {
239 const SfxPoolItem* pCharItem = rCharItem.second;
240 sal_uInt16 nCharWhich = pCharItem->Which();
241 if (!SearchPoolItems(aINetItems, nCharWhich) && !SearchPoolItems(rItems, nCharWhich))
242 AttrOutput().OutputItem(*pCharItem);
243 }
244 continue;
245 }
246 }
247
248 // tdf#38778 Fix output of the font in DOC run for fields
249 if (pFont &&
250 nWhich == RES_TXTATR_FIELD)
251 {
252 AttrOutput().OutputItem( *pFont );
253 }
254
255 // tdf#66401 For Combined Characters in docx, MS Word uses half the normal font-size for the field's
256 // font-size, but only for <w:sz>. Therefore, we check if we are currently writing a field of type
257 // Combined Characters and if so, we half the font size.
258 if (bWriteCombChars &&
259 nWhich == RES_CHRATR_FONTSIZE)
260 {
261 SvxFontHeightItem fontHeight(item_cast<SvxFontHeightItem>( *pItem ));
262 fontHeight.SetHeight( fontHeight.GetHeight() / 2 );
263
264 AttrOutput().OutputItem( fontHeight );
265 }
266 else if (nWhich == RES_CHRATR_COLOR)
267 {
268 const SvxColorItem& rColor = static_cast<const SvxColorItem&>(*pItem);
269 const SfxPoolItem* pBackgroundItem = SearchPoolItems(rItems, RES_CHRATR_BACKGROUND);
270 if (rColor.GetValue() == COL_AUTO && pBackgroundItem)
271 {
272 const SvxBrushItem& rBrushBackground = static_cast<const SvxBrushItem&>(*pBackgroundItem);
273 SvxColorItem aForeground(rBrushBackground.GetColor().IsDark() ? COL_WHITE : COL_BLACK, RES_CHRATR_COLOR);
274 AttrOutput().OutputItem(aForeground);
275 }
276 else
277 {
278 // default
279 AttrOutput().OutputItem( *pItem );
280 }
281 }
282 else
283 {
284 AttrOutput().OutputItem( *pItem );
285 }
286 }
287 }
288}
289
290/*
291 * Output format as follows:
292 * - output the attributes; without parents!
293 */
294
295void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, bool bChpFormat, sal_uInt16 nScript,
296 bool bExportParentItemSet )
297{
298 if( !(bExportParentItemSet || rSet.Count()) )
299 return;
300
301 const SfxPoolItem* pItem;
302 m_pISet = &rSet; // for double attributes
303
304 // If frame dir is set, but not adjust, then force adjust as well
305 if ( bPapFormat && SfxItemState::SET == rSet.GetItemState( RES_FRAMEDIR, bExportParentItemSet ) )
306 {
307 // No explicit adjust set ?
308 if ( SfxItemState::SET != rSet.GetItemState( RES_PARATR_ADJUST, bExportParentItemSet ) )
309 {
310 pItem = rSet.GetItem( RES_PARATR_ADJUST, bExportParentItemSet );
311 if ( nullptr != pItem )
312 {
313 // then set the adjust used by the parent format
314 AttrOutput().OutputItem( *pItem );
315 }
316 }
317 }
318
319 if ( bPapFormat && SfxItemState::SET == rSet.GetItemState( RES_PARATR_NUMRULE, bExportParentItemSet, &pItem ) )
320 {
321 AttrOutput().OutputItem( *pItem );
322
323 // switch off the numbering?
324 if ( static_cast<const SwNumRuleItem*>(pItem)->GetValue().isEmpty() &&
325 SfxItemState::SET != rSet.GetItemState( RES_LR_SPACE, false) &&
326 SfxItemState::SET == rSet.GetItemState( RES_LR_SPACE, true, &pItem ) )
327 {
328 // the set the LR-Space of the parentformat!
329 AttrOutput().OutputItem( *pItem );
330 }
331 }
332
333 ww8::PoolItems aItems;
334 GetPoolItems( rSet, aItems, bExportParentItemSet );
335 if ( bChpFormat )
336 ExportPoolItemsToCHP(aItems, nScript, nullptr);
337 if ( bPapFormat )
338 {
339 AttrOutput().MaybeOutputBrushItem(rSet);
340
341 for ( const auto& rItem : aItems )
342 {
343 pItem = rItem.second;
344 sal_uInt16 nWhich = pItem->Which();
345 // Handle fill attributes just like frame attributes for now.
346 if ( (nWhich >= RES_PARATR_BEGIN && nWhich < RES_FRMATR_END && nWhich != RES_PARATR_NUMRULE ) ||
347 (nWhich >= XATTR_FILL_FIRST && nWhich < XATTR_FILL_LAST))
348 AttrOutput().OutputItem( *pItem );
349 }
350
351 // Has to be called after RES_PARATR_GRABBAG is processed.
352 const XFillStyleItem* pXFillStyleItem(rSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE));
353 if (pXFillStyleItem && pXFillStyleItem->GetValue() == drawing::FillStyle_SOLID && !rSet.HasItem(RES_BACKGROUND))
354 {
355 // Construct an SvxBrushItem, as expected by the exporters.
356 std::unique_ptr<SvxBrushItem> aBrush(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND));
357 AttrOutput().OutputItem(*aBrush);
358 }
359#if 0
360 else
361 {
362 // note: *does not work* due to undocumented Word behavior: must be before a:ln element at least
363 AttrOutput().MaybeOutputBrushItem(rSet);
364 }
365#endif
366 }
367 m_pISet = nullptr; // for double attributes
368}
369
370void MSWordExportBase::GatherChapterFields()
371{
372 //If the header/footer contains a chapter field
373 SwFieldType* pType = m_rDoc.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Chapter );
374 pType->GatherNodeIndex(m_aChapterFieldLocs);
375}
376
377bool MSWordExportBase::ContentContainsChapterField(const SwFormatContent &rContent) const
378{
379 bool bRet = false;
380 if ( const SwNodeIndex* pSttIdx = rContent.GetContentIdx() )
381 {
382 SwNodeIndex aIdx( *pSttIdx, 1 );
383 SwNodeIndex aEnd( *pSttIdx->GetNode().EndOfSectionNode() );
384 sal_uLong nStart = aIdx.GetIndex();
385 sal_uLong nEnd = aEnd.GetIndex();
386 //If the header/footer contains a chapter field
387 bRet = std::any_of(m_aChapterFieldLocs.cbegin(), m_aChapterFieldLocs.cend(),
388 [nStart, nEnd](sal_uLong i) { return ( nStart <= i ) && ( i <= nEnd ); });
389 }
390 return bRet;
391}
392
393bool MSWordExportBase::FormatHdFtContainsChapterField(const SwFrameFormat &rFormat) const
394{
395 if ( m_aChapterFieldLocs.empty() )
396 return false;
397
398 const SwFrameFormat *pFormat = nullptr;
399
400 pFormat = rFormat.GetHeader().GetHeaderFormat();
401 if ( pFormat && ContentContainsChapterField( pFormat->GetContent() ) )
402 return true;
403
404 pFormat = rFormat.GetFooter().GetFooterFormat();
405 return pFormat && ContentContainsChapterField( pFormat->GetContent() );
406}
407
408bool MSWordExportBase::SetCurrentPageDescFromNode(const SwNode &rNd)
409{
410 bool bNewPageDesc = false;
411 const SwPageDesc* pCurrent = SwPageDesc::GetPageDescOfNode(rNd);
412 OSL_ENSURE(pCurrent && m_pCurrentPageDesc, "Not possible surely")do { if (true && (!(pCurrent && m_pCurrentPageDesc
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "412" ": "), "%s", "Not possible surely"); } } while (false
)
;
413 if (m_pCurrentPageDesc && pCurrent)
414 {
415 if (pCurrent != m_pCurrentPageDesc)
416 {
417 if (m_pCurrentPageDesc->GetFollow() != pCurrent)
418 bNewPageDesc = true;
419 else
420 {
421 const SwFrameFormat& rTitleFormat = m_pCurrentPageDesc->GetFirstMaster();
422 const SwFrameFormat& rFollowFormat = pCurrent->GetMaster();
423
424 bNewPageDesc = !IsPlausableSingleWordSection(rTitleFormat,
425 rFollowFormat);
426 }
427 m_pCurrentPageDesc = pCurrent;
428 }
429 else
430 {
431 const SwFrameFormat &rFormat = pCurrent->GetMaster();
432 bNewPageDesc = FormatHdFtContainsChapterField(rFormat);
433 }
434 }
435 return bNewPageDesc;
436}
437
438/**
439 * WW only knows Break-After (page break and section breaks),
440 * whereas in SW page breaks exist both "before" and "after" and PageDesc exists
441 * only "before". Therefore the breaks are iterated two times, namely before
442 * and after every line.
443 * Depending on the break type they're set before or after the line.
444 * Only functions can be called, which do not write in output area pO,
445 * because that one only exits once for CHP and PAP and therefore end up in
446 * the wrong one.
447 */
448void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen )
449{
450 if ( m_bStyDef || m_bOutKF || m_bInWriteEscher || m_bOutPageDescs )
1
Assuming field 'm_bStyDef' is false
2
Assuming field 'm_bOutKF' is false
3
Assuming field 'm_bInWriteEscher' is false
4
Assuming field 'm_bOutPageDescs' is false
5
Taking false branch
451 return;
452
453 m_bBreakBefore = true;
454 bool bNewPageDesc = false;
455 const SfxPoolItem* pItem=nullptr;
456 const SwFormatPageDesc *pPgDesc=nullptr;
457
458 //Output a sectionbreak if there's a new pagedescriptor. Otherwise output a
459 //pagebreak if there is a pagebreak here, unless the new page (follow
460 //style) is different to the current one, in which case plump for a
461 //section.
462 bool bBreakSet = false;
463
464 const SwPageDesc * pPageDesc = rNd.FindPageDesc();
465
466 // Even if m_pCurrentPageDesc != pPageDesc ,it might be because of the different header & footer types.
467 if (m_pCurrentPageDesc != pPageDesc)
6
Assuming 'pPageDesc' is equal to field 'm_pCurrentPageDesc'
7
Taking false branch
468 {
469 if (isCellOpen && ( m_pCurrentPageDesc->GetName() != pPageDesc->GetName() ))
470 {
471 /*
472 * If Table cell is open and page header types are different
473 * set pSet to NULL as we don't want to add any section breaks inside a table.
474 */
475 pSet = nullptr;
476 }
477 else if (!sw::util::IsPlausableSingleWordSection(m_pCurrentPageDesc->GetFirstMaster(), pPageDesc->GetMaster()))
478 {
479 bBreakSet = true;
480 bNewPageDesc = true;
481 m_pCurrentPageDesc = pPageDesc;
482 }
483 }
484
485 if ( pSet && pSet->Count() )
8
Assuming 'pSet' is non-null
9
Assuming the condition is true
10
Taking true branch
486 {
487 if ( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, false, &pItem ) &&
11
Assuming the condition is false
488 static_cast<const SwFormatPageDesc*>(pItem)->GetRegisteredIn() != nullptr)
489 {
490 bBreakSet = true;
491 bNewPageDesc = true;
492 pPgDesc = static_cast<const SwFormatPageDesc*>(pItem);
493 m_pCurrentPageDesc = pPgDesc->GetPageDesc();
494 }
495 else if ( SfxItemState::SET == pSet->GetItemState( RES_BREAK, false, &pItem ) )
12
Value assigned to 'pItem'
13
Assuming the condition is true
14
Taking true branch
496 {
497 // Word does not like hard break attributes in some table cells
498 bool bRemoveHardBreakInsideTable = false;
499 if ( m_bOutTable )
15
Assuming field 'm_bOutTable' is false
16
Taking false branch
500 {
501 const SwTableNode* pTableNode = rNd.FindTableNode();
502 if ( pTableNode )
503 {
504 const SwTableBox* pBox = rNd.GetTableBox();
505 const SwTableLine* pLine = pBox ? pBox->GetUpper() : nullptr;
506 // but only for non-complex tables
507 if ( pLine && !pLine->GetUpper() )
508 {
509 // check if box is not first in that line:
510 if ( 0 < pLine->GetBoxPos( pBox ) && pBox->GetSttNd() )
511 {
512 bRemoveHardBreakInsideTable = true;
513 }
514 }
515 }
516 }
517 bBreakSet = true;
518
519 if ( !bRemoveHardBreakInsideTable
16.1
'bRemoveHardBreakInsideTable' is false
)
17
Taking true branch
520 {
521 OSL_ENSURE(m_pCurrentPageDesc, "should not be possible")do { if (true && (!(m_pCurrentPageDesc))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "521" ": "), "%s", "should not be possible"); } } while (
false)
;
18
Assuming field 'm_pCurrentPageDesc' is non-null
19
Taking false branch
20
Loop condition is false. Exiting loop
522 /*
523 If because of this pagebreak the page desc following the page
524 break is the follow style of the current page desc then output a
525 section break using that style instead. At least in those cases
526 we end up with the same style in word and writer, nothing can be
527 done when it happens when we get a new pagedesc because we
528 overflow from the first page style.
529 */
530 if ( m_pCurrentPageDesc
20.1
Field 'm_pCurrentPageDesc' is non-null
)
21
Taking true branch
531 {
532 // #i76301# - assure that there is a page break before set at the node.
533 const SvxFormatBreakItem* pBreak = dynamic_cast<const SvxFormatBreakItem*>(pItem);
534 if ( pBreak &&
22
Assuming 'pBreak' is null
535 pBreak->GetBreak() == SvxBreak::PageBefore )
536 {
537 bNewPageDesc |= SetCurrentPageDescFromNode( rNd );
538 }
539 }
540 if ( !bNewPageDesc
22.1
'bNewPageDesc' is false
)
23
Taking true branch
541 AttrOutput().OutputItem( *pItem );
24
Forming reference to null pointer
542 }
543 }
544 }
545
546 /*
547 #i9301#
548 No explicit page break, lets see if the style had one and we've moved to a
549 new page style because of it, if we have to then we take the opportunity to
550 set the equivalent word section here. We *could* do it for every paragraph
551 that moves onto a new page because of layout, but that would be insane.
552 */
553 bool bHackInBreak = false;
554 if ( !bBreakSet )
555 {
556 if ( const SwContentNode *pNd = rNd.GetContentNode() )
557 {
558 const SvxFormatBreakItem &rBreak =
559 ItemGet<SvxFormatBreakItem>( *pNd, RES_BREAK );
560 if ( rBreak.GetBreak() == SvxBreak::PageBefore )
561 bHackInBreak = true;
562 else
563 { // Even a pagedesc item is set, the break item can be set 'NONE',
564 // but a pagedesc item is an implicit page break before...
565 const SwFormatPageDesc &rPageDesc =
566 ItemGet<SwFormatPageDesc>( *pNd, RES_PAGEDESC );
567 if ( rPageDesc.KnowsPageDesc() )
568 bHackInBreak = true;
569 }
570 }
571 }
572
573 if ( bHackInBreak )
574 {
575 OSL_ENSURE( m_pCurrentPageDesc, "should not be possible" )do { if (true && (!(m_pCurrentPageDesc))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "575" ": "), "%s", "should not be possible"); } } while (
false)
;
576 if ( m_pCurrentPageDesc )
577 bNewPageDesc = SetCurrentPageDescFromNode( rNd );
578 }
579
580 if ( bNewPageDesc && m_pCurrentPageDesc )
581 {
582 PrepareNewPageDesc( pSet, rNd, pPgDesc, m_pCurrentPageDesc );
583 }
584 m_bBreakBefore = false;
585}
586
587// #i76300#
588bool MSWordExportBase::OutputFollowPageDesc( const SfxItemSet* pSet, const SwTextNode* pNd )
589{
590 bool bRet = false;
591
592 if ( pNd &&
593 m_pCurrentPageDesc &&
594 m_pCurrentPageDesc != m_pCurrentPageDesc->GetFollow() )
595 {
596 PrepareNewPageDesc( pSet, *pNd, nullptr, m_pCurrentPageDesc->GetFollow() );
597 bRet = true;
598 }
599
600 return bRet;
601}
602
603const SwSectionFormat* MSWordExportBase::GetSectionFormat( const SwNode& rNd )
604{
605 const SwSectionFormat* pFormat = nullptr;
606 const SwSectionNode* pSect = rNd.FindSectionNode();
607 if ( pSect &&
608 SectionType::Content == pSect->GetSection().GetType() )
609 {
610 pFormat = pSect->GetSection().GetFormat();
611 }
612
613 return pFormat;
614}
615
616sal_uLong MSWordExportBase::GetSectionLineNo( const SfxItemSet* pSet, const SwNode& rNd )
617{
618 const SwFormatLineNumber* pNItem = nullptr;
619 if ( pSet )
620 {
621 pNItem = &( ItemGet<SwFormatLineNumber>( *pSet, RES_LINENUMBER ) );
622 }
623 else if ( const SwContentNode *pNd = rNd.GetContentNode() )
624 {
625 pNItem = &( ItemGet<SwFormatLineNumber>( *pNd, RES_LINENUMBER ) );
626 }
627
628 return pNItem? pNItem->GetStartValue() : 0;
629}
630
631void WW8Export::PrepareNewPageDesc( const SfxItemSet*pSet,
632 const SwNode& rNd,
633 const SwFormatPageDesc* pNewPgDescFormat,
634 const SwPageDesc* pNewPgDesc )
635{
636 // The PageDescs will only be inserted in WW8Writer::pSepx with the corresponding
637 // position by the occurrences of PageDesc attributes. The construction and
638 // output of the attributes and header/footer of the PageDesc are done
639 // after the main text and its attributes.
640
641 sal_uLong nFcPos = ReplaceCr( msword::PageBreak ); // Page/Section-Break
642
643 // actually nothing is outputted here, rather the arrays aCps, aSects
644 // accordingly completed
645 if ( !nFcPos )
646 return;
647
648 const SwSectionFormat* pFormat = GetSectionFormat( rNd );
649 const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
650
651 OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." )do { if (true && (!(pNewPgDescFormat || pNewPgDesc)))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "651" ": "), "%s", "Neither page desc format nor page desc provided."
); } } while (false)
;
652
653 if ( pNewPgDescFormat )
654 {
655 pSepx->AppendSep( Fc2Cp( nFcPos ), *pNewPgDescFormat, rNd, pFormat, nLnNm );
656 }
657 else if ( pNewPgDesc )
658 {
659 pSepx->AppendSep( Fc2Cp( nFcPos ), pNewPgDesc, rNd, pFormat, nLnNm );
660 }
661}
662
663void MSWordExportBase::CorrectTabStopInSet( SfxItemSet& rSet, sal_Int32 nAbsLeft )
664{
665 const SvxTabStopItem *pItem = rSet.GetItem<SvxTabStopItem>(RES_PARATR_TABSTOP);
666 if (!pItem)
667 return;
668
669 // then it must be corrected for the output
670 SvxTabStopItem aTStop(*pItem);
671 for ( sal_uInt16 nCnt = 0; nCnt < aTStop.Count(); ++nCnt )
672 {
673 SvxTabStop& rTab = const_cast<SvxTabStop&>(aTStop[ nCnt ]);
674 if ( SvxTabAdjust::Default != rTab.GetAdjustment() &&
675 rTab.GetTabPos() >= nAbsLeft )
676 {
677 rTab.GetTabPos() -= nAbsLeft;
678 }
679 else
680 {
681 aTStop.Remove( nCnt );
682 --nCnt;
683 }
684 }
685 rSet.Put( aTStop );
686}
687
688sal_uInt8 WW8Export::GetNumId( sal_uInt16 eNumType )
689{
690 sal_uInt8 nRet = 0;
691 switch( eNumType )
692 {
693 case SVX_NUM_CHARS_UPPER_LETTER:
694 case SVX_NUM_CHARS_UPPER_LETTER_N: nRet = 3; break;
695 case SVX_NUM_CHARS_LOWER_LETTER:
696 case SVX_NUM_CHARS_LOWER_LETTER_N: nRet = 4; break;
697 case SVX_NUM_ROMAN_UPPER: nRet = 1; break;
698 case SVX_NUM_ROMAN_LOWER: nRet = 2; break;
699
700 case SVX_NUM_BITMAP:
701 case SVX_NUM_CHAR_SPECIAL: nRet = 23; break;
702
703 // nothing, WW does the same (undocumented)
704 case SVX_NUM_NUMBER_NONE: nRet = 0xff; break;
705 case SVX_NUM_SYMBOL_CHICAGO:
706 // 0x09, msonfcChiManSty
707 nRet = 9;
708 break;
709 case SVX_NUM_ARABIC_ZERO:
710 // 0x16, msonfcArabicLZ
711 nRet = 22;
712 break;
713 }
714 return nRet;
715}
716
717void WW8AttributeOutput::OutlineNumbering(sal_uInt8 nLvl)
718{
719 if ( nLvl >= WW8ListManager::nMaxLevel )
720 nLvl = WW8ListManager::nMaxLevel-1;
721
722 // write sprmPOutLvl sprmPIlvl and sprmPIlfo
723 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::POutLvl::val );
724 m_rWW8Export.pO->push_back( nLvl );
725 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlvl::val );
726 m_rWW8Export.pO->push_back( nLvl );
727 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlfo::val );
728 SwWW8Writer::InsUInt16( *m_rWW8Export.pO,
729 1 + m_rWW8Export.GetNumberingId(*m_rWW8Export.m_rDoc.GetOutlineNumRule()) );
730}
731
732// #i77805#
733bool WW8Export::DisallowInheritingOutlineNumbering(const SwFormat &rFormat)
734{
735 bool bRet( false );
736
737 //If there is no numbering on this fmt, but its parent was outline
738 //numbered, then in writer this is no inheritied, but in word it would
739 //be, so we must export "no numbering" and "body level" to make word
740 //behave like writer (see #i25755)
741 if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
742 {
743 if (const SwFormat *pParent = rFormat.DerivedFrom())
744 {
745 if (static_cast<const SwTextFormatColl*>(pParent)->IsAssignedToListLevelOfOutlineStyle())
746 {
747 SwWW8Writer::InsUInt16(*pO, NS_sprm::POutLvl::val);
748 pO->push_back(sal_uInt8(9));
749 SwWW8Writer::InsUInt16(*pO, NS_sprm::PIlfo::val);
750 SwWW8Writer::InsUInt16(*pO, 0);
751
752 bRet = true;
753 }
754 }
755 }
756
757 return bRet;
758}
759
760void MSWordExportBase::OutputFormat( const SwFormat& rFormat, bool bPapFormat, bool bChpFormat, bool bFlyFormat )
761{
762 bool bCallOutSet = true;
763 const SwModify* pOldMod = m_pOutFormatNode;
764 m_pOutFormatNode = &rFormat;
765
766 switch( rFormat.Which() )
767 {
768 case RES_CONDTXTFMTCOLL:
769 case RES_TXTFMTCOLL:
770 if( bPapFormat )
771 {
772 int nLvl = MAXLEVEL;
773
774 if (static_cast<const SwTextFormatColl&>(rFormat).IsAssignedToListLevelOfOutlineStyle())
775 nLvl = static_cast<const SwTextFormatColl&>(rFormat).GetAssignedOutlineStyleLevel();
776
777 if (nLvl >= 0 && nLvl < MAXLEVEL)
778 {
779 //if outline numbered
780 // if Write StyleDefinition then write the OutlineRule
781 const SwNumFormat& rNFormat = m_rDoc.GetOutlineNumRule()->Get( static_cast<sal_uInt16>( nLvl ) );
782 if ( m_bStyDef )
783 AttrOutput().OutlineNumbering(static_cast<sal_uInt8>(nLvl));
784
785 if ( rNFormat.GetPositionAndSpaceMode() ==
786 SvxNumberFormat::LABEL_WIDTH_AND_POSITION &&
787 rNFormat.GetAbsLSpace() )
788 {
789 SfxItemSet aSet( rFormat.GetAttrSet() );
790 SvxLRSpaceItem aLR(
791 ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE));
792
793 aLR.SetTextLeft( aLR.GetTextLeft() + rNFormat.GetAbsLSpace() );
794 aLR.SetTextFirstLineOffset( GetWordFirstLineOffset(rNFormat));
795
796 aSet.Put( aLR );
797 CorrectTabStopInSet( aSet, rNFormat.GetAbsLSpace() );
798 OutputItemSet( aSet, bPapFormat, bChpFormat,
799 i18n::ScriptType::LATIN, m_bExportModeRTF);
800 bCallOutSet = false;
801 }
802 }
803 else
804 {
805 //otherwise we might have to remove outline numbering from
806 //what gets exported if the parent style was outline numbered
807 // #i77805#
808 // If inherited outline numbering is suppress, the left/right
809 // margins has to be exported explicitly.
810 if ( m_bStyDef && DisallowInheritingOutlineNumbering(rFormat) )
811 {
812 SfxItemSet aSet( rFormat.GetAttrSet() );
813 const SvxLRSpaceItem& aLR(
814 ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE));
815 aSet.Put( aLR );
816 OutputItemSet( aSet, bPapFormat, bChpFormat,
817 css::i18n::ScriptType::LATIN, m_bExportModeRTF);
818 bCallOutSet = false;
819 }
820 }
821 }
822 break;
823
824 case RES_CHRFMT:
825 break;
826 case RES_FLYFRMFMT:
827 if (bFlyFormat)
828 {
829 OSL_ENSURE(m_pParentFrame, "No parent frame, all broken")do { if (true && (!(m_pParentFrame))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "829" ": "), "%s", "No parent frame, all broken"); } } while
(false)
;
830
831 if (m_pParentFrame)
832 {
833 const SwFrameFormat &rFrameFormat = m_pParentFrame->GetFrameFormat();
834
835 SfxItemSet aSet(m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN,
836 RES_FRMATR_END-1,
837 XATTR_FILL_FIRST, XATTR_FILL_LAST>{});
838 aSet.Set(rFrameFormat.GetAttrSet());
839
840 // Fly as character becomes a paragraph bound
841 // now set the distance to paragraph margin
842 if (m_pFlyOffset)
843 {
844 aSet.Put(SwFormatHoriOrient(m_pFlyOffset->X()));
845 aSet.Put(SwFormatVertOrient(m_pFlyOffset->Y()));
846 SwFormatAnchor aAnchor(rFrameFormat.GetAnchor());
847 aAnchor.SetType(m_eNewAnchorType);
848 aSet.Put(aAnchor);
849 }
850
851 if (SfxItemState::SET != aSet.GetItemState(RES_SURROUND))
852 aSet.Put(SwFormatSurround(css::text::WrapTextMode_NONE));
853
854 const XFillStyleItem* pXFillStyleItem(rFrameFormat.GetAttrSet().GetItem<XFillStyleItem>(XATTR_FILLSTYLE));
855 if (pXFillStyleItem)
856 {
857 switch (pXFillStyleItem->GetValue())
858 {
859 case drawing::FillStyle_NONE:
860 break;
861 case drawing::FillStyle_SOLID:
862 {
863 // Construct an SvxBrushItem, as expected by the exporters.
864 std::unique_ptr<SvxBrushItem> aBrush(getSvxBrushItemFromSourceSet(rFrameFormat.GetAttrSet(), RES_BACKGROUND));
865 aSet.Put(*aBrush);
866 break;
867 }
868 default:
869 break;
870 }
871 }
872
873 m_bOutFlyFrameAttrs = true;
874 //script doesn't matter if not exporting chp
875 OutputItemSet(aSet, true, false,
876 i18n::ScriptType::LATIN, m_bExportModeRTF);
877 m_bOutFlyFrameAttrs = false;
878
879 bCallOutSet = false;
880 }
881 }
882 break;
883 case RES_FRMFMT:
884 break;
885 default:
886 OSL_ENSURE( false, "Which format is exported here?" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "886" ": "), "%s", "Which format is exported here?"); } }
while (false)
;
887 break;
888 }
889
890 if( bCallOutSet )
891 OutputItemSet( rFormat.GetAttrSet(), bPapFormat, bChpFormat,
892 i18n::ScriptType::LATIN, m_bExportModeRTF);
893 m_pOutFormatNode = pOldMod;
894}
895
896bool MSWordExportBase::HasRefToAttr(const OUString& rName)
897{
898 SwFieldType* pType = m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef);
899 std::vector<SwGetRefField*> vpRFields;
900 pType->GatherRefFields(vpRFields, REF_SETREFATTR);
901 return std::any_of(vpRFields.begin(), vpRFields.end(),
902 [rName](SwGetRefField* pF) { return rName == pF->GetSetRefName(); });
903}
904
905bool MSWordExportBase::HasRefToFootOrEndnote(const bool isEndNote, const sal_uInt16 nSeqNo)
906{
907 SwFieldType* pType = m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef);
908 std::vector<SwGetRefField*> vpRFields;
909 pType->GatherRefFields(vpRFields, isEndNote ? REF_ENDNOTE : REF_FOOTNOTE);
910 return std::any_of(vpRFields.begin(), vpRFields.end(),
911 [nSeqNo](SwGetRefField* pF) { return nSeqNo == pF->GetSeqNo(); });
912}
913
914OUString MSWordExportBase::GetBookmarkName( sal_uInt16 nTyp, const OUString* pName, sal_uInt16 nSeqNo )
915{
916 OUString sRet;
917 switch ( nTyp )
918 {
919 case REF_SETREFATTR:
920 if ( pName )
921 {
922 sRet = "Ref_" + *pName;
923 }
924 break;
925 case REF_SEQUENCEFLD:
926 {
927 assert(pName)(static_cast <bool> (pName) ? void (0) : __assert_fail (
"pName", "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 927, __extension__ __PRETTY_FUNCTION__))
;
928 sRet = "Ref_" + *pName;
929 break;
930 }
931 case REF_BOOKMARK:
932 if ( pName )
933 sRet = *pName;
934 break;
935 case REF_OUTLINE:
936 break; // ???
937 case REF_FOOTNOTE:
938 sRet = "_RefF" + OUString::number( nSeqNo );
939 break;
940 case REF_ENDNOTE:
941 sRet = "_RefE" + OUString::number( nSeqNo );
942 break;
943 }
944 return BookmarkToWord( sRet ); // #i43956# - encode bookmark accordingly
945}
946
947/* File CHRATR.HXX: */
948void WW8AttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript )
949{
950 if (bIsRTL)
951 {
952 if( m_rWW8Export.m_rDoc.GetDocumentType() != SwDoc::DOCTYPE_MSWORD )
953 {
954 m_rWW8Export.InsUInt16( NS_sprm::CFBiDi::val );
955 m_rWW8Export.pO->push_back( sal_uInt8(1) );
956 }
957 }
958
959 // #i46087# patch from james_clark; complex texts needs the undocumented SPRM CComplexScript with param 0x81.
960 if (nScript == i18n::ScriptType::COMPLEX && !bIsRTL)
961 {
962 m_rWW8Export.InsUInt16( NS_sprm::CFComplexScripts::val );
963 m_rWW8Export.pO->push_back( sal_uInt8(0x81) );
964 m_rWW8Export.pDop->bUseThaiLineBreakingRules = true;
965 }
966}
967
968void WW8AttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner )
969{
970 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() - (mbOnTOXEnding?2:0), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
971 mbOnTOXEnding = false;
972 m_rWW8Export.pO->clear();
973
974 if ( pTextNodeInfoInner )
975 {
976 if ( pTextNodeInfoInner->isEndOfLine() )
977 {
978 TableRowEnd( pTextNodeInfoInner->getDepth() );
979
980 SVBT16 nSty;
981 ShortToSVBT16( 0, nSty );
982 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nSty, nSty+2 ); // Style #
983 TableInfoRow( pTextNodeInfoInner );
984 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data());
985 m_rWW8Export.pO->clear();
986 }
987 }
988
989 // Clear bookmarks of the current paragraph
990 m_aBookmarksOfParagraphStart.clear();
991 m_aBookmarksOfParagraphEnd.clear();
992}
993
994void WW8AttributeOutput::StartRunProperties()
995{
996 WW8_WrPlcField* pCurrentFields = m_rWW8Export.CurrentFieldPlc();
997 m_nFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
998}
999
1000void WW8AttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool /*bSingleEmptyRun*/ )
1001{
1002 if (pRedlineData)
1003 {
1004 const OUString &rComment = pRedlineData->GetComment();
1005 //Only possible to export to main text
1006 if (!rComment.isEmpty() && (m_rWW8Export.m_nTextTyp == TXT_MAINTEXT))
1007 {
1008 if (m_rWW8Export.m_pAtn->IsNewRedlineComment(pRedlineData))
1009 {
1010 m_rWW8Export.m_pAtn->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), pRedlineData );
1011 m_rWW8Export.WritePostItBegin( m_rWW8Export.pO.get() );
1012 }
1013 }
1014 }
1015
1016 /// Insert bookmarks started at this run
1017 auto aRange = m_aBookmarksOfParagraphStart.equal_range(nPos);
1018 for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
1019 {
1020 GetExport().AppendBookmark(BookmarkToWord(aIter->second));
1021 }
1022}
1023
1024void WW8AttributeOutput::OnTOXEnding()
1025{
1026 mbOnTOXEnding = true;
1027}
1028
1029void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, bool bLastRun )
1030{
1031 /// Insert bookmarks ended after this run
1032 auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nPos);
1033 for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
1034 {
1035 if(bLastRun)
1036 GetExport().AppendBookmarkEndWithCorrection(BookmarkToWord(aIter->second));
1037 else
1038 GetExport().AppendBookmark(BookmarkToWord(aIter->second));
1039 }
1040}
1041
1042void WW8AttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData )
1043{
1044 Redline( pRedlineData );
1045
1046 WW8_WrPlcField* pCurrentFields = m_rWW8Export.CurrentFieldPlc();
1047 sal_uInt16 nNewFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
1048
1049 bool bExportedFieldResult = ( m_nFieldResults != nNewFieldResults );
1050
1051 // If we have exported a field result, then we will have been forced to
1052 // split up the text into a 0x13, 0x14, <result> 0x15 sequence with the
1053 // properties forced out at the end of the result, so the 0x15 itself
1054 // should remain clean of all other attributes to avoid #iXXXXX#
1055 if ( !bExportedFieldResult )
1056 {
1057 m_rWW8Export.m_pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(),
1058 m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1059 }
1060 m_rWW8Export.pO->clear();
1061}
1062
1063void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet )
1064{
1065 RawText(rText, eCharSet);
1066}
1067
1068void WW8AttributeOutput::RawText(const OUString& rText, rtl_TextEncoding)
1069{
1070 m_rWW8Export.OutSwString(rText, 0, rText.getLength());
1071}
1072
1073void WW8AttributeOutput::OutputFKP(bool bForce)
1074{
1075 if (!m_rWW8Export.pO->empty() || bForce)
1076 {
1077 m_rWW8Export.m_pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(),
1078 m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1079 m_rWW8Export.pO->clear();
1080 }
1081}
1082
1083void WW8AttributeOutput::ParagraphStyle( sal_uInt16 nStyle )
1084{
1085 OSL_ENSURE( m_rWW8Export.pO->empty(), " pO is not empty at line end" )do { if (true && (!(m_rWW8Export.pO->empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "1085" ": "), "%s", " pO is not empty at line end"); } }
while (false)
;
1086
1087 SVBT16 nSty;
1088 ShortToSVBT16( nStyle, nSty );
1089 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nSty, nSty+2 ); // style #
1090}
1091
1092void WW8AttributeOutput::OutputWW8Attribute( sal_uInt8 nId, bool bVal )
1093{
1094 m_rWW8Export.InsUInt16( 8 == nId ? NS_sprm::CFDStrike::val : NS_sprm::CFBold::val + nId );
1095
1096 m_rWW8Export.pO->push_back( bVal ? 1 : 0 );
1097}
1098
1099void WW8AttributeOutput::OutputWW8AttributeCTL( sal_uInt8 nId, bool bVal )
1100{
1101 OSL_ENSURE( nId <= 1, "out of range" )do { if (true && (!(nId <= 1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "1101" ": "), "%s", "out of range"); } } while (false)
;
1102 if (nId > 1)
1103 return;
1104
1105 m_rWW8Export.InsUInt16( NS_sprm::CFBoldBi::val + nId );
1106 m_rWW8Export.pO->push_back( bVal ? 1 : 0 );
1107}
1108
1109void WW8AttributeOutput::CharFont( const SvxFontItem& rFont )
1110{
1111 sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1112
1113 m_rWW8Export.InsUInt16( NS_sprm::CRgFtc0::val );
1114 m_rWW8Export.InsUInt16( nFontID );
1115 m_rWW8Export.InsUInt16( NS_sprm::CRgFtc2::val );
1116
1117 m_rWW8Export.InsUInt16( nFontID );
1118}
1119
1120void WW8AttributeOutput::CharFontCTL( const SvxFontItem& rFont )
1121{
1122 sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1123 m_rWW8Export.InsUInt16( NS_sprm::CFtcBi::val );
1124 m_rWW8Export.InsUInt16( nFontID );
1125}
1126
1127void WW8AttributeOutput::CharFontCJK( const SvxFontItem& rFont )
1128{
1129 sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1130 m_rWW8Export.InsUInt16( NS_sprm::CRgFtc1::val );
1131 m_rWW8Export.InsUInt16( nFontID );
1132}
1133
1134void WW8AttributeOutput::CharWeightCTL( const SvxWeightItem& rWeight )
1135{
1136 OutputWW8AttributeCTL( 0, WEIGHT_BOLD == rWeight.GetWeight());
1137}
1138
1139void WW8AttributeOutput::CharPostureCTL( const SvxPostureItem& rPosture )
1140{
1141 OutputWW8AttributeCTL( 1, ITALIC_NONE != rPosture.GetPosture() );
1142}
1143
1144void WW8AttributeOutput::CharPosture( const SvxPostureItem& rPosture )
1145{
1146 OutputWW8Attribute( 1, ITALIC_NONE != rPosture.GetPosture() );
1147}
1148
1149void WW8AttributeOutput::CharWeight( const SvxWeightItem& rWeight )
1150{
1151 OutputWW8Attribute( 0, WEIGHT_BOLD == rWeight.GetWeight() );
1152}
1153
1154// Shadowed and Contour are not in WW-UI. JP: ??
1155void WW8AttributeOutput::CharContour( const SvxContourItem& rContour )
1156{
1157 OutputWW8Attribute( 3, rContour.GetValue() );
1158}
1159
1160void WW8AttributeOutput::CharShadow( const SvxShadowedItem& rShadow )
1161{
1162 OutputWW8Attribute( 4, rShadow.GetValue() );
1163}
1164
1165void WW8AttributeOutput::CharKerning( const SvxKerningItem& rKerning )
1166{
1167 m_rWW8Export.InsUInt16( NS_sprm::CDxaSpace::val );
1168
1169 m_rWW8Export.InsUInt16( rKerning.GetValue() );
1170}
1171
1172void WW8AttributeOutput::CharAutoKern( const SvxAutoKernItem& rAutoKern )
1173{
1174 m_rWW8Export.InsUInt16( NS_sprm::CHpsKern::val );
1175
1176 m_rWW8Export.InsUInt16( rAutoKern.GetValue() ? 2 : 0 );
1177}
1178
1179void WW8AttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink )
1180{
1181 m_rWW8Export.InsUInt16( NS_sprm::CSfxText::val );
1182 // At the moment the only animated text effect we support is blinking
1183 m_rWW8Export.pO->push_back( rBlink.GetValue() ? 2 : 0 );
1184}
1185
1186void WW8AttributeOutput::CharCrossedOut( const SvxCrossedOutItem& rCrossed )
1187{
1188 FontStrikeout eSt = rCrossed.GetStrikeout();
1189 if ( STRIKEOUT_DOUBLE == eSt )
1190 {
1191 OutputWW8Attribute( 8, true );
1192 return;
1193 }
1194 if ( STRIKEOUT_NONE != eSt )
1195 {
1196 OutputWW8Attribute( 2, true );
1197 return;
1198 }
1199
1200 // otherwise both off
1201 OutputWW8Attribute( 8, false );
1202 OutputWW8Attribute( 2, false );
1203}
1204
1205void WW8AttributeOutput::CharCaseMap( const SvxCaseMapItem& rCaseMap )
1206{
1207 SvxCaseMap eSt = rCaseMap.GetValue();
1208 switch ( eSt )
1209 {
1210 case SvxCaseMap::SmallCaps:
1211 OutputWW8Attribute( 5, true );
1212 return;
1213 case SvxCaseMap::Uppercase:
1214 OutputWW8Attribute( 6, true );
1215 return;
1216 case SvxCaseMap::Capitalize:
1217 // no such feature in word
1218 break;
1219 default:
1220 // otherwise both off
1221 OutputWW8Attribute( 5, false );
1222 OutputWW8Attribute( 6, false );
1223 return;
1224 }
1225}
1226
1227void WW8AttributeOutput::CharHidden( const SvxCharHiddenItem& rHidden )
1228{
1229 OutputWW8Attribute( 7, rHidden.GetValue() );
1230}
1231
1232void WW8AttributeOutput::CharBorder( const SvxBorderLine* pAllBorder, const sal_uInt16 /*nDist*/, const bool bShadow )
1233{
1234 WW8Export::Out_BorderLine( *m_rWW8Export.pO, pAllBorder, 0, NS_sprm::CBrc80::val, NS_sprm::CBrc::val, bShadow );
1235}
1236
1237void WW8AttributeOutput::CharHighlight( const SvxBrushItem& rBrush )
1238{
1239 if (rBrush.GetColor() != COL_TRANSPARENT)
1240 {
1241 sal_uInt8 nColor = msfilter::util::TransColToIco( rBrush.GetColor() );
1242 // sprmCHighlight
1243 m_rWW8Export.InsUInt16( NS_sprm::CHighlight::val );
1244 m_rWW8Export.pO->push_back( nColor );
1245 }
1246}
1247
1248void WW8AttributeOutput::CharUnderline( const SvxUnderlineItem& rUnderline )
1249{
1250 m_rWW8Export.InsUInt16( NS_sprm::CKul::val );
1251
1252 const SfxPoolItem* pItem = m_rWW8Export.HasItem( RES_CHRATR_WORDLINEMODE );
1253 bool bWord = false;
1254 if (pItem)
1255 bWord = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
1256
1257 // WW95 - parameters: 0 = none, 1 = single, 2 = by Word,
1258 // 3 = double, 4 = dotted, 5 = hidden
1259 // WW97 - additional parameters:
1260 // 6 = thick, 7 = dash, 8 = dot(not used)
1261 // 9 = dotdash 10 = dotdotdash, 11 = wave
1262 sal_uInt8 b = 0;
1263 switch ( rUnderline.GetLineStyle() )
1264 {
1265 case LINESTYLE_SINGLE:
1266 b = bWord ? 2 : 1;
1267 break;
1268 case LINESTYLE_BOLD:
1269 b = 6;
1270 break;
1271 case LINESTYLE_DOUBLE:
1272 b = 3;
1273 break;
1274 case LINESTYLE_DOTTED:
1275 b = 4;
1276 break;
1277 case LINESTYLE_DASH:
1278 b = 7;
1279 break;
1280 case LINESTYLE_DASHDOT:
1281 b = 9;
1282 break;
1283 case LINESTYLE_DASHDOTDOT:
1284 b = 10;
1285 break;
1286 case LINESTYLE_WAVE:
1287 b = 11;
1288 break;
1289 // new in WW2000
1290 case LINESTYLE_BOLDDOTTED:
1291 b = 20;
1292 break;
1293 case LINESTYLE_BOLDDASH:
1294 b = 23;
1295 break;
1296 case LINESTYLE_LONGDASH:
1297 b = 39;
1298 break;
1299 case LINESTYLE_BOLDLONGDASH:
1300 b = 55;
1301 break;
1302 case LINESTYLE_BOLDDASHDOT:
1303 b = 25;
1304 break;
1305 case LINESTYLE_BOLDDASHDOTDOT:
1306 b = 26;
1307 break;
1308 case LINESTYLE_BOLDWAVE:
1309 b = 27;
1310 break;
1311 case LINESTYLE_DOUBLEWAVE:
1312 b = 43;
1313 break;
1314 case LINESTYLE_NONE:
1315 b = 0;
1316 break;
1317 default:
1318 OSL_ENSURE( rUnderline.GetLineStyle() == LINESTYLE_NONE, "Unhandled underline type" )do { if (true && (!(rUnderline.GetLineStyle() == LINESTYLE_NONE
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "1318" ": "), "%s", "Unhandled underline type"); } } while
(false)
;
1319 break;
1320 }
1321
1322 m_rWW8Export.pO->push_back( b );
1323 Color aColor = rUnderline.GetColor();
1324 if( aColor != COL_TRANSPARENT )
1325 {
1326 m_rWW8Export.InsUInt16( NS_sprm::CCvUl::val );
1327
1328 m_rWW8Export.InsUInt32( wwUtility::RGBToBGR( aColor ) );
1329 }
1330}
1331
1332void WW8AttributeOutput::CharLanguage( const SvxLanguageItem& rLanguage )
1333{
1334 sal_uInt16 nId = 0;
1335 switch ( rLanguage.Which() )
1336 {
1337 case RES_CHRATR_LANGUAGE:
1338 nId = NS_sprm::CRgLid0_80::val;
1339 break;
1340 case RES_CHRATR_CJK_LANGUAGE:
1341 nId = NS_sprm::CRgLid1_80::val;
1342 break;
1343 case RES_CHRATR_CTL_LANGUAGE:
1344 nId = NS_sprm::CLidBi::val;
1345 break;
1346 }
1347
1348 if ( !nId )
1349 return;
1350
1351 // use sprmCRgLid0_80 rather than sprmCLid
1352 m_rWW8Export.InsUInt16( nId );
1353 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLanguage.GetLanguage()) );
1354
1355 // Word 2000 and above apparently require both old and new versions of
1356 // these sprms to be set, without it spellchecking doesn't work
1357 if ( nId == NS_sprm::CRgLid0_80::val )
1358 {
1359 m_rWW8Export.InsUInt16( NS_sprm::CRgLid0::val );
1360 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLanguage.GetLanguage()) );
1361 }
1362 else if ( nId == NS_sprm::CRgLid1_80::val )
1363 {
1364 m_rWW8Export.InsUInt16( NS_sprm::CRgLid1::val );
1365 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLanguage.GetLanguage()) );
1366 }
1367}
1368
1369void WW8AttributeOutput::CharEscapement( const SvxEscapementItem& rEscapement )
1370{
1371 sal_uInt8 b = 0xFF;
1372 short nEsc = rEscapement.GetEsc(), nProp = rEscapement.GetProportionalHeight();
1373 if ( !nEsc )
1374 {
1375 b = 0;
1376 nEsc = 0;
1377 nProp = 100;
1378 }
1379 else if ( DFLT_ESC_PROP58 == nProp || nProp < 1 || nProp > 100 )
1380 {
1381 if ( DFLT_ESC_SUB-8 == nEsc || DFLT_ESC_AUTO_SUB-(13999 +1) == nEsc )
1382 b = 2;
1383 else if ( DFLT_ESC_SUPER33 == nEsc || DFLT_ESC_AUTO_SUPER(13999 +1) == nEsc )
1384 b = 1;
1385 }
1386 else if ( DFLT_ESC_AUTO_SUPER(13999 +1) == nEsc )
1387 {
1388 // Raised by the differences between the ascenders (ascent = baseline to top of highest letter).
1389 // The ascent is generally about 80% of the total font height.
1390 // That is why DFLT_ESC_PROP (58) leads to 33% (DFLT_ESC_SUPER)
1391 nEsc = .8 * (100 - nProp);
1392 }
1393 else if ( DFLT_ESC_AUTO_SUB-(13999 +1) == nEsc )
1394 {
1395 // Lowered by the differences between the descenders (descent = baseline to bottom of lowest letter).
1396 // The descent is generally about 20% of the total font height.
1397 // That is why DFLT_ESC_PROP (58) leads to 8% (DFLT_ESC_SUB)
1398 nEsc = .2 * -(100 - nProp);
1399 }
1400
1401 if ( 0xFF != b )
1402 {
1403 m_rWW8Export.InsUInt16( NS_sprm::CIss::val );
1404
1405 m_rWW8Export.pO->push_back( b );
1406 }
1407
1408 if ( 0 != b && 0xFF != b )
1409 return;
1410
1411 double fHeight = m_rWW8Export.GetItem( RES_CHRATR_FONTSIZE ).GetHeight();
1412 m_rWW8Export.InsUInt16( NS_sprm::CHpsPos::val );
1413
1414 m_rWW8Export.InsUInt16(static_cast<short>( round(fHeight * nEsc / 1000) ));
1415
1416 if( 100 != nProp || !b )
1417 {
1418 m_rWW8Export.InsUInt16( NS_sprm::CHps::val );
1419 m_rWW8Export.InsUInt16(msword_cast<sal_uInt16>( round(fHeight * nProp / 1000) ));
1420 }
1421}
1422
1423void WW8AttributeOutput::CharFontSize( const SvxFontHeightItem& rHeight )
1424{
1425 sal_uInt16 nId = 0;
1426 switch ( rHeight.Which() )
1427 {
1428 case RES_CHRATR_FONTSIZE:
1429 case RES_CHRATR_CJK_FONTSIZE:
1430 nId = NS_sprm::CHps::val;
1431 break;
1432 case RES_CHRATR_CTL_FONTSIZE:
1433 nId = NS_sprm::CHpsBi::val;
1434 break;
1435 }
1436
1437 if ( nId )
1438 {
1439 m_rWW8Export.InsUInt16( nId );
1440
1441 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(( rHeight.GetHeight() + 5 ) / 10 ) );
1442 }
1443}
1444
1445void WW8AttributeOutput::CharScaleWidth( const SvxCharScaleWidthItem& rScaleWidth )
1446{
1447 m_rWW8Export.InsUInt16( NS_sprm::CCharScale::val );
1448 m_rWW8Export.InsUInt16( rScaleWidth.GetValue() );
1449}
1450
1451void WW8AttributeOutput::CharRelief( const SvxCharReliefItem& rRelief )
1452{
1453 sal_uInt16 nId;
1454 switch ( rRelief.GetValue() )
1455 {
1456 case FontRelief::Embossed: nId = NS_sprm::CFEmboss::val; break;
1457 case FontRelief::Engraved: nId = NS_sprm::CFImprint::val; break;
1458 default: nId = 0; break;
1459 }
1460
1461 if( nId )
1462 {
1463 m_rWW8Export.InsUInt16( nId );
1464 m_rWW8Export.pO->push_back( sal_uInt8(0x81) );
1465 }
1466 else
1467 {
1468 // switch both flags off
1469 m_rWW8Export.InsUInt16( NS_sprm::CFEmboss::val );
1470 m_rWW8Export.pO->push_back( sal_uInt8(0x0) );
1471 m_rWW8Export.InsUInt16( NS_sprm::CFImprint::val );
1472 m_rWW8Export.pO->push_back( sal_uInt8(0x0) );
1473 }
1474}
1475
1476void WW8AttributeOutput::CharBidiRTL( const SfxPoolItem& rHt )
1477{
1478 const SfxInt16Item& rAttr = static_cast<const SfxInt16Item&>(rHt);
1479 if( rAttr.GetValue() == 1 )
1480 {
1481 m_rWW8Export.InsUInt16(0x85a);
1482 m_rWW8Export.pO->push_back(sal_uInt8(1));
1483 }
1484}
1485
1486void WW8AttributeOutput::CharIdctHint( const SfxPoolItem& rHt )
1487{
1488 const SfxInt16Item& rAttr = static_cast<const SfxInt16Item&>(rHt);
1489 m_rWW8Export.InsUInt16(0x286F);
1490 m_rWW8Export.pO->push_back(static_cast<sal_uInt8>(rAttr.GetValue()));
1491}
1492
1493void WW8AttributeOutput::CharRotate( const SvxCharRotateItem& rRotate )
1494{
1495 // #i28331# - check that a Value is set
1496 if ( !rRotate.GetValue() )
1497 return;
1498
1499 if (m_rWW8Export.IsInTable())
1500 return;
1501
1502 // #i36867 In word the text in a table is rotated via the TC or NS_sprm::TTextFlow::val
1503 // This means you can only rotate all or none of the text adding NS_sprm::CFELayout::val
1504 // here corrupts the table, hence !m_rWW8Export.bIsInTable
1505
1506 m_rWW8Export.InsUInt16( NS_sprm::CFELayout::val );
1507 m_rWW8Export.pO->push_back( sal_uInt8(0x06) ); //len 6
1508 m_rWW8Export.pO->push_back( sal_uInt8(0x01) );
1509
1510 m_rWW8Export.InsUInt16( rRotate.IsFitToLine() ? 1 : 0 );
1511 static const sal_uInt8 aZeroArr[ 3 ] = { 0, 0, 0 };
1512 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aZeroArr, aZeroArr+3);
1513}
1514
1515void WW8AttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisMark )
1516{
1517 sal_uInt8 nVal;
1518 const FontEmphasisMark v = rEmphasisMark.GetEmphasisMark();
1519 if (v == FontEmphasisMark::NONE)
1520 nVal = 0;
1521 else if (v == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove))
1522 nVal = 2;
1523 else if (v == (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove))
1524 nVal = 3;
1525 else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow))
1526 nVal = 4;
1527 else
1528 // case 1:
1529 nVal = 1;
1530
1531 m_rWW8Export.InsUInt16( NS_sprm::CKcd::val );
1532 m_rWW8Export.pO->push_back( nVal );
1533}
1534
1535/**
1536 * TransBrush converts SW-Brushes to WW. The result is WW8_SHD.
1537 * Non-standard colours of SW won't be converted now to the mixed values
1538 * ( 0 .. 95% ) of WW.
1539 * Also if transparent, e.g. for tables a transparent brush is returned
1540 *
1541 * @return real brush ( not transparent )
1542 */
1543bool WW8Export::TransBrush(const Color& rCol, WW8_SHD& rShd)
1544{
1545 if( rCol.GetTransparency() )
1546 rShd = WW8_SHD(); // all zeros: transparent
1547 else
1548 {
1549 rShd.SetFore( 0);
1550 rShd.SetBack( msfilter::util::TransColToIco( rCol ) );
1551 rShd.SetStyle( 0 );
1552 }
1553 return !rCol.GetTransparency();
1554}
1555
1556static sal_uInt32 SuitableBGColor(Color nIn)
1557{
1558 if (nIn == COL_AUTO)
1559 return 0xFF000000;
1560 return wwUtility::RGBToBGR(nIn);
1561}
1562
1563void WW8AttributeOutput::CharColor( const SvxColorItem& rColor )
1564{
1565 m_rWW8Export.InsUInt16( NS_sprm::CIco::val );
1566
1567 sal_uInt8 nColor = msfilter::util::TransColToIco( rColor.GetValue() );
1568 m_rWW8Export.pO->push_back( nColor );
1569
1570 if (nColor)
1571 {
1572 m_rWW8Export.InsUInt16( NS_sprm::CCv::val );
1573 m_rWW8Export.InsUInt32( wwUtility::RGBToBGR( rColor.GetValue() ) );
1574 }
1575}
1576
1577void WW8AttributeOutput::CharBackground( const SvxBrushItem& rBrush )
1578{
1579 WW8_SHD aSHD;
1580
1581 WW8Export::TransBrush( rBrush.GetColor(), aSHD );
1582 // sprmCShd80
1583 m_rWW8Export.InsUInt16( NS_sprm::CShd80::val );
1584 m_rWW8Export.InsUInt16( aSHD.GetValue() );
1585
1586 //Quite a few unknowns, some might be transparency or something
1587 //of that nature...
1588 m_rWW8Export.InsUInt16( NS_sprm::CShd::val );
1589 m_rWW8Export.pO->push_back( 10 );
1590 m_rWW8Export.InsUInt32( 0xFF000000 );
1591 m_rWW8Export.InsUInt32( SuitableBGColor( rBrush.GetColor() ) );
1592 m_rWW8Export.InsUInt16( 0x0000);
1593}
1594
1595namespace sw { namespace util {
1596
1597const SwCharFormat* GetSwCharFormat(const SwFormatINetFormat& rINet, SwDoc& rDoc)
1598{
1599 if (rINet.GetValue().isEmpty())
1600 return nullptr;
1601
1602 const sal_uInt16 nId = rINet.GetINetFormatId();
1603 const OUString& rStr = rINet.GetINetFormat();
1604 if (rStr.isEmpty())
1605 {
1606 OSL_ENSURE( false, "WW8AttributeOutput::TextINetFormat(..) - missing unvisited character format at hyperlink attribute" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "1606" ": "), "%s", "WW8AttributeOutput::TextINetFormat(..) - missing unvisited character format at hyperlink attribute"
); } } while (false)
;
1607 }
1608
1609 return IsPoolUserFormat( nId )
1610 ? rDoc.FindCharFormatByName( rStr )
1611 : rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( nId );
1612}
1613
1614} }
1615
1616void WW8AttributeOutput::TextINetFormat( const SwFormatINetFormat& rINet )
1617{
1618 const SwCharFormat* pFormat = GetSwCharFormat(rINet, m_rWW8Export.m_rDoc);
1619 if (!pFormat)
1620 return;
1621
1622 m_rWW8Export.InsUInt16( NS_sprm::CIstd::val );
1623
1624 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( pFormat ) );
1625}
1626
1627// #i43956# - add optional parameter <pLinkStr>
1628// It's needed to write the hyperlink data for a certain cross-reference
1629// - it contains the name of the link target, which is a bookmark.
1630// add optional parameter <bIncludeEmptyPicLocation>
1631// It is needed to write an empty picture location for page number field separators
1632static void InsertSpecialChar( WW8Export& rWrt, sal_uInt8 c,
1633 OUString const * pLinkStr,
1634 bool bIncludeEmptyPicLocation = false )
1635{
1636 ww::bytes aItems;
1637 rWrt.GetCurrentItems(aItems);
1638
1639 if (c == 0x13)
1640 rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell());
1641 else
1642 rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell(), aItems.size(), aItems.data());
1643
1644 rWrt.WriteChar(c);
1645
1646 // store empty sprmCPicLocation for field separator
1647 if ( bIncludeEmptyPicLocation &&
1648 ( c == 0x13 || c == 0x14 || c == 0x15 ) )
1649 {
1650 SwWW8Writer::InsUInt16( aItems, NS_sprm::CPicLocation::val );
1651 SwWW8Writer::InsUInt32( aItems, 0x00000000 );
1652 }
1653
1654 // #i43956# - write hyperlink data and attributes
1655 if ( c == 0x01 && pLinkStr)
1656 {
1657 // write hyperlink data to data stream
1658 SvStream& rStrm = *rWrt.pDataStrm;
1659 // position of hyperlink data
1660 const sal_uInt32 nLinkPosInDataStrm = rStrm.Tell();
1661 // write empty header
1662 const sal_uInt16 nEmptyHdrLen = 0x44;
1663 sal_uInt8 aEmptyHeader[ nEmptyHdrLen ] = { 0 };
1664 aEmptyHeader[ 4 ] = 0x44;
1665 rStrm.WriteBytes( aEmptyHeader, nEmptyHdrLen );
1666 // writer fixed header
1667 const sal_uInt16 nFixHdrLen = 0x19;
1668 sal_uInt8 const aFixHeader[ nFixHdrLen ] =
1669 {
1670 0x08, 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE,
1671 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9,
1672 0x0B, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
1673 0x00,
1674 };
1675 rStrm.WriteBytes( aFixHeader, nFixHdrLen );
1676 // write reference string including length+1
1677 sal_uInt32 nStrLen( pLinkStr->getLength() + 1 );
1678 SwWW8Writer::WriteLong( rStrm, nStrLen );
1679 SwWW8Writer::WriteString16( rStrm, *pLinkStr, false );
1680 // write additional two NULL Bytes
1681 SwWW8Writer::WriteLong( rStrm, 0 );
1682 // write length of hyperlink data
1683 const sal_uInt32 nCurrPos = rStrm.Tell();
1684 rStrm.Seek( nLinkPosInDataStrm );
1685 rStrm.WriteUInt32(nCurrPos - nLinkPosInDataStrm);
1686 rStrm.Seek( nCurrPos );
1687
1688 // write attributes of hyperlink character 0x01
1689 SwWW8Writer::InsUInt16( aItems, NS_sprm::CFFldVanish::val );
1690 aItems.push_back( sal_uInt8(0x81) );
1691 SwWW8Writer::InsUInt16( aItems, NS_sprm::CPicLocation::val );
1692 SwWW8Writer::InsUInt32( aItems, nLinkPosInDataStrm );
1693 SwWW8Writer::InsUInt16( aItems, NS_sprm::CFData::val );
1694 aItems.push_back( sal_uInt8(0x01) );
1695 }
1696
1697 //Technically we should probably Remove all attribs
1698 //here for the 0x13, 0x14, 0x15, but our import
1699 //is slightly lacking
1700 //aItems.Remove(0, aItems.Count());
1701 // fSpec-Attribute true
1702 SwWW8Writer::InsUInt16( aItems, NS_sprm::CFSpec::val );
1703 aItems.push_back( 1 );
1704
1705 rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell(), aItems.size(), aItems.data());
1706}
1707
1708static OUString lcl_GetExpandedField(const SwField &rField)
1709{
1710 //replace LF 0x0A with VT 0x0B
1711 return rField.ExpandField(true, nullptr).replace(0x0A, 0x0B);
1712}
1713
1714WW8_WrPlcField* WW8Export::CurrentFieldPlc() const
1715{
1716 WW8_WrPlcField* pFieldP = nullptr;
1717 switch (m_nTextTyp)
1718 {
1719 case TXT_MAINTEXT:
1720 pFieldP = m_pFieldMain.get();
1721 break;
1722 case TXT_HDFT:
1723 pFieldP = m_pFieldHdFt.get();
1724 break;
1725 case TXT_FTN:
1726 pFieldP = m_pFieldFootnote.get();
1727 break;
1728 case TXT_EDN:
1729 pFieldP = m_pFieldEdn.get();
1730 break;
1731 case TXT_ATN:
1732 pFieldP = m_pFieldAtn.get();
1733 break;
1734 case TXT_TXTBOX:
1735 pFieldP = m_pFieldTextBxs.get();
1736 break;
1737 case TXT_HFTXTBOX:
1738 pFieldP = m_pFieldHFTextBxs.get();
1739 break;
1740 default:
1741 OSL_ENSURE( false, "what type of SubDoc is that?" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "1741" ": "), "%s", "what type of SubDoc is that?"); } }
while (false)
;
1742 }
1743 return pFieldP;
1744}
1745
1746void WW8Export::OutputField( const SwField* pField, ww::eField eFieldType,
1747 const OUString& rFieldCmd, FieldFlags nMode )
1748{
1749 OUString sFieldCmd(rFieldCmd);
1750 switch (eFieldType)
1751 {
1752 // map fields that are not supported in WW8 as of Word 2003
1753 case ww::eBIBLIOGRAPHY:
1754 eFieldType = ww::eQUOTE;
1755 assert(rFieldCmd == FieldString(ww::eBIBLIOGRAPHY))(static_cast <bool> (rFieldCmd == FieldString(ww::eBIBLIOGRAPHY
)) ? void (0) : __assert_fail ("rFieldCmd == FieldString(ww::eBIBLIOGRAPHY)"
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 1755, __extension__ __PRETTY_FUNCTION__))
;
1756 sFieldCmd = FieldString(ww::eQUOTE);
1757 break;
1758 case ww::eCITATION:
1759 eFieldType = ww::eQUOTE;
1760 assert(rFieldCmd.trim().startsWith("CITATION"))(static_cast <bool> (rFieldCmd.trim().startsWith("CITATION"
)) ? void (0) : __assert_fail ("rFieldCmd.trim().startsWith(\"CITATION\")"
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 1760, __extension__ __PRETTY_FUNCTION__))
;
1761 sFieldCmd = rFieldCmd.replaceFirst(FieldString(ww::eCITATION),
1762 FieldString(ww::eQUOTE));
1763 break;
1764 default:
1765 break;
1766 }
1767
1768 assert(eFieldType <= 0x5F)(static_cast <bool> (eFieldType <= 0x5F) ? void (0) :
__assert_fail ("eFieldType <= 0x5F", "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 1768, __extension__ __PRETTY_FUNCTION__))
; // 95 is the highest documented one
1769
1770 WW8_WrPlcField* pFieldP = CurrentFieldPlc();
1771
1772 const bool bIncludeEmptyPicLocation = ( eFieldType == ww::ePAGE );
1773 if (FieldFlags::Start & nMode)
1774 {
1775 sal_uInt8 aField13[2] = { 0x13, 0x00 }; // will change
1776 //#i3958#, Needed to make this field work correctly in Word 2000
1777 if (eFieldType == ww::eSHAPE)
1778 aField13[0] |= 0x80;
1779 aField13[1] = static_cast< sal_uInt8 >(eFieldType); // add type
1780 pFieldP->Append( Fc2Cp( Strm().Tell() ), aField13 );
1781 InsertSpecialChar( *this, 0x13, nullptr, bIncludeEmptyPicLocation );
1782 }
1783 if (FieldFlags::CmdStart & nMode)
1784 {
1785 SwWW8Writer::WriteString16(Strm(), sFieldCmd, false);
1786 // #i43956# - write hyperlink character including
1787 // attributes and corresponding binary data for certain reference fields.
1788 bool bHandleBookmark = false;
1789
1790 if (pField)
1791 {
1792 if (pField->GetTyp()->Which() == SwFieldIds::GetRef &&
1793 ( eFieldType == ww::ePAGEREF || eFieldType == ww::eREF ||
1794 eFieldType == ww::eNOTEREF || eFieldType == ww::eFOOTREF ))
1795 bHandleBookmark = true;
1796 }
1797
1798 if ( bHandleBookmark )
1799 {
1800 // retrieve reference destination - the name of the bookmark
1801 OUString aLinkStr;
1802 const sal_uInt16 nSubType = pField->GetSubType();
1803 const SwGetRefField& rRField = *static_cast<const SwGetRefField*>(pField);
1804 if ( nSubType == REF_SETREFATTR ||
1805 nSubType == REF_BOOKMARK )
1806 {
1807 const OUString& aRefName(rRField.GetSetRefName());
1808 aLinkStr = GetBookmarkName( nSubType, &aRefName, 0 );
1809 }
1810 else if ( nSubType == REF_FOOTNOTE ||
1811 nSubType == REF_ENDNOTE )
1812 {
1813 aLinkStr = GetBookmarkName( nSubType, nullptr, rRField.GetSeqNo() );
1814 }
1815 else if ( nSubType == REF_SEQUENCEFLD )
1816 {
1817 aLinkStr = pField->GetPar2();
1818 }
1819 // insert hyperlink character including attributes and data.
1820 InsertSpecialChar( *this, 0x01, &aLinkStr );
1821 }
1822 }
1823 if (FieldFlags::CmdEnd & nMode)
1824 {
1825 static const sal_uInt8 aField14[2] = { 0x14, 0xff };
1826 pFieldP->Append( Fc2Cp( Strm().Tell() ), aField14 );
1827 pFieldP->ResultAdded();
1828 InsertSpecialChar( *this, 0x14, nullptr, bIncludeEmptyPicLocation );
1829 }
1830 if (FieldFlags::End & nMode)
1831 {
1832 OUString sOut;
1833 if( pField )
1834 sOut = lcl_GetExpandedField(*pField);
1835 else
1836 sOut = sFieldCmd;
1837 if( !sOut.isEmpty() )
1838 {
1839 SwWW8Writer::WriteString16(Strm(), sOut, false);
1840
1841 if (pField)
1842 {
1843 if (pField->GetTyp()->Which() == SwFieldIds::Input &&
1844 eFieldType == ww::eFORMTEXT)
1845 {
1846 sal_uInt8 aArr[12];
1847 sal_uInt8 *pArr = aArr;
1848
1849 Set_UInt16( pArr, NS_sprm::CPicLocation::val );
1850 Set_UInt32( pArr, 0x0 );
1851
1852 Set_UInt16( pArr, NS_sprm::CFSpec::val );
1853 Set_UInt8( pArr, 1 );
1854
1855 Set_UInt16( pArr, NS_sprm::CFNoProof::val );
1856 Set_UInt8( pArr, 1 );
1857
1858 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
1859 }
1860 }
1861 }
1862 }
1863 if (!(FieldFlags::Close & nMode))
1864 return;
1865
1866 sal_uInt8 aField15[2] = { 0x15, 0x80 };
1867
1868 if (pField)
1869 {
1870 if (pField->GetTyp()->Which() == SwFieldIds::Input &&
1871 eFieldType == ww::eFORMTEXT)
1872 {
1873 sal_uInt16 nSubType = pField->GetSubType();
1874
1875 if (nSubType == REF_SEQUENCEFLD)
1876 aField15[0] |= (0x4 << 5);
1877 }
1878 }
1879
1880 pFieldP->Append( Fc2Cp( Strm().Tell() ), aField15 );
1881 InsertSpecialChar( *this, 0x15, nullptr, bIncludeEmptyPicLocation );
1882}
1883
1884void WW8Export::StartCommentOutput(const OUString& rName)
1885{
1886 const OUString sStr{ FieldString(ww::eQUOTE) + "[" + rName + "] " };
1887 OutputField(nullptr, ww::eQUOTE, sStr, FieldFlags::Start | FieldFlags::CmdStart);
1888}
1889
1890void WW8Export::EndCommentOutput(const OUString& rName)
1891{
1892 const OUString sStr{ " [" + rName + "] " };
1893 OutputField(nullptr, ww::eQUOTE, sStr, FieldFlags::CmdEnd | FieldFlags::End |
1894 FieldFlags::Close);
1895}
1896
1897sal_uInt16 MSWordExportBase::GetId( const SwTOXType& rTOXType )
1898{
1899 std::vector<const SwTOXType*>::iterator it
1900 = std::find( m_aTOXArr.begin(), m_aTOXArr.end(), &rTOXType );
1901 if ( it != m_aTOXArr.end() )
1902 {
1903 return it - m_aTOXArr.begin();
1904 }
1905 m_aTOXArr.push_back( &rTOXType );
1906 return m_aTOXArr.size() - 1;
1907}
1908
1909// return values: 1 - no PageNum,
1910// 2 - TabStop before PageNum,
1911// 3 - Text before PageNum - rText hold the text
1912// 4 - no Text and no TabStop before PageNum
1913static int lcl_CheckForm( const SwForm& rForm, sal_uInt8 nLvl, OUString& rText )
1914{
1915 int nRet = 4;
1916 rText.clear();
1917
1918 // #i21237#
1919 SwFormTokens aPattern = rForm.GetPattern(nLvl);
1920 SwFormTokens::iterator aIt = aPattern.begin();
1921 FormTokenType eTType;
1922
1923 // #i61362#
1924 if (! aPattern.empty())
1925 {
1926 bool bPgNumFnd = false;
1927
1928 // #i21237#
1929 while( ++aIt != aPattern.end() && !bPgNumFnd )
1930 {
1931 eTType = aIt->eTokenType;
1932
1933 switch( eTType )
1934 {
1935 case TOKEN_PAGE_NUMS:
1936 bPgNumFnd = true;
1937 break;
1938
1939 case TOKEN_TAB_STOP:
1940 nRet = 2;
1941 break;
1942 case TOKEN_TEXT:
1943 {
1944 nRet = 3;
1945 sal_Int32 nCount = std::min<sal_Int32>(5, aIt->sText.getLength());
1946 rText = aIt->sText.copy(0, nCount); // #i21237#
1947 break;
1948 }
1949 case TOKEN_LINK_START:
1950 case TOKEN_LINK_END:
1951 break;
1952
1953 default:
1954 nRet = 4;
1955 break;
1956 }
1957 }
1958
1959 if( !bPgNumFnd )
1960 nRet = 1;
1961 }
1962
1963 return nRet;
1964}
1965
1966static bool lcl_IsHyperlinked(const SwForm& rForm, sal_uInt16 nTOXLvl)
1967{
1968 bool bRes = false;
1969 for (sal_uInt16 nI = 1; nI < nTOXLvl; ++nI)
1970 {
1971 // #i21237#
1972 SwFormTokens aPattern = rForm.GetPattern(nI);
1973
1974 if ( !aPattern.empty() )
1975 {
1976 SwFormTokens::iterator aIt = aPattern.begin();
1977
1978 FormTokenType eTType;
1979
1980 // #i21237#
1981 while ( ++aIt != aPattern.end() )
1982 {
1983 eTType = aIt->eTokenType;
1984 switch (eTType)
1985 {
1986 case TOKEN_LINK_START:
1987 case TOKEN_LINK_END:
1988 bRes = true;
1989 break;
1990 default:
1991 ;
1992 }
1993 }
1994 }
1995 }
1996 return bRes;
1997}
1998
1999void AttributeOutputBase::GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter)
2000{
2001 if(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF) // Not implemented for RTF
2002 return;
2003
2004 const SwpHints* pTextAttrs = rNode.GetpSwpHints();
2005 if (!pTextAttrs)
2006 return;
2007
2008 for( size_t i = 0; i < pTextAttrs->Count(); ++i )
2009 {
2010 const SwTextAttr* pHt = pTextAttrs->Get(i);
2011 if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
2012 {
2013 const SwFormatField& rField = static_cast<const SwFormatField&>(pHt->GetAttr());
2014 const SwField* pField = rField.GetField();
2015 // Need to have bookmarks only for sequence fields
2016 if (pField && pField->GetTyp()->Which() == SwFieldIds::SetExp && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
2017 {
2018 const sal_uInt16 nSeqFieldNumber = static_cast<const SwSetExpField*>(pField)->GetSeqNumber();
2019 const OUString sObjectName = static_cast<const SwSetExpFieldType*>(pField->GetTyp())->GetName();
2020 const SwFieldTypes* pFieldTypes = GetExport().m_rDoc.getIDocumentFieldsAccess().GetFieldTypes();
2021 bool bHaveFullBkm = false;
2022 bool bHaveLabelAndNumberBkm = false;
2023 bool bHaveCaptionOnlyBkm = false;
2024 bool bHaveNumberOnlyBkm = false;
2025 bool bRunSplittedAtSep = false;
2026 for( auto const & pFieldType : *pFieldTypes )
2027 {
2028 if( SwFieldIds::GetRef == pFieldType->Which() )
2029 {
2030 SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
2031 for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
2032 {
2033 SwGetRefField* pRefField = static_cast<SwGetRefField*>(pFormatField->GetField());
2034 // If we have a reference to the current sequence field
2035 if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
2036 {
2037 // Need to create a separate run for separator character
2038 SwWW8AttrIter aLocalAttrIter( GetExport(), rNode ); // We need a local iterator having the right number of runs
2039 const OUString& aText = rNode.GetText();
2040 const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
2041 const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
2042 bool bCategoryFirst = nCategoryStart < pHt->GetStart();
2043 sal_Int32 nSeparatorPos = 0;
2044 if (bCategoryFirst)
2045 {
2046 nSeparatorPos = aLocalAttrIter.WhereNext();
2047 while (nSeparatorPos <= nPosBeforeSeparator)
2048 {
2049 aLocalAttrIter.NextPos();
2050 nSeparatorPos = aLocalAttrIter.WhereNext();
2051 }
2052 }
2053 else
2054 {
2055 nSeparatorPos = nCategoryStart + pRefField->GetSetRefName().getLength();
2056 }
2057 sal_Int32 nRefTextPos = 0;
2058 if(nSeparatorPos < aText.getLength())
2059 {
2060 nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), GetExport().m_rDoc, nSeparatorPos);
2061 if(nRefTextPos != nSeparatorPos)
2062 {
2063 if(!bRunSplittedAtSep)
2064 {
2065 if(!bCategoryFirst)
2066 rAttrIter.SplitRun(nSeparatorPos);
2067 rAttrIter.SplitRun(nRefTextPos);
2068 bRunSplittedAtSep = true;
2069 }
2070 if(!bCategoryFirst)
2071 aLocalAttrIter.SplitRun(nSeparatorPos);
2072 aLocalAttrIter.SplitRun(nRefTextPos);
2073 }
2074 else if (bCategoryFirst)
2075 {
2076 if(!bRunSplittedAtSep)
2077 {
2078 rAttrIter.SplitRun(nSeparatorPos);
2079 bRunSplittedAtSep = true;
2080 }
2081 aLocalAttrIter.SplitRun(nSeparatorPos);
2082 }
2083 }
2084 // Generate bookmarks on the right position
2085 OUString sName("Ref_" + pRefField->GetSetRefName() + OUString::number(pRefField->GetSeqNo()));
2086 switch (pRefField->GetFormat())
2087 {
2088 case REF_PAGE:
2089 case REF_PAGE_PGDESC:
2090 case REF_CONTENT:
2091 case REF_UPDOWN:
2092 if(!bHaveFullBkm)
2093 {
2094 sal_Int32 nLastAttrStart = 0;
2095 sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
2096 while (nActAttr < rNode.GetText().getLength())
2097 {
2098 nLastAttrStart = nActAttr;
2099 aLocalAttrIter.NextPos();
2100 nActAttr = aLocalAttrIter.WhereNext();
2101 }
2102 WriteBookmarkInActParagraph( sName + "_full", std::min(nCategoryStart, pHt->GetStart()), nLastAttrStart );
2103 bHaveFullBkm = true;
2104 }
2105 break;
2106 case REF_ONLYNUMBER:
2107 {
2108 if(!bHaveLabelAndNumberBkm)
2109 {
2110 sName += "_label_and_number";
2111 if(bCategoryFirst)
2112 WriteBookmarkInActParagraph( sName, std::min(nCategoryStart, pHt->GetStart()), std::max(nCategoryStart, pHt->GetStart()) );
2113 else
2114 {
2115 // Find the last run which contains category text
2116 SwWW8AttrIter aLocalAttrIter2( GetExport(), rNode );
2117 sal_Int32 nCatLastRun = 0;
2118 sal_Int32 nNextAttr = aLocalAttrIter2.WhereNext();
2119 while (nNextAttr < nSeparatorPos)
2120 {
2121 nCatLastRun = nNextAttr;
2122 aLocalAttrIter2.NextPos();
2123 nNextAttr = aLocalAttrIter2.WhereNext();
2124 }
2125 WriteBookmarkInActParagraph( sName, pHt->GetStart(), nCatLastRun );
2126 }
2127 bHaveLabelAndNumberBkm = true;
2128 }
2129 break;
2130 }
2131 case REF_ONLYCAPTION:
2132 {
2133 if(!bHaveCaptionOnlyBkm)
2134 {
2135 // Find last run
2136 sal_Int32 nLastAttrStart = 0;
2137 sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
2138 while (nActAttr < rNode.GetText().getLength())
2139 {
2140 nLastAttrStart = nActAttr;
2141 aLocalAttrIter.NextPos();
2142 nActAttr = aLocalAttrIter.WhereNext();
2143 }
2144 WriteBookmarkInActParagraph( sName + "_caption_only", nRefTextPos, nLastAttrStart );
2145 bHaveCaptionOnlyBkm = true;
2146 }
2147 break;
2148 }
2149 case REF_ONLYSEQNO:
2150 {
2151 if(!bHaveNumberOnlyBkm)
2152 {
2153 WriteBookmarkInActParagraph( sName + "_number_only", pHt->GetStart(), pHt->GetStart() );
2154 bHaveNumberOnlyBkm = true;
2155 }
2156 break;
2157 }
2158 }
2159 }
2160 }
2161 }
2162 }
2163 return;
2164 }
2165 }
2166 }
2167}
2168
2169void AttributeOutputBase::StartTOX( const SwSection& rSect )
2170{
2171 if ( const SwTOXBase* pTOX = rSect.GetTOXBase() )
2172 {
2173 static const char sEntryEnd[] = "\" ";
2174
2175 ww::eField eCode = ww::eTOC;
2176 OUString sStr = pTOX ->GetMSTOCExpression();
2177 if ( sStr.isEmpty() )
2178 {
2179 switch (pTOX->GetType())
2180 {
2181 case TOX_INDEX:
2182 eCode = ww::eINDEX;
2183 sStr = FieldString(eCode);
2184
2185 {
2186 const SwFormatCol& rCol = rSect.GetFormat()->GetFormatAttr( RES_COL );
2187 const SwColumns& rColumns = rCol.GetColumns();
2188 sal_Int32 nCol = rColumns.size();
2189
2190 if ( 0 < nCol )
2191 {
2192 // Add a continuous section break
2193 if( GetExport().AddSectionBreaksForTOX() )
2194 {
2195 SwSection *pParent = rSect.GetParent();
2196 WW8_SepInfo rInfo(&GetExport().m_rDoc.GetPageDesc(0),
2197 pParent ? pParent->GetFormat() : nullptr, 0/*nRstLnNum*/);
2198 GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, false, &rInfo );
2199 }
2200
2201 sStr += "\\c \"" + OUString::number( nCol ) + "\"";
2202 }
2203 }
2204
2205 if (pTOX->GetTOXForm().IsCommaSeparated())
2206 sStr += "\\r ";
2207
2208 if (SwTOIOptions::AlphaDelimiter & pTOX->GetOptions())
2209 sStr += "\\h \"A\" ";
2210
2211 if(SwTOXElement::IndexEntryType & pTOX->GetCreateType())
2212 {
2213 sStr += "\\f ";
2214 const OUString& sName = pTOX->GetEntryTypeName();
2215 if(!sName.isEmpty())
2216 {
2217 sStr += sName + sEntryEnd;
2218 }
2219 }
2220
2221 if (!pTOX->GetTOXForm().IsCommaSeparated())
2222 {
2223 // In case of Run-in style no separators are added.
2224 OUString aFillText;
2225 for (sal_uInt8 n = 1; n <= 3; ++n)
2226 {
2227 OUString aText;
2228 int nRet = ::lcl_CheckForm(pTOX->GetTOXForm(), n, aText);
2229
2230 if( 3 == nRet )
2231 aFillText = aText;
2232 else if ((4 == nRet) || (2 == nRet))
2233 aFillText = "\t";
2234 else
2235 aFillText.clear();
2236 }
2237 sStr += "\\e \"" + aFillText + sEntryEnd;
2238 }
2239 break;
2240
2241 case TOX_ILLUSTRATIONS:
2242 case TOX_OBJECTS:
2243 case TOX_TABLES:
2244 if (!pTOX->IsFromObjectNames())
2245 {
2246 sStr = FieldString(eCode) + "\\c ";
2247 const OUString& seqName = pTOX->GetSequenceName();
2248 if(!seqName.isEmpty())
2249 {
2250 sStr += "\"" + seqName + sEntryEnd;
2251 }
2252 OUString aText;
2253 int nRet = ::lcl_CheckForm( pTOX->GetTOXForm(), 1, aText );
2254 if (1 == nRet)
2255 sStr += "\\n ";
2256 else if( 3 == nRet || 4 == nRet )
2257 {
2258 sStr += "\\p \"" + aText + sEntryEnd;
2259 }
2260 }
2261 break;
2262
2263 case TOX_AUTHORITIES:
2264 eCode = ww::eBIBLIOGRAPHY;
2265 sStr = FieldString(eCode);
2266 break;
2267 // case TOX_USER:
2268 // case TOX_CONTENT:
2269 default:
2270 {
2271 sStr = FieldString(eCode);
2272
2273 OUString sTOption;
2274 sal_uInt16 n, nTOXLvl = pTOX->GetLevel();
2275 if( !nTOXLvl )
2276 ++nTOXLvl;
2277
2278 if(SwTOXElement::TableLeader & pTOX->GetCreateType())
2279 {
2280 sStr +="\\z " ;
2281 GetExport( ).m_bHideTabLeaderAndPageNumbers = true ;
2282 }
2283 if(SwTOXElement::TableInToc & pTOX->GetCreateType())
2284 {
2285 sStr +="\\w " ;
2286 GetExport( ).m_bTabInTOC = true ;
2287 }
2288 if(SwTOXElement::Newline & pTOX->GetCreateType())
2289 {
2290 sStr +="\\x " ;
2291 }
2292 if( SwTOXElement::Mark & pTOX->GetCreateType() )
2293 {
2294 sStr += "\\f ";
2295
2296 if( TOX_USER == pTOX->GetType() )
2297 {
2298 sStr += "\""
2299 + OUStringChar(static_cast<char>( 'A' + GetExport( ).GetId( *pTOX->GetTOXType() ) ))
2300 + sEntryEnd;
2301 }
2302 }
2303 if(SwTOXElement::Bookmark & pTOX->GetCreateType())
2304 {
2305 sStr += "\\b \"" + pTOX->GetBookmarkName() + sEntryEnd;
2306 }
2307
2308 if( SwTOXElement::OutlineLevel & pTOX->GetCreateType() )
2309 {
2310 // Take the TOC value of the max level to evaluate to as
2311 // the starting point for the \o flag, but reduce it to the
2312 // value of the highest outline level filled by a *standard*
2313 // Heading 1 - 9 style because \o "Builds a table of
2314 // contents from paragraphs formatted with built-in heading
2315 // styles". And afterward fill in any outline styles left
2316 // uncovered by that range to the \t flag
2317
2318 // i.e. for
2319 // Heading 1
2320 // Heading 2
2321 // custom-style
2322 // Heading 4
2323 // output
2324 // \o 1-2 \tcustom-style,3,Heading 3,4
2325
2326 // Search over all the outline styles used and figure out
2327 // what is the minimum outline level (if any) filled by a
2328 // non-standard style for that level, i.e. ignore headline
2329 // styles 1-9 and find the lowest valid outline level
2330 sal_uInt8 nPosOfLowestNonStandardLvl = MAXLEVEL;
2331 const SwTextFormatColls& rColls = *GetExport().m_rDoc.GetTextFormatColls();
2332 for( n = rColls.size(); n; )
2333 {
2334 const SwTextFormatColl* pColl = rColls[ --n ];
2335 sal_uInt16 nPoolId = pColl->GetPoolFormatId();
2336 if (
2337 //Is a Non-Standard Outline Style
2338 (RES_POOLCOLL_HEADLINE1 > nPoolId || RES_POOLCOLL_HEADLINE9 < nPoolId) &&
2339 //Has a valid outline level
2340 (pColl->IsAssignedToListLevelOfOutlineStyle()) &&
2341 // Is less than the lowest known non-standard level
2342 (pColl->GetAssignedOutlineStyleLevel() < nPosOfLowestNonStandardLvl)
2343 )
2344 {
2345 nPosOfLowestNonStandardLvl = ::sal::static_int_cast<sal_uInt8>(pColl->GetAssignedOutlineStyleLevel());
2346 }
2347 }
2348
2349 sal_uInt8 nMaxMSAutoEvaluate = nPosOfLowestNonStandardLvl < nTOXLvl ? nPosOfLowestNonStandardLvl : static_cast<sal_uInt8>(nTOXLvl);
2350
2351 //output \o 1-X where X is the highest normal outline style to be included in the toc
2352 if ( nMaxMSAutoEvaluate )
2353 {
2354 if (nMaxMSAutoEvaluate > WW8ListManager::nMaxLevel)
2355 nMaxMSAutoEvaluate = WW8ListManager::nMaxLevel;
2356
2357 sStr += "\\o \"1-" + OUString::number(nMaxMSAutoEvaluate) + sEntryEnd;
2358 }
2359
2360 //collect up any other styles in the writer TOC which will
2361 //not already appear in the MS TOC and place then into the
2362 //\t option
2363 if( nMaxMSAutoEvaluate < nTOXLvl )
2364 {
2365 // collect this templates into the \t option
2366 for( n = rColls.size(); n;)
2367 {
2368 const SwTextFormatColl* pColl = rColls[ --n ];
2369 if (!pColl->IsAssignedToListLevelOfOutlineStyle())
2370 continue;
2371 sal_uInt8 nTestLvl = ::sal::static_int_cast<sal_uInt8>(pColl->GetAssignedOutlineStyleLevel());
2372 if (nTestLvl < nTOXLvl && nTestLvl >= nMaxMSAutoEvaluate)
2373 {
2374 if (!sTOption.isEmpty())
2375 sTOption += ",";
2376 sTOption += pColl->GetName() + "," + OUString::number( nTestLvl + 1 );
2377 }
2378 }
2379 }
2380 }
2381
2382 if( SwTOXElement::ParagraphOutlineLevel & pTOX->GetCreateType() )
2383 {
2384 sStr +="\\u " ;
2385 }
2386
2387 if( SwTOXElement::Template & pTOX->GetCreateType() )
2388 {
2389 // #i99641# - Consider additional styles regardless of TOX-outlinelevel
2390 for( n = 0; n < MAXLEVEL; ++n )
2391 {
2392 const OUString& rStyles = pTOX->GetStyleNames( n );
2393 if( !rStyles.isEmpty() )
2394 {
2395 sal_Int32 nPos = 0;
2396 const OUString sLvl{ "," + OUString::number( n + 1 ) };
2397 do {
2398 const OUString sStyle( rStyles.getToken( 0, TOX_STYLE_DELIMITERu'\x0001', nPos ));
2399 if( !sStyle.isEmpty() )
2400 {
2401 SwTextFormatColl* pColl = GetExport().m_rDoc.FindTextFormatCollByName(sStyle);
2402 if (pColl)
2403 {
2404 if (!pColl->IsAssignedToListLevelOfOutlineStyle() || pColl->GetAssignedOutlineStyleLevel() < nTOXLvl)
2405 {
2406 if( !sTOption.isEmpty() )
2407 sTOption += ",";
2408 sTOption += sStyle + sLvl;
2409 }
2410 }
2411 }
2412 } while( -1 != nPos );
2413 }
2414 }
2415 }
2416
2417 // No 'else' branch; why the below snippet is a block I have no idea.
2418 {
2419 OUString aFillText;
2420 sal_uInt8 nNoPgStt = MAXLEVEL, nNoPgEnd = MAXLEVEL;
2421 bool bFirstFillText = true, bOnlyText = true;
2422 for( n = 0; n < nTOXLvl; ++n )
2423 {
2424 OUString aText;
2425 int nRet = ::lcl_CheckForm( pTOX->GetTOXForm(),
2426 static_cast< sal_uInt8 >(n+1), aText );
2427 if( 1 == nRet )
2428 {
2429 bOnlyText = false;
2430 if( MAXLEVEL == nNoPgStt )
2431 nNoPgStt = static_cast< sal_uInt8 >(n+1);
2432 }
2433 else
2434 {
2435 if( MAXLEVEL != nNoPgStt &&
2436 MAXLEVEL == nNoPgEnd )
2437 nNoPgEnd = sal_uInt8(n);
2438
2439 bOnlyText = bOnlyText && 3 == nRet;
2440 if( 3 == nRet || 4 == nRet )
2441 {
2442 if( bFirstFillText )
2443 aFillText = aText;
2444 else if( aFillText != aText )
2445 aFillText.clear();
2446 bFirstFillText = false;
2447 }
2448 }
2449 }
2450 if( MAXLEVEL != nNoPgStt )
2451 {
2452 if (WW8ListManager::nMaxLevel < nNoPgEnd)
2453 nNoPgEnd = WW8ListManager::nMaxLevel;
2454 sStr += "\\n "
2455 + OUString::number( nNoPgStt )
2456 + "-"
2457 + OUString::number( nNoPgEnd )
2458 + " ";
2459 }
2460 if( bOnlyText )
2461 {
2462 sStr += "\\p \"" + aFillText + sEntryEnd;
2463 }
2464 }
2465
2466 if( !sTOption.isEmpty() )
2467 {
2468 sStr += "\\t \"" + sTOption + sEntryEnd;
2469 }
2470
2471 if (lcl_IsHyperlinked(pTOX->GetTOXForm(), nTOXLvl))
2472 sStr += "\\h";
2473 break;
2474 }
2475 }
2476 }
2477
2478 if (!sStr.isEmpty())
2479 {
2480 GetExport( ).m_bInWriteTOX = true;
2481 if (GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
2482 { // tdf#129574: required for RTF; doesn't work with DOCX
2483 StartRun(nullptr, -42, true);
2484 }
2485 GetExport( ).OutputField( nullptr, eCode, sStr, FieldFlags::Start | FieldFlags::CmdStart |
2486 FieldFlags::CmdEnd );
2487 if (GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
2488 {
2489 EndRun(nullptr, -42, true);
2490 }
2491 }
2492 }
2493
2494 GetExport( ).m_bStartTOX = false;
2495}
2496
2497void AttributeOutputBase::EndTOX( const SwSection& rSect,bool bCareEnd )
2498{
2499 const SwTOXBase* pTOX = rSect.GetTOXBase();
2500 if ( pTOX )
2501 {
2502 ww::eField eCode = TOX_INDEX == pTOX->GetType() ? ww::eINDEX : ww::eTOC;
2503 GetExport( ).OutputField( nullptr, eCode, OUString(), FieldFlags::Close );
2504
2505 if ( pTOX->GetType() == TOX_INDEX && GetExport().AddSectionBreaksForTOX() )
2506 {
2507 const SwFormatCol& rCol = rSect.GetFormat()->GetFormatAttr( RES_COL );
2508 const SwColumns& rColumns = rCol.GetColumns();
2509 sal_Int32 nCol = rColumns.size();
2510
2511 if ( 0 < nCol )
2512 {
2513 WW8_SepInfo rInfo( &GetExport().m_rDoc.GetPageDesc( 0 ), rSect.GetFormat(), 0/*nRstLnNum*/ );
2514 GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, false, &rInfo );
2515 }
2516 }
2517 }
2518 GetExport( ).m_bInWriteTOX = false;
2519 GetExport( ).m_bHideTabLeaderAndPageNumbers = false;
2520 if (bCareEnd)
2521 OnTOXEnding();
2522}
2523
2524bool MSWordExportBase::GetNumberFormat(const SwField& rField, OUString& rStr)
2525{
2526 // Returns a date or time format string by using the US NfKeywordTable
2527 bool bHasFormat = false;
2528 SvNumberFormatter* pNFormatr = m_rDoc.GetNumberFormatter();
2529 sal_uInt32 nFormatIdx = rField.GetFormat();
2530 const SvNumberformat* pNumFormat = pNFormatr->GetEntry( nFormatIdx );
2531 if( pNumFormat )
2532 {
2533 LanguageType nLng = rField.GetLanguage();
2534 LocaleDataWrapper aLocDat(pNFormatr->GetComponentContext(),
2535 LanguageTag(nLng));
2536
2537 OUString sFormat(pNumFormat->GetMappedFormatstring(GetNfKeywordTable(),
2538 aLocDat));
2539
2540 if (!sFormat.isEmpty())
2541 {
2542 sw::ms::SwapQuotesInField(sFormat);
2543
2544 rStr = "\\@\"" + sFormat + "\" " ;
2545 bHasFormat = true;
2546 }
2547 }
2548 return bHasFormat;
2549}
2550
2551void AttributeOutputBase::GetNumberPara( OUString& rStr, const SwField& rField )
2552{
2553 switch(rField.GetFormat())
2554 {
2555 case SVX_NUM_CHARS_UPPER_LETTER:
2556 case SVX_NUM_CHARS_UPPER_LETTER_N:
2557 rStr += "\\* ALPHABETIC ";
2558 break;
2559 case SVX_NUM_CHARS_LOWER_LETTER:
2560 case SVX_NUM_CHARS_LOWER_LETTER_N:
2561 rStr += "\\* alphabetic ";
2562 break;
2563 case SVX_NUM_ROMAN_UPPER:
2564 rStr += "\\* ROMAN ";
2565 break;
2566 case SVX_NUM_ROMAN_LOWER:
2567 rStr += "\\* roman ";
2568 break;
2569 default:
2570 OSL_ENSURE(rField.GetFormat() == SVX_NUM_ARABIC,do { if (true && (!(rField.GetFormat() == SVX_NUM_ARABIC
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "2571" ": "), "%s", "Unknown numbering type exported as default of Arabic"
); } } while (false)
2571 "Unknown numbering type exported as default of Arabic")do { if (true && (!(rField.GetFormat() == SVX_NUM_ARABIC
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "2571" ": "), "%s", "Unknown numbering type exported as default of Arabic"
); } } while (false)
;
2572 [[fallthrough]];
2573 case SVX_NUM_ARABIC:
2574 rStr += "\\* ARABIC ";
2575 break;
2576 case SVX_NUM_PAGEDESC:
2577 //Nothing, use word's default
2578 break;
2579 }
2580}
2581
2582void WW8Export::WritePostItBegin( ww::bytes* pOut )
2583{
2584 sal_uInt8 aArr[ 3 ];
2585 sal_uInt8* pArr = aArr;
2586
2587 // sprmCFSpec true
2588 Set_UInt16( pArr, NS_sprm::CFSpec::val );
2589 Set_UInt8( pArr, 1 );
2590
2591 m_pChpPlc->AppendFkpEntry( Strm().Tell() );
2592 WriteChar( 0x05 ); // Annotation reference
2593
2594 if( pOut )
2595 pOut->insert( pOut->end(), aArr, pArr );
2596 else
2597 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
2598}
2599
2600OUString FieldString(ww::eField eIndex)
2601{
2602 if (const char *pField = ww::GetEnglishFieldName(eIndex))
2603 return " " + OUString::createFromAscii(pField) + " ";
2604 return " ";
2605}
2606
2607void WW8AttributeOutput::HiddenField( const SwField& rField )
2608{
2609 //replace LF 0x0A with VT 0x0B
2610 const OUString sExpand(rField.GetPar2().replace(0x0A, 0x0B));
2611
2612 m_rWW8Export.m_pChpPlc->AppendFkpEntry(m_rWW8Export.Strm().Tell());
2613 SwWW8Writer::WriteString16(m_rWW8Export.Strm(), sExpand, false);
2614 static sal_uInt8 aArr[] =
2615 {
2616 0x3C, 0x08, 0x1
2617 };
2618 m_rWW8Export.m_pChpPlc->AppendFkpEntry(m_rWW8Export.Strm().Tell(), sizeof(aArr), aArr);
2619}
2620
2621void WW8AttributeOutput::SetField( const SwField& rField, ww::eField eType, const OUString& rCmd )
2622{
2623 const SwSetExpField* pSet = static_cast<const SwSetExpField*>(&rField);
2624 const OUString &rVar = pSet->GetPar2();
2625
2626 sal_uLong nFrom = m_rWW8Export.Fc2Cp(m_rWW8Export.Strm().Tell());
2627
2628 GetExport().OutputField(&rField, eType, rCmd, FieldFlags::Start |
2629 FieldFlags::CmdStart | FieldFlags::CmdEnd);
2630
2631 /*
2632 Is there a bookmark at the start position of this field, if so
2633 move it to the 0x14 of the result of the field. This is what word
2634 does. MoveFieldMarks moves any bookmarks at this position to
2635 the beginning of the field result, and marks the bookmark as a
2636 fieldbookmark which is to be ended before the field end mark
2637 instead of after it like a normal bookmark.
2638 */
2639 m_rWW8Export.MoveFieldMarks(nFrom,m_rWW8Export.Fc2Cp(m_rWW8Export.Strm().Tell()));
2640
2641 if (!rVar.isEmpty())
2642 {
2643 SwWW8Writer::WriteString16(m_rWW8Export.Strm(), rVar, false);
2644 }
2645 GetExport().OutputField(&rField, eType, rCmd, FieldFlags::Close);
2646}
2647
2648void WW8AttributeOutput::PostitField( const SwField* pField )
2649{
2650 const SwPostItField *pPField = static_cast<const SwPostItField*>(pField);
2651 m_rWW8Export.m_pAtn->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), pPField );
2652 m_rWW8Export.WritePostItBegin( m_rWW8Export.pO.get() );
2653}
2654
2655bool WW8AttributeOutput::DropdownField( const SwField* pField )
2656{
2657 const SwDropDownField& rField2 = *static_cast<const SwDropDownField*>(pField);
2658 uno::Sequence<OUString> aItems =
2659 rField2.GetItemSequence();
2660 GetExport().DoComboBox(rField2.GetName(),
2661 rField2.GetHelp(),
2662 rField2.GetToolTip(),
2663 rField2.GetSelectedItem(), aItems);
2664 return false;
2665}
2666
2667bool WW8AttributeOutput::PlaceholderField( const SwField* )
2668{
2669 return true; // expand to text?
2670}
2671
2672void WW8AttributeOutput::RefField( const SwField &rField, const OUString &rRef)
2673{
2674 const OUString sStr{ FieldString( ww::eREF ) + "\"" + rRef + "\" " };
2675 m_rWW8Export.OutputField( &rField, ww::eREF, sStr, FieldFlags::Start |
2676 FieldFlags::CmdStart | FieldFlags::CmdEnd );
2677 const OUString sVar = lcl_GetExpandedField( rField );
2678 if ( !sVar.isEmpty() )
2679 {
2680 SwWW8Writer::WriteString16( m_rWW8Export.Strm(), sVar, false );
2681 }
2682 m_rWW8Export.OutputField( &rField, ww::eREF, sStr, FieldFlags::Close );
2683}
2684
2685void WW8AttributeOutput::WriteExpand( const SwField* pField )
2686{
2687 SwWW8Writer::WriteString16( m_rWW8Export.Strm(), lcl_GetExpandedField( *pField ), false );
2688}
2689
2690namespace
2691{
2692// Escapes a token string for storing in Word formats. Its import counterpart
2693// is lcl_ExtractToken in writerfilter/source/dmapper/DomainMapper_Impl.cxx
2694OUString EscapeToken(const OUString& rCommand)
2695{
2696 bool bWasEscaped = false;
2697
2698 const int nBufferLen = rCommand.getLength()*1.5;
2699 OUStringBuffer sResult(nBufferLen);
2700 sResult.append('"'); // opening quote
2701 for (sal_Int32 i = 0; i < rCommand.getLength(); ++i)
2702 {
2703 sal_Unicode ch = rCommand[i];
2704 switch (ch)
2705 {
2706 case '\\':
2707 case '"':
2708 // Backslashes and doublequotes must be escaped
2709 bWasEscaped = true;
2710 sResult.append('\\');
2711 break;
2712 case ' ':
2713 // Spaces require quotation
2714 bWasEscaped = true;
2715 break;
2716 }
2717 sResult.append(ch);
2718 }
2719
2720 if (bWasEscaped)
2721 {
2722 sResult.append('"'); // closing quote
2723 return sResult.makeStringAndClear();
2724 }
2725 // No escapement/quotation was required
2726 return rCommand;
2727}
2728}
2729
2730void AttributeOutputBase::TextField( const SwFormatField& rField )
2731{
2732 const SwField* pField = rField.GetField();
2733 bool bWriteExpand = false;
2734 const sal_uInt16 nSubType = pField->GetSubType();
2735
2736 switch (pField->GetTyp()->Which())
2737 {
2738 case SwFieldIds::GetExp:
2739 if (nSubType == nsSwGetSetExpType::GSE_STRING)
2740 {
2741 const SwGetExpField *pGet = static_cast<const SwGetExpField*>(pField);
2742 RefField( *pGet, pGet->GetFormula() );
2743 }
2744 else
2745 bWriteExpand = true;
2746 break;
2747 case SwFieldIds::SetExp:
2748 if (nsSwGetSetExpType::GSE_SEQ == nSubType)
2749 {
2750 OUString sStr;
2751 if (GetExport().FieldsQuoted())
2752 sStr = FieldString(ww::eSEQ) + pField->GetTyp()->GetName() + " ";
2753 else
2754 sStr = FieldString(ww::eSEQ) + "\"" + pField->GetTyp()->GetName() +"\" ";
2755 GetNumberPara( sStr, *pField );
2756 GetExport().OutputField(pField, ww::eSEQ, sStr);
2757 }
2758 else if (nSubType & nsSwGetSetExpType::GSE_STRING)
2759 {
2760 bool bShowAsWell = false;
2761 ww::eField eFieldNo;
2762 const SwSetExpField *pSet = static_cast<const SwSetExpField*>(pField);
2763 const OUString sVar = pSet->GetPar2();
2764 OUString sStr;
2765 if (pSet->GetInputFlag())
2766 {
2767 sStr = FieldString(ww::eASK) + "\""
2768 + pSet->GetPar1() + "\" "
2769 + pSet->GetPromptText() + " \\d "
2770 + sVar;
2771 eFieldNo = ww::eASK;
2772 }
2773 else
2774 {
2775 sStr = FieldString(ww::eSET)
2776 + pSet->GetPar1() + " \""
2777 + sVar + "\" ";
2778 eFieldNo = ww::eSET;
2779 bShowAsWell = (nSubType & nsSwExtendedSubType::SUB_INVISIBLE) == 0;
2780 }
2781
2782 SetField( *pField, eFieldNo, sStr );
2783
2784 if (bShowAsWell)
2785 RefField( *pSet, pSet->GetPar1() );
2786 }
2787 else
2788 bWriteExpand = true;
2789 break;
2790 case SwFieldIds::PageNumber:
2791 {
2792 OUString sStr = FieldString(ww::ePAGE);
2793 GetNumberPara(sStr, *pField);
2794 GetExport().OutputField(pField, ww::ePAGE, sStr);
2795 }
2796 break;
2797 case SwFieldIds::Filename:
2798 {
2799 OUString sStr = FieldString(ww::eFILENAME);
2800 if (pField->GetFormat() == FF_PATHNAME)
2801 sStr += "\\p ";
2802 GetExport().OutputField(pField, ww::eFILENAME, sStr);
2803 }
2804 break;
2805 case SwFieldIds::Database:
2806 {
2807 OUString sStr = FieldString(ww::eMERGEFIELD)
2808 + EscapeToken(static_cast<SwDBFieldType *>(pField->GetTyp())->GetColumnName()) + " ";
2809 GetExport().OutputField(pField, ww::eMERGEFIELD, sStr);
2810 }
2811 break;
2812 case SwFieldIds::DatabaseName:
2813 {
2814 SwDBData aData = GetExport().m_rDoc.GetDBData();
2815 const OUString sStr = FieldString(ww::eDATABASE)
2816 + aData.sDataSource
2817 + OUStringChar(DB_DELIMu'\x00ff')
2818 + aData.sCommand;
2819 GetExport().OutputField(pField, ww::eDATABASE, sStr);
2820 }
2821 break;
2822 case SwFieldIds::Author:
2823 {
2824 ww::eField eField =
2825 ((AF_SHORTCUT & pField->GetFormat()) ? ww::eUSERINITIALS : ww::eUSERNAME);
2826 GetExport().OutputField(pField, eField, FieldString(eField));
2827 }
2828 break;
2829 case SwFieldIds::TemplateName:
2830 GetExport().OutputField(pField, ww::eTEMPLATE, FieldString(ww::eTEMPLATE));
2831 break;
2832 case SwFieldIds::DocInfo: // Last printed, last edited,...
2833 if( DI_SUB_FIXED & nSubType )
2834 bWriteExpand = true;
2835 else
2836 {
2837 OUString sStr;
2838 ww::eField eField(ww::eNONE);
2839 switch (0xff & nSubType)
2840 {
2841 case DI_TITLE:
2842 eField = ww::eTITLE;
2843 break;
2844 case DI_SUBJECT:
2845 eField = ww::eSUBJECT;
2846 break;
2847 case DI_KEYS:
2848 eField = ww::eKEYWORDS;
2849 break;
2850 case DI_COMMENT:
2851 eField = ww::eCOMMENTS;
2852 break;
2853 case DI_DOCNO:
2854 eField = ww::eREVNUM;
2855 break;
2856 case DI_CREATE:
2857 if (DI_SUB_AUTHOR == (nSubType & DI_SUB_MASK))
2858 eField = ww::eAUTHOR;
2859 else if (GetExport().GetNumberFormat(*pField, sStr))
2860 eField = ww::eCREATEDATE;
2861 break;
2862
2863 case DI_CHANGE:
2864 if (DI_SUB_AUTHOR == (nSubType & DI_SUB_MASK))
2865 eField = ww::eLASTSAVEDBY;
2866 else if (GetExport().GetNumberFormat(*pField, sStr))
2867 eField = ww::eSAVEDATE;
2868 break;
2869
2870 case DI_PRINT:
2871 if (DI_SUB_AUTHOR != (nSubType & DI_SUB_MASK) &&
2872 GetExport().GetNumberFormat(*pField, sStr))
2873 eField = ww::ePRINTDATE;
2874 break;
2875 case DI_EDIT:
2876 if( DI_SUB_AUTHOR != (nSubType & DI_SUB_MASK ) &&
2877 GetExport().GetNumberFormat( *pField, sStr ))
2878 eField = ww::eSAVEDATE;
2879 else
2880 eField = ww::eEDITTIME;
2881 break;
2882 case DI_CUSTOM:
2883 eField = ww::eDOCPROPERTY;
2884 {
2885 const SwDocInfoField * pDocInfoField =
2886 dynamic_cast<const SwDocInfoField *> (pField);
2887
2888 if (pDocInfoField != nullptr)
2889 {
2890 OUString sFieldname = pDocInfoField->GetFieldName();
2891
2892 const sal_Int32 nIndex = sFieldname.indexOf(':');
2893 if (nIndex >= 0)
2894 sFieldname = sFieldname.copy(nIndex + 1);
2895
2896 sStr = "\"" + sFieldname + "\"";
2897 }
2898 }
2899 break;
2900 default:
2901 break;
2902 }
2903
2904 if (eField != ww::eNONE)
2905 {
2906 GetExport().OutputField(pField, eField, FieldString(eField) + sStr);
2907 }
2908 else
2909 bWriteExpand = true;
2910 }
2911 break;
2912 case SwFieldIds::DateTime:
2913 {
2914 OUString sStr;
2915 if (!GetExport().GetNumberFormat(*pField, sStr))
2916 bWriteExpand = true;
2917 else
2918 {
2919 ww::eField eField = (DATEFLD & nSubType) ? ww::eDATE : ww::eTIME;
2920 GetExport().OutputField(pField, eField, FieldString(eField) + sStr);
2921 }
2922 }
2923 break;
2924 case SwFieldIds::DocStat:
2925 {
2926 ww::eField eField = ww::eNONE;
2927
2928 switch (nSubType)
2929 {
2930 case DS_PAGE:
2931 eField = ww::eNUMPAGES;
2932 break;
2933 case DS_WORD:
2934 eField = ww::eNUMWORDS;
2935 break;
2936 case DS_CHAR:
2937 eField = ww::eNUMCHARS;
2938 break;
2939 }
2940
2941 if (eField != ww::eNONE)
2942 {
2943 OUString sStr = FieldString(eField);
2944 GetNumberPara(sStr, *pField);
2945 GetExport().OutputField(pField, eField, sStr);
2946 }
2947 else
2948 bWriteExpand = true;
2949 }
2950 break;
2951 case SwFieldIds::ExtUser:
2952 {
2953 ww::eField eField = ww::eNONE;
2954 switch (0xFF & nSubType)
2955 {
2956 case EU_FIRSTNAME:
2957 case EU_NAME:
2958 eField = ww::eUSERNAME;
2959 break;
2960 case EU_SHORTCUT:
2961 eField = ww::eUSERINITIALS;
2962 break;
2963 case EU_STREET:
2964 case EU_COUNTRY:
2965 case EU_ZIP:
2966 case EU_CITY:
2967 eField = ww::eUSERADDRESS;
2968 break;
2969 }
2970
2971 if (eField != ww::eNONE)
2972 {
2973 GetExport().OutputField(pField, eField, FieldString(eField));
2974 }
2975 else
2976 bWriteExpand = true;
2977 }
2978 break;
2979 case SwFieldIds::TableOfAuthorities:
2980 {
2981 OUString sRet(static_cast<SwAuthorityField const*>(pField)
2982 ->ExpandCitation(AUTH_FIELD_IDENTIFIER, nullptr));
2983 // FIXME: DomainMapper_Impl::CloseFieldCommand() stuffs fully formed
2984 // field instructions in here, but if the field doesn't originate
2985 // from those filters it won't have that
2986 if (!sRet.trim().startsWith("CITATION"))
2987 {
2988 sRet = FieldString(ww::eCITATION) + " \"" + sRet + "\"";
2989 }
2990 GetExport().OutputField( pField, ww::eCITATION, sRet );
2991 }
2992 break;
2993 case SwFieldIds::Postit:
2994 //Sadly only possible for word in main document text
2995 if (GetExport().m_nTextTyp == TXT_MAINTEXT)
2996 {
2997 PostitField( pField );
2998 }
2999 break;
3000 case SwFieldIds::Input:
3001 {
3002 const SwInputField * pInputField = dynamic_cast<const SwInputField *>(pField);
3003
3004 if (pInputField && pInputField->isFormField())
3005 GetExport().DoFormText(pInputField);
3006 else
3007 {
3008 const OUString sStr = FieldString(ww::eFILLIN) + "\""
3009 + pField->GetPar2() + "\"";
3010
3011 GetExport().OutputField(pField, ww::eFILLIN, sStr);
3012 }
3013 }
3014 break;
3015 case SwFieldIds::GetRef:
3016 {
3017 ww::eField eField = ww::eNONE;
3018 OUString sStr;
3019 const SwGetRefField& rRField = *static_cast<const SwGetRefField*>(pField);
3020 switch (nSubType)
3021 {
3022 case REF_SETREFATTR:
3023 case REF_BOOKMARK:
3024 switch (pField->GetFormat())
3025 {
3026 case REF_PAGE_PGDESC:
3027 case REF_PAGE:
3028 eField = ww::ePAGEREF;
3029 break;
3030 default:
3031 eField = ww::eREF;
3032 break;
3033 }
3034 {
3035 const OUString& aRefName(rRField.GetSetRefName());
3036 sStr = FieldString(eField)
3037 + MSWordExportBase::GetBookmarkName(nSubType, &aRefName, 0);
3038 }
3039 switch (pField->GetFormat())
3040 {
3041 case REF_NUMBER:
3042 sStr += " \\r";
3043 break;
3044 case REF_NUMBER_NO_CONTEXT:
3045 sStr += " \\n";
3046 break;
3047 case REF_NUMBER_FULL_CONTEXT:
3048 sStr += " \\w";
3049 break;
3050 }
3051 break;
3052 case REF_SEQUENCEFLD:
3053 {
3054 // Not implemented for RTF
3055 if(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
3056 break;
3057
3058 switch (pField->GetFormat())
3059 {
3060 case REF_PAGE:
3061 case REF_PAGE_PGDESC:
3062 eField = ww::ePAGEREF;
3063 break;
3064 default:
3065 eField = ww::eREF;
3066 break;
3067 }
3068 // Generate a unique bookmark name
3069 {
3070 OUString sName{rRField.GetSetRefName() + OUString::number(rRField.GetSeqNo())};
3071 switch (pField->GetFormat())
3072 {
3073 case REF_PAGE:
3074 case REF_PAGE_PGDESC:
3075 case REF_CONTENT:
3076 case REF_UPDOWN:
3077 sName += "_full";
3078 break;
3079 case REF_ONLYNUMBER:
3080 sName += "_label_and_number";
3081 break;
3082 case REF_ONLYCAPTION:
3083 sName += "_caption_only";
3084 break;
3085 case REF_ONLYSEQNO:
3086 sName += "_number_only";
3087 break;
3088 default: // Ignore other types of reference fields
3089 eField = ww::eNONE;
3090 break;
3091 }
3092 sStr = FieldString(eField) + MSWordExportBase::GetBookmarkName(nSubType, &sName, 0);
3093 }
3094 switch (pField->GetFormat())
3095 {
3096 case REF_NUMBER:
3097 sStr += " \\r";
3098 break;
3099 case REF_NUMBER_NO_CONTEXT:
3100 sStr += " \\n";
3101 break;
3102 case REF_NUMBER_FULL_CONTEXT:
3103 sStr += " \\w";
3104 break;
3105 }
3106 break;
3107 }
3108 case REF_FOOTNOTE:
3109 case REF_ENDNOTE:
3110 switch (pField->GetFormat())
3111 {
3112 case REF_PAGE_PGDESC:
3113 case REF_PAGE:
3114 eField = ww::ePAGEREF;
3115 break;
3116 case REF_UPDOWN:
3117 eField = ww::eREF;
3118 break;
3119 default:
3120 eField =
3121 REF_ENDNOTE == nSubType ? ww::eNOTEREF : ww::eFOOTREF;
3122 break;
3123 }
3124 sStr = FieldString(eField)
3125 + MSWordExportBase::GetBookmarkName(nSubType, nullptr, rRField.GetSeqNo());
3126 break;
3127 }
3128
3129 if (eField != ww::eNONE)
3130 {
3131 switch (pField->GetFormat())
3132 {
3133 case REF_UPDOWN:
3134 sStr += " \\p \\h "; // with hyperlink
3135 break;
3136 case REF_CHAPTER:
3137 sStr += " \\n \\h "; // with hyperlink
3138 break;
3139 default:
3140 sStr += " \\h "; // insert hyperlink
3141 break;
3142 }
3143 GetExport().OutputField(pField, eField, sStr);
3144 }
3145 else
3146 bWriteExpand = true;
3147 }
3148 break;
3149 case SwFieldIds::CombinedChars:
3150 {
3151 /*
3152 We need a font size to fill in the defaults, if these are overridden
3153 (as they generally are) by character properties then those properties
3154 win.
3155
3156 The fontsize that is used in MS for determining the defaults is always
3157 the CJK fontsize even if the text is not in that language, in OOo the
3158 largest fontsize used in the field is the one we should take, but
3159 whatever we do, word will actually render using the fontsize set for
3160 CJK text. Nevertheless we attempt to guess whether the script is in
3161 asian or western text based up on the first character and use the
3162 font size of that script as our default.
3163 */
3164 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt->
GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()"
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 3164, __extension__ __PRETTY_FUNCTION__))
;
3165 sal_uInt16 nScript = g_pBreakIt->GetBreakIter()->getScriptType( pField->GetPar1(), 0);
3166
3167 long nHeight = static_cast<const SvxFontHeightItem&>((GetExport().GetItem(
3168 GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript)))).GetHeight();
3169
3170 nHeight = (nHeight + 10) / 20; //Font Size in points;
3171
3172 /*
3173 Divide the combined char string into its up and down part. Get the
3174 font size and fill in the defaults as up == half the font size and
3175 down == a fifth the font size
3176 */
3177 const sal_Int32 nAbove = (pField->GetPar1().getLength()+1)/2;
3178 const OUString sStr = FieldString(ww::eEQ)
3179 + "\\o (\\s\\up "
3180 + OUString::number(nHeight/2)
3181 + "("
3182 + pField->GetPar1().copy(0, nAbove)
3183 + "), \\s\\do "
3184 + OUString::number(nHeight/5)
3185 + "("
3186 + pField->GetPar1().copy(nAbove)
3187 + "))";
3188 GetExport().OutputField(pField, ww::eEQ, sStr);
3189 }
3190 break;
3191 case SwFieldIds::Dropdown:
3192 bWriteExpand = DropdownField( pField );
3193 break;
3194 case SwFieldIds::Chapter:
3195 bWriteExpand = true;
3196 if (GetExport().m_bOutKF && rField.GetTextField())
3197 {
3198 const SwTextNode *pTextNd = GetExport().GetHdFtPageRoot();
3199 if (!pTextNd)
3200 {
3201 pTextNd = GetExport().m_pCurPam->GetNode().GetTextNode();
3202 }
3203
3204 if (pTextNd)
3205 {
3206 SwChapterField aCopy(*static_cast<const SwChapterField*>(pField));
3207 aCopy.ChangeExpansion(*pTextNd, false);
3208 const OUString sStr = FieldString(ww::eSTYLEREF)
3209 + " "
3210 + OUString::number(aCopy.GetLevel() + 1)
3211 + " \\* MERGEFORMAT ";
3212 GetExport().OutputField(pField, ww::eSTYLEREF, sStr);
3213 bWriteExpand = false;
3214 }
3215 }
3216 break;
3217 case SwFieldIds::HiddenText:
3218 {
3219 OUString sExpand(pField->GetPar2());
3220 if (!sExpand.isEmpty())
3221 {
3222 HiddenField( *pField );
3223 }
3224 }
3225 break;
3226 case SwFieldIds::JumpEdit:
3227 bWriteExpand = PlaceholderField( pField );
3228 break;
3229 case SwFieldIds::Macro:
3230 {
3231 const OUString sStr = " MACROBUTTON"
3232 + pField->GetPar1().replaceFirst("StarOffice.Standard.Modul1.", " ")
3233 + " "
3234 + lcl_GetExpandedField(*pField);
3235 GetExport().OutputField( pField, ww::eMACROBUTTON, sStr );
3236 }
3237 break;
3238 case SwFieldIds::Table:
3239 {
3240 ww::eField eField = ww::eEquals;
3241 OUString aExpand = " =" + pField->GetFieldName().trim();
3242 GetExport().OutputField(pField, eField, aExpand);
3243 }
3244 break;
3245 case SwFieldIds::User:
3246 {
3247 ww::eField eField = ww::eDOCVARIABLE;
3248 OUString aExpand = FieldString(eField) + pField->GetPar1() + " ";
3249 GetExport().OutputField(pField, eField, aExpand);
3250 }
3251 break;
3252 default:
3253 bWriteExpand = true;
3254 break;
3255 }
3256
3257 if (bWriteExpand)
3258 WriteExpand( pField );
3259}
3260
3261void AttributeOutputBase::TextFlyContent( const SwFormatFlyCnt& rFlyContent )
3262{
3263 if ( auto pTextNd = dynamic_cast< const SwContentNode *>( GetExport().m_pOutFormatNode ) )
3264 {
3265 Point const origin;
3266 Point aLayPos = pTextNd->FindLayoutRect( false, &origin ).Pos();
3267
3268 SwPosition aPos( *pTextNd );
3269 ww8::Frame aFrame( *rFlyContent.GetFrameFormat(), aPos );
3270
3271 OutputFlyFrame_Impl( aFrame, aLayPos );
3272 }
3273}
3274
3275// TOXMarks are still missing
3276
3277// WW allows detailed settings for hyphenation only for the whole document.
3278// One could implement following mimic: The values of the style "Standard" will
3279// be set in the Document Properties ( DOP ) if they exist.
3280
3281// ACK. This suggestion fits exactly to our implementation of the import,
3282// therefore I'll implement that right now. (KHZ, 07/15/2000)
3283void WW8AttributeOutput::ParaHyphenZone( const SvxHyphenZoneItem& rHyphenZone )
3284{
3285 // sprmPFNoAutoHyph
3286 m_rWW8Export.InsUInt16( NS_sprm::PFNoAutoHyph::val );
3287
3288 m_rWW8Export.pO->push_back( rHyphenZone.IsHyphen() ? 0 : 1 );
3289}
3290
3291void WW8AttributeOutput::ParaScriptSpace( const SfxBoolItem& rScriptSpace )
3292{
3293 m_rWW8Export.InsUInt16( NS_sprm::PFAutoSpaceDE::val );
3294 m_rWW8Export.pO->push_back( rScriptSpace.GetValue() ? 1 : 0 );
3295}
3296
3297void WW8AttributeOutput::ParaHangingPunctuation( const SfxBoolItem& rItem )
3298{
3299 m_rWW8Export.InsUInt16( NS_sprm::PFOverflowPunct::val );
3300 m_rWW8Export.pO->push_back( rItem.GetValue() ? 1 : 0 );
3301}
3302
3303void WW8AttributeOutput::ParaForbiddenRules( const SfxBoolItem& rItem )
3304{
3305 m_rWW8Export.InsUInt16( NS_sprm::PFKinsoku::val );
3306 m_rWW8Export.pO->push_back( rItem.GetValue() ? 1 : 0 );
3307}
3308
3309void WW8AttributeOutput::ParaSnapToGrid( const SvxParaGridItem& rGrid )
3310{
3311 // sprmPFUsePgsuSettings
3312
3313 m_rWW8Export.InsUInt16( NS_sprm::PFUsePgsuSettings::val );
3314 m_rWW8Export.pO->push_back( rGrid.GetValue() ? 1 : 0 );
3315}
3316
3317void WW8AttributeOutput::ParaVerticalAlign( const SvxParaVertAlignItem& rAlign )
3318{
3319 // sprmPWAlignFont
3320
3321 m_rWW8Export.InsUInt16( NS_sprm::PWAlignFont::val );
3322
3323 SvxParaVertAlignItem::Align nAlign = rAlign.GetValue();
3324 sal_uInt16 nVal;
3325 switch ( nAlign )
3326 {
3327 case SvxParaVertAlignItem::Align::Baseline:
3328 nVal = 2;
3329 break;
3330 case SvxParaVertAlignItem::Align::Top:
3331 nVal = 0;
3332 break;
3333 case SvxParaVertAlignItem::Align::Center:
3334 nVal = 1;
3335 break;
3336 case SvxParaVertAlignItem::Align::Bottom:
3337 nVal = 3;
3338 break;
3339 case SvxParaVertAlignItem::Align::Automatic:
3340 nVal = 4;
3341 break;
3342 default:
3343 nVal = 4;
3344 OSL_FAIL( "Unknown vert alignment" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "3344" ": "), "%s", "Unknown vert alignment"); } } while
(false)
;
3345 break;
3346 }
3347 m_rWW8Export.InsUInt16( nVal );
3348}
3349
3350// NoHyphen: I didn't find an equal in the SW UI and WW UI
3351
3352// RefMark, NoLineBreakHere are still missing
3353
3354void WW8Export::WriteFootnoteBegin( const SwFormatFootnote& rFootnote, ww::bytes* pOutArr )
3355{
3356 ww::bytes aAttrArr;
3357 const bool bAutoNum = rFootnote.GetNumStr().isEmpty();
3358 if( bAutoNum )
3359 {
3360 static const sal_uInt8 aSpec[] =
3361 {
3362 0x03, 0x6a, 0, 0, 0, 0, // sprmCObjLocation
3363 0x55, 0x08, 1 // sprmCFSpec
3364 };
3365
3366 aAttrArr.insert(aAttrArr.end(), aSpec, aSpec+sizeof(aSpec));
3367 }
3368
3369 // sprmCIstd
3370 const SwEndNoteInfo* pInfo;
3371 if( rFootnote.IsEndNote() )
3372 pInfo = &m_rDoc.GetEndNoteInfo();
3373 else
3374 pInfo = &m_rDoc.GetFootnoteInfo();
3375 const SwCharFormat* pCFormat = pOutArr
3376 ? pInfo->GetAnchorCharFormat( m_rDoc )
3377 : pInfo->GetCharFormat( m_rDoc );
3378 SwWW8Writer::InsUInt16( aAttrArr, NS_sprm::CIstd::val );
3379 SwWW8Writer::InsUInt16( aAttrArr, GetId( pCFormat ) );
3380
3381 // fSpec-Attribut true
3382 // For Auto-Number a special character must go
3383 // into the text and therefore a fSpec attribute
3384 m_pChpPlc->AppendFkpEntry( Strm().Tell() );
3385 if( bAutoNum )
3386 WriteChar( 0x02 ); // auto number character
3387 else
3388 // user numbering
3389 OutSwString(rFootnote.GetNumStr(), 0, rFootnote.GetNumStr().getLength());
3390
3391 if( pOutArr )
3392 {
3393 // insert at start of array, so the "hard" attribute overrule the
3394 // attributes of the character template
3395 pOutArr->insert( pOutArr->begin(), aAttrArr.begin(), aAttrArr.end() );
3396 }
3397 else
3398 {
3399 std::unique_ptr<ww::bytes> pOwnOutArr(new ww::bytes);
3400
3401 // insert at start of array, so the "hard" attribute overrule the
3402 // attributes of the character template
3403 pOwnOutArr->insert(pOwnOutArr->begin(), aAttrArr.begin(), aAttrArr.end());
3404
3405 // write for the ftn number in the content, the font of the anchor
3406 const SwTextFootnote* pTextFootnote = rFootnote.GetTextFootnote();
3407 if( pTextFootnote )
3408 {
3409 std::unique_ptr<ww::bytes> pOld = std::move(pO);
3410 pO = std::move(pOwnOutArr);
3411 SfxItemSet aSet( m_rDoc.GetAttrPool(), svl::Items<RES_CHRATR_FONT,
3412 RES_CHRATR_FONT>{} );
3413
3414 pCFormat = pInfo->GetCharFormat( m_rDoc );
3415
3416 pTextFootnote->GetTextNode().GetParaAttr(aSet,
3417 pTextFootnote->GetStart(), pTextFootnote->GetStart() + 1, true);
3418 if (aSet.Count())
3419 {
3420 m_pAttrOutput->OutputItem( aSet.Get( RES_CHRATR_FONT ) );
3421 }
3422 else
3423 {
3424 m_pAttrOutput->OutputItem( pCFormat->GetAttrSet().Get(RES_CHRATR_FONT) );
3425 }
3426 pOwnOutArr = std::move(pO);
3427 pO = std::move(pOld);
3428 }
3429 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pOwnOutArr->size(),
3430 pOwnOutArr->data() );
3431 }
3432}
3433
3434static bool lcl_IsAtTextEnd(const SwFormatFootnote& rFootnote)
3435{
3436 bool bRet = true;
3437 if( rFootnote.GetTextFootnote() )
3438 {
3439 sal_uInt16 nWh = rFootnote.IsEndNote() ? sal_uInt16(RES_END_AT_TXTEND)
3440 : sal_uInt16(RES_FTN_AT_TXTEND);
3441 const SwSectionNode* pSectNd = rFootnote.GetTextFootnote()->GetTextNode().
3442 FindSectionNode();
3443 while( pSectNd && FTNEND_ATPGORDOCEND ==
3444 static_cast<const SwFormatFootnoteEndAtTextEnd&>(pSectNd->GetSection().GetFormat()->
3445 GetFormatAttr( nWh)).GetValue() )
3446 pSectNd = pSectNd->StartOfSectionNode()->FindSectionNode();
3447
3448 if (!pSectNd)
3449 bRet = false; // the is ftn/end collected at Page- or Doc-End
3450 }
3451 return bRet;
3452}
3453
3454void AttributeOutputBase::TextFootnote( const SwFormatFootnote& rFootnote )
3455{
3456 sal_uInt16 nTyp;
3457 if ( rFootnote.IsEndNote() )
3458 {
3459 nTyp = REF_ENDNOTE;
3460 if ( GetExport().m_bEndAtTextEnd )
3461 GetExport().m_bEndAtTextEnd = lcl_IsAtTextEnd( rFootnote );
3462 }
3463 else
3464 {
3465 nTyp = REF_FOOTNOTE;
3466 if ( GetExport().m_bFootnoteAtTextEnd )
3467 GetExport().m_bFootnoteAtTextEnd = lcl_IsAtTextEnd( rFootnote );
3468 }
3469
3470 // if any reference to this footnote/endnote then insert an internal
3471 // Bookmark.
3472 OUString sBkmkNm;
3473 if ( GetExport().HasRefToFootOrEndnote( rFootnote.IsEndNote(), rFootnote.GetTextFootnote()->GetSeqRefNo()))
3474 {
3475 sBkmkNm = MSWordExportBase::GetBookmarkName( nTyp, nullptr,
3476 rFootnote.GetTextFootnote()->GetSeqRefNo() );
3477 GetExport().AppendBookmark( sBkmkNm );
3478 }
3479
3480 TextFootnote_Impl( rFootnote );
3481
3482 if ( !sBkmkNm.isEmpty() )
3483 GetExport().AppendBookmark( sBkmkNm ); // FIXME: Why is it added twice? Shouldn't this one go to WW8AttributeOutput::TextFootnote_Impl()?
3484}
3485
3486void WW8AttributeOutput::TextFootnote_Impl( const SwFormatFootnote& rFootnote )
3487{
3488 WW8_WrPlcFootnoteEdn* pFootnoteEnd;
3489 if ( rFootnote.IsEndNote() || GetExport().m_rDoc.GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER )
3490 pFootnoteEnd = m_rWW8Export.pEdn.get();
3491 else
3492 pFootnoteEnd = m_rWW8Export.pFootnote.get();
3493
3494 pFootnoteEnd->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), rFootnote );
3495 m_rWW8Export.WriteFootnoteBegin( rFootnote, m_rWW8Export.pO.get() );
3496}
3497
3498void WW8AttributeOutput::TextCharFormat( const SwFormatCharFormat& rCharFormat )
3499{
3500 if( rCharFormat.GetCharFormat() )
3501 {
3502 m_rWW8Export.InsUInt16( NS_sprm::CIstd::val );
3503
3504 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( rCharFormat.GetCharFormat() ) );
3505 }
3506}
3507
3508/*
3509 See ww8par6.cxx Read_DoubleLine for some more info
3510 */
3511void WW8AttributeOutput::CharTwoLines( const SvxTwoLinesItem& rTwoLines )
3512{
3513 // #i28331# - check that bOn is set
3514 if ( !rTwoLines.GetValue() )
3515 return;
3516
3517 m_rWW8Export.InsUInt16( NS_sprm::CFELayout::val );
3518 m_rWW8Export.pO->push_back( sal_uInt8(0x06) ); //len 6
3519 m_rWW8Export.pO->push_back( sal_uInt8(0x02) );
3520
3521 sal_Unicode cStart = rTwoLines.GetStartBracket();
3522 sal_Unicode cEnd = rTwoLines.GetEndBracket();
3523
3524 /*
3525 As per usual we have problems. We can have separate left and right brackets
3526 in OOo, it doesn't appear that you can in word. Also in word there appear
3527 to only be a limited number of possibilities, we can use pretty much
3528 anything.
3529
3530 So if we have none, we export none, if either bracket is set to a known
3531 word type we export both as that type (with the bracket winning out in
3532 the case of a conflict simply being the order of test here.
3533
3534 Upshot being a documented created in word will be reexported with no
3535 ill effects.
3536 */
3537
3538 sal_uInt16 nType;
3539 if (!cStart && !cEnd)
3540 nType = 0;
3541 else if ((cStart == '{') || (cEnd == '}'))
3542 nType = 4;
3543 else if ((cStart == '<') || (cEnd == '>'))
3544 nType = 3;
3545 else if ((cStart == '[') || (cEnd == ']'))
3546 nType = 2;
3547 else
3548 nType = 1;
3549 m_rWW8Export.InsUInt16( nType );
3550 static const sal_uInt8 aZeroArr[ 3 ] = { 0, 0, 0 };
3551 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aZeroArr, aZeroArr+3);
3552}
3553
3554void AttributeOutputBase::ParaNumRule( const SwNumRuleItem& rNumRule )
3555{
3556 const SwTextNode* pTextNd = nullptr;
3557 if (rNumRule.GetValue().isEmpty())
3558 {
3559 ParaNumRule_Impl(pTextNd, 0, 0);
3560 return;
3561 }
3562 const SwNumRule* pRule = GetExport().m_rDoc.FindNumRulePtr(
3563 rNumRule.GetValue() );
3564 if (!pRule)
3565 return;
3566
3567 sal_uInt16 nNumId = GetExport().GetNumberingId(*pRule) + 1;
3568 sal_uInt8 nLvl = 0;
3569
3570 if (!GetExport().m_pOutFormatNode)
3571 {
3572 ParaNumRule_Impl(pTextNd, nLvl, nNumId);
3573 return;
3574 }
3575
3576 if ( dynamic_cast< const SwContentNode *>( GetExport().m_pOutFormatNode ) != nullptr )
3577 {
3578 pTextNd = static_cast<const SwTextNode*>(GetExport().m_pOutFormatNode);
3579
3580 if( pTextNd->IsCountedInList())
3581 {
3582 int nLevel = pTextNd->GetActualListLevel();
3583
3584 if (nLevel < 0)
3585 nLevel = 0;
3586
3587 if (nLevel >= MAXLEVEL)
3588 nLevel = MAXLEVEL - 1;
3589
3590 nLvl = static_cast< sal_uInt8 >(nLevel);
3591
3592 if (GetExport().GetExportFormat() == MSWordExportBase::DOCX) // FIXME
3593 {
3594 // tdf#95848 find the abstract list definition
3595 OUString const listId(pTextNd->GetListId());
3596 if (!listId.isEmpty()
3597 && (listId != pRule->GetDefaultListId() // default list id uses the 1:1 mapping
3598 || pTextNd->IsListRestart()) // or restarting previous list
3599 )
3600 {
3601 SwList const*const pList(
3602 GetExport().m_rDoc.getIDocumentListsAccess().getListByName(listId));
3603 if (pList)
3604 {
3605 SwNumRule const*const pAbstractRule(
3606 GetExport().m_rDoc.FindNumRulePtr(
3607 pList->GetDefaultListStyleName()));
3608 assert(pAbstractRule)(static_cast <bool> (pAbstractRule) ? void (0) : __assert_fail
("pAbstractRule", "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 3608, __extension__ __PRETTY_FUNCTION__))
;
3609 if (pAbstractRule == pRule && !pTextNd->IsListRestart())
3610 {
3611 // different list, but no override
3612 nNumId = GetExport().DuplicateAbsNum(listId, *pAbstractRule) + 1;
3613 }
3614 else
3615 {
3616 nNumId = GetExport().OverrideNumRule(
3617 *pRule, listId, *pAbstractRule) + 1;
3618
3619 if (pTextNd->IsListRestart())
3620 {
3621 // For restarted lists we should also keep value for
3622 // future w:lvlOverride / w:startOverride
3623 GetExport().AddListLevelOverride(nNumId-1, pTextNd->GetActualListLevel(),
3624 pTextNd->GetActualListStartValue());
3625 }
3626 }
3627 }
3628 }
3629 }
3630 }
3631 else
3632 {
3633 // #i44815# adjust numbering for numbered paragraphs
3634 // without number (NO_NUMLEVEL). These paragraphs
3635 // will receive a list id 0, which WW interprets as
3636 // 'no number'.
3637 nNumId = 0;
3638 }
3639 }
3640 else if ( dynamic_cast< const SwTextFormatColl *>( GetExport().m_pOutFormatNode ) != nullptr )
3641 {
3642 const SwTextFormatColl* pC = static_cast<const SwTextFormatColl*>(GetExport().m_pOutFormatNode);
3643 if ( pC && pC->IsAssignedToListLevelOfOutlineStyle() )
3644 nLvl = static_cast< sal_uInt8 >( pC->GetAssignedOutlineStyleLevel() );
3645 }
3646
3647 if ( nLvl >= WW8ListManager::nMaxLevel )
3648 nLvl = WW8ListManager::nMaxLevel - 1;
3649
3650 ParaNumRule_Impl( pTextNd, nLvl, nNumId);
3651}
3652
3653void WW8AttributeOutput::ParaNumRule_Impl(const SwTextNode* /*pTextNd*/,
3654 sal_Int32 const nLvl, sal_Int32 const nNumId)
3655{
3656 if (USHRT_MAX(32767 *2 +1) == nNumId)
3657 return;
3658
3659 // write sprmPIlvl and sprmPIlfo
3660 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlvl::val );
3661 m_rWW8Export.pO->push_back( ::sal::static_int_cast<sal_uInt8>(nLvl) );
3662 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlfo::val );
3663 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, ::sal::static_int_cast<sal_uInt16>(nNumId) );
3664}
3665
3666/* File FRMATR.HXX */
3667
3668void WW8AttributeOutput::FormatFrameSize( const SwFormatFrameSize& rSize )
3669{
3670 if( m_rWW8Export.m_bOutFlyFrameAttrs ) // Flys
3671 {
3672 if( m_rWW8Export.m_bOutGrf )
3673 return; // Fly around graphic -> Auto-size
3674
3675 //???? What about percentages ???
3676 if ( rSize.GetWidth() && rSize.GetWidthSizeType() == SwFrameSize::Fixed)
3677 {
3678 //"sprmPDxaWidth"
3679 m_rWW8Export.InsUInt16( NS_sprm::PDxaWidth::val );
3680 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rSize.GetWidth()) );
3681 }
3682
3683 if ( rSize.GetHeight() )
3684 {
3685 // sprmPWHeightAbs
3686 m_rWW8Export.InsUInt16( NS_sprm::PWHeightAbs::val );
3687
3688 sal_uInt16 nH = 0;
3689 switch ( rSize.GetHeightSizeType() )
3690 {
3691 case SwFrameSize::Variable: break;
3692 case SwFrameSize::Fixed: nH = static_cast<sal_uInt16>(rSize.GetHeight()) & 0x7fff; break;
3693 default: nH = static_cast<sal_uInt16>(rSize.GetHeight()) | 0x8000; break;
3694 }
3695 m_rWW8Export.InsUInt16( nH );
3696 }
3697 }
3698 else if( m_rWW8Export.m_bOutPageDescs ) // PageDesc : width + height
3699 {
3700 if( m_rWW8Export.m_pCurrentPageDesc->GetLandscape() )
3701 {
3702 /*sprmSBOrientation*/
3703 m_rWW8Export.InsUInt16( NS_sprm::SBOrientation::val );
3704 m_rWW8Export.pO->push_back( 2 );
3705 }
3706
3707 /*sprmSXaPage*/
3708 m_rWW8Export.InsUInt16( NS_sprm::SXaPage::val );
3709 m_rWW8Export.InsUInt16(
3710 msword_cast<sal_uInt16>(SvxPaperInfo::GetSloppyPaperDimension(rSize.GetWidth())));
3711
3712 /*sprmSYaPage*/
3713 m_rWW8Export.InsUInt16( NS_sprm::SYaPage::val );
3714 m_rWW8Export.InsUInt16(
3715 msword_cast<sal_uInt16>(SvxPaperInfo::GetSloppyPaperDimension(rSize.GetHeight())));
3716 }
3717}
3718
3719// FillOrder is still missing
3720
3721/**
3722 * ReplaceCr() is used for Pagebreaks and Pagedescs. An already written CR
3723 * will be replaced by a break character. Replace must be called right after
3724 * the writing of CR.
3725 *
3726 * @return FilePos + 1 of the replaced CR or 0 if nothing was replaced.
3727 */
3728sal_uLong WW8Export::ReplaceCr( sal_uInt8 nChar )
3729{
3730 OSL_ENSURE( nChar, "replaced with 0 crashes WW97/95" )do { if (true && (!(nChar))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "3730" ": "), "%s", "replaced with 0 crashes WW97/95"); }
} while (false)
;
3731
3732 bool bReplaced = false;
3733 SvStream& rStrm = Strm();
3734 sal_uLong nRetPos = 0, nPos = rStrm.Tell();
3735 //If there is at least two characters already output
3736 if (nPos - 2 >= o3tl::make_unsigned(pFib->m_fcMin))
3737 {
3738 sal_uInt16 nUCode=0;
3739
3740 rStrm.SeekRel(-2);
3741 rStrm.ReadUInt16( nUCode );
3742 //If the last char was a cr
3743 if (nUCode == 0x0d) // CR ?
3744 {
3745 if ((nChar == 0x0c) &&
3746 (nPos - 4 >= o3tl::make_unsigned(pFib->m_fcMin)))
3747 {
3748 rStrm.SeekRel(-4);
3749 rStrm.ReadUInt16( nUCode );
3750 }
3751 else
3752 {
3753 rStrm.SeekRel(-2);
3754 nUCode = 0x0;
3755 }
3756 //And the para is not of len 0, then replace this cr with the mark
3757 //#120140# If there is a cr before a column break, need replace the cr. So remove the "nChar==0x0e" check.
3758 if( nUCode == 0x0d )
3759 bReplaced = false;
3760 else
3761 {
3762 bReplaced = true;
3763 WriteChar(nChar);
3764 nRetPos = nPos;
3765 }
3766 }
3767 else if ((nUCode == 0x0c) && (nChar == 0x0e))
3768 {
3769 // a column break after a section has no effect in writer
3770 bReplaced = true;
3771 }
3772 rStrm.Seek( nPos );
3773 }
3774 else
3775 bReplaced = true;
3776
3777 if (!bReplaced)
3778 {
3779 // then write as normal char
3780 WriteChar(nChar);
3781 m_pPiece->SetParaBreak();
3782 m_pPapPlc->AppendFkpEntry(rStrm.Tell());
3783 m_pChpPlc->AppendFkpEntry(rStrm.Tell());
3784 nRetPos = rStrm.Tell();
3785 }
3786 return nRetPos;
3787}
3788
3789void WW8AttributeOutput::TableRowEnd(sal_uInt32 nDepth)
3790{
3791 if ( nDepth == 1 )
3792 m_rWW8Export.WriteChar( 0x07 );
3793 else if ( nDepth > 1 )
3794 m_rWW8Export.WriteChar( 0x0d );
3795
3796 //Technically in a word document this is a different value for a row ends
3797 //that are not row ends directly after a cell with a graphic. But it
3798 //doesn't seem to make a difference
3799 //pMagicTable->Append(Fc2Cp(Strm().Tell()),0x1B6);
3800}
3801
3802void AttributeOutputBase::FormatPageDescription( const SwFormatPageDesc& rPageDesc )
3803{
3804 if ( GetExport().m_bStyDef && dynamic_cast< const SwTextFormatColl *>( GetExport().m_pOutFormatNode ) )
3805 {
3806 const SwTextFormatColl* pC = static_cast<const SwTextFormatColl*>(GetExport().m_pOutFormatNode);
3807 if ( (SfxItemState::SET != pC->GetItemState( RES_BREAK, false ) ) && rPageDesc.KnowsPageDesc() )
3808 FormatBreak( SvxFormatBreakItem( SvxBreak::PageBefore, RES_BREAK ) );
3809 }
3810}
3811
3812void WW8AttributeOutput::PageBreakBefore( bool bBreak )
3813{
3814 // sprmPPageBreakBefore/sprmPFPageBreakBefore
3815 m_rWW8Export.InsUInt16( NS_sprm::PFPageBreakBefore::val );
3816
3817 m_rWW8Export.pO->push_back( bBreak ? 1 : 0 );
3818}
3819
3820/**
3821 * breaks write nothing in the output field rWrt.pO,
3822 * but only in the text stream (requirement so they can
3823 * be called from Out_Break...)
3824 */
3825void AttributeOutputBase::FormatBreak( const SvxFormatBreakItem& rBreak )
3826{
3827 if ( GetExport().m_bStyDef )
3828 {
3829 switch ( rBreak.GetBreak() )
3830 {
3831 case SvxBreak::NONE:
3832 case SvxBreak::PageBefore:
3833 case SvxBreak::PageBoth:
3834 PageBreakBefore( rBreak.GetValue() != SvxBreak::NONE );
3835 break;
3836 default:
3837 break;
3838 }
3839 }
3840 else if ( !GetExport().m_pParentFrame )
3841 {
3842 sal_uInt8 nC = 0;
3843 bool bBefore = false;
3844 // #i76300# - Note: Can only be <true>, if <bBefore> equals <false>.
3845 bool bCheckForFollowPageDesc = false;
3846
3847 switch ( rBreak.GetBreak() )
3848 {
3849 case SvxBreak::NONE: // disabled
3850 if ( !GetExport().m_bBreakBefore )
3851 PageBreakBefore( false );
3852 return;
3853
3854 case SvxBreak::ColumnBefore: // ColumnBreak
3855 bBefore = true;
3856 [[fallthrough]];
3857 case SvxBreak::ColumnAfter:
3858 case SvxBreak::ColumnBoth:
3859 if ( GetExport().m_rDoc.getIDocumentSettingAccess().get( DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK )
3860 || GetExport().Sections().CurrentNumberOfColumns( GetExport().m_rDoc ) > 1 )
3861 {
3862 nC = msword::ColumnBreak;
3863 }
3864 break;
3865
3866 case SvxBreak::PageBefore: // PageBreak
3867 // From now on(fix for #i77900#) we prefer to save a page break
3868 // as paragraph attribute (if the exporter is OK with that),
3869 // this has to be done after the export of the paragraph ( =>
3870 // !GetExport().bBreakBefore )
3871 if (GetExport().PreferPageBreakBefore())
3872 {
3873 if (!GetExport().m_bBreakBefore)
3874 PageBreakBefore(true);
3875 }
3876 else
3877 {
3878 bBefore = true;
3879 nC = msword::PageBreak;
3880 }
3881 break;
3882 case SvxBreak::PageAfter:
3883 case SvxBreak::PageBoth:
3884 nC = msword::PageBreak;
3885 // #i76300# - check for follow page description,
3886 // if current writing attributes of a paragraph.
3887 if ( dynamic_cast< const SwTextNode* >( GetExport().m_pOutFormatNode ) &&
3888 GetExport().GetCurItemSet() )
3889 {
3890 bCheckForFollowPageDesc = true;
3891 }
3892 break;
3893
3894 default:
3895 break;
3896 }
3897
3898 if ( ( bBefore == GetExport().m_bBreakBefore ) && nC )
3899 {
3900 // #i76300#
3901 bool bFollowPageDescWritten = false;
3902 if ( bCheckForFollowPageDesc )
3903 {
3904 bFollowPageDescWritten =
3905 GetExport().OutputFollowPageDesc( GetExport().GetCurItemSet(),
3906 dynamic_cast<const SwTextNode*>( GetExport().m_pOutFormatNode ) );
3907 }
3908 if ( !bFollowPageDescWritten )
3909 {
3910 SectionBreak(nC, !bBefore);
3911 }
3912 }
3913 }
3914}
3915
3916void WW8AttributeOutput::SectionBreak( sal_uInt8 nC, bool /*bBreakAfter*/, const WW8_SepInfo* /*pSectionInfo*/ )
3917{
3918 m_rWW8Export.ReplaceCr( nC );
3919}
3920
3921sal_uInt32 AttributeOutputBase::GridCharacterPitch( const SwTextGridItem& rGrid ) const
3922{
3923 MSWordStyles * pStyles = GetExport().m_pStyles.get();
3924 const SwFormat * pSwFormat = pStyles->GetSwFormat(0);
3925
3926 sal_uInt32 nPageCharSize = 0;
3927
3928 if (pSwFormat != nullptr)
3929 {
3930 nPageCharSize = ItemGet<SvxFontHeightItem>
3931 (*pSwFormat, RES_CHRATR_FONTSIZE).GetHeight();
3932 }
3933 sal_uInt16 nPitch = rGrid.IsSquaredMode() ? rGrid.GetBaseHeight() :
3934 rGrid.GetBaseWidth( );
3935
3936 sal_Int32 nCharWidth = nPitch - nPageCharSize;
3937 sal_Int32 nFraction = nCharWidth % 20;
3938 if ( nCharWidth < 0 )
3939 nFraction = 20 + nFraction;
3940 nFraction = ( nFraction * 0xFFF ) / 20;
3941 nFraction = ( nFraction & 0x00000FFF );
3942
3943 sal_Int32 nMain = nCharWidth / 20;
3944 if ( nCharWidth < 0 )
3945 nMain -= 1;
3946 nMain = nMain * 0x1000;
3947 nMain = ( nMain & 0xFFFFF000 );
3948
3949 return sal_uInt32( nFraction + nMain );
3950}
3951
3952void WW8AttributeOutput::FormatTextGrid( const SwTextGridItem& rGrid )
3953{
3954 if (!m_rWW8Export.m_bOutPageDescs)
3955 return;
3956
3957 sal_uInt16 nGridType = 0;
3958 switch ( rGrid.GetGridType() )
3959 {
3960 default:
3961 OSL_FAIL("Unknown grid type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "3961" ": "), "%s", "Unknown grid type"); } } while (false
)
;
3962 [[fallthrough]];
3963 case GRID_NONE:
3964 nGridType = 0;
3965 break;
3966 case GRID_LINES_ONLY:
3967 nGridType = 2;
3968 break;
3969 case GRID_LINES_CHARS:
3970 if ( rGrid.IsSnapToChars() )
3971 nGridType = 3;
3972 else
3973 nGridType = 1;
3974 break;
3975 }
3976 m_rWW8Export.InsUInt16( NS_sprm::SClm::val );
3977 m_rWW8Export.InsUInt16( nGridType );
3978
3979 sal_uInt16 nHeight = rGrid.GetBaseHeight() + rGrid.GetRubyHeight();
3980 m_rWW8Export.InsUInt16( NS_sprm::SDyaLinePitch::val );
3981 m_rWW8Export.InsUInt16( nHeight );
3982
3983 m_rWW8Export.InsUInt16( NS_sprm::SDxtCharSpace::val );
3984 m_rWW8Export.InsUInt32( GridCharacterPitch( rGrid ) );
3985}
3986
3987void WW8AttributeOutput::FormatPaperBin( const SvxPaperBinItem& rPaperBin )
3988{
3989 if ( !m_rWW8Export.m_bOutPageDescs )
3990 return;
3991
3992 sal_uInt16 nVal;
3993 switch ( rPaperBin.GetValue() )
3994 {
3995 case 0: nVal = 15; break; // Automatically select
3996 case 1: nVal = 1; break; // Upper paper tray
3997 case 2: nVal = 4; break; // Manual paper feed
3998 default: nVal = 0; break;
3999 }
4000
4001 if ( nVal )
4002 {
4003 m_rWW8Export.InsUInt16( m_rWW8Export.m_bOutFirstPage
4004 ? NS_sprm::SDmBinFirst::val : NS_sprm::SDmBinOther::val );
4005
4006 m_rWW8Export.InsUInt16( nVal );
4007 }
4008}
4009
4010void WW8AttributeOutput::FormatLRSpace( const SvxLRSpaceItem& rLR )
4011{
4012 // Flys are still missing ( see RTF )
4013
4014 if ( m_rWW8Export.m_bOutFlyFrameAttrs ) // Flys
4015 {
4016 // sprmPDxaFromText10
4017 m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText10 );
4018 // use average, since WW only knows one value
4019 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>( ( rLR.GetLeft() + rLR.GetRight() ) / 2 ) );
4020 }
4021 else if ( m_rWW8Export.m_bOutPageDescs ) // PageDescs
4022 {
4023 m_pageMargins.nLeft = 0;
4024 m_pageMargins.nRight = 0;
4025
4026 if ( auto pBoxItem = static_cast<const SvxBoxItem*>(m_rWW8Export.HasItem( RES_BOX )) )
4027 {
4028 m_pageMargins.nLeft = pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/true );
4029 m_pageMargins.nRight = pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/true );
4030 }
4031
4032 m_pageMargins.nLeft += sal::static_int_cast<sal_uInt16>(rLR.GetLeft());
4033 m_pageMargins.nRight += sal::static_int_cast<sal_uInt16>(rLR.GetRight());
4034
4035 // sprmSDxaLeft
4036 m_rWW8Export.InsUInt16( NS_sprm::SDxaLeft::val );
4037 m_rWW8Export.InsUInt16( m_pageMargins.nLeft );
4038
4039 // sprmSDxaRight
4040 m_rWW8Export.InsUInt16( NS_sprm::SDxaRight::val );
4041 m_rWW8Export.InsUInt16( m_pageMargins.nRight );
4042 }
4043 else
4044 { // normal paragraphs
4045 // sprmPDxaLeft
4046 m_rWW8Export.InsUInt16( 0x845E ); //asian version ?
4047 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLR.GetTextLeft()) );
4048
4049 // sprmPDxaRight
4050 m_rWW8Export.InsUInt16( 0x845D ); //asian version ?
4051 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLR.GetRight()) );
4052
4053 // sprmPDxaLeft1
4054 m_rWW8Export.InsUInt16( 0x8460 ); //asian version ?
4055 m_rWW8Export.InsUInt16( rLR.GetTextFirstLineOffset() );
4056 }
4057}
4058
4059void WW8AttributeOutput::FormatULSpace( const SvxULSpaceItem& rUL )
4060{
4061 // Flys are still missing ( see RTF )
4062
4063 if ( m_rWW8Export.m_bOutFlyFrameAttrs ) // Flys
4064 {
4065 // sprmPDyaFromText
4066 m_rWW8Export.InsUInt16( NS_sprm::PDyaFromText::val );
4067 // use average, since WW only knows one value
4068 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>( ( rUL.GetUpper() + rUL.GetLower() ) / 2 ) );
4069 }
4070 else if ( m_rWW8Export.m_bOutPageDescs ) // Page-UL
4071 {
4072 OSL_ENSURE( m_rWW8Export.GetCurItemSet(), "Impossible" )do { if (true && (!(m_rWW8Export.GetCurItemSet()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4072" ": "), "%s", "Impossible"); } } while (false)
;
4073 if ( !m_rWW8Export.GetCurItemSet() )
4074 return;
4075
4076 HdFtDistanceGlue aDistances( *m_rWW8Export.GetCurItemSet() );
4077
4078 if ( aDistances.HasHeader() )
4079 {
4080 //sprmSDyaHdrTop
4081 m_rWW8Export.InsUInt16( NS_sprm::SDyaHdrTop::val );
4082 m_rWW8Export.InsUInt16( aDistances.dyaHdrTop );
4083 }
4084
4085 // sprmSDyaTop
4086 m_rWW8Export.InsUInt16( NS_sprm::SDyaTop::val );
4087 m_rWW8Export.InsUInt16( aDistances.dyaTop );
4088 m_pageMargins.nTop = aDistances.dyaTop;
4089
4090 if ( aDistances.HasFooter() )
4091 {
4092 //sprmSDyaHdrBottom
4093 m_rWW8Export.InsUInt16( NS_sprm::SDyaHdrBottom::val );
4094 m_rWW8Export.InsUInt16( aDistances.dyaHdrBottom );
4095 }
4096
4097 //sprmSDyaBottom
4098 m_rWW8Export.InsUInt16( NS_sprm::SDyaBottom::val );
4099 m_rWW8Export.InsUInt16( aDistances.dyaBottom );
4100 m_pageMargins.nBottom = aDistances.dyaBottom;
4101 }
4102 else
4103 {
4104 // sprmPDyaBefore
4105 m_rWW8Export.InsUInt16( NS_sprm::PDyaBefore::val );
4106 m_rWW8Export.InsUInt16( rUL.GetUpper() );
4107 // sprmPDyaAfter
4108 m_rWW8Export.InsUInt16( NS_sprm::PDyaAfter::val );
4109 m_rWW8Export.InsUInt16( rUL.GetLower() );
4110 // sprmPFContextualSpacing
4111 if (rUL.GetContext())
4112 {
4113 m_rWW8Export.InsUInt16(NS_sprm::PFContextualSpacing::val);
4114 m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(rUL.GetContext()) );
4115 }
4116 }
4117}
4118
4119// print, opaque, protect are still missing
4120
4121void WW8AttributeOutput::FormatSurround( const SwFormatSurround& rSurround )
4122{
4123 if ( m_rWW8Export.m_bOutFlyFrameAttrs )
4124 {
4125 m_rWW8Export.InsUInt16( NS_sprm::PWr::val );
4126
4127 m_rWW8Export.pO->push_back(
4128 ( css::text::WrapTextMode_NONE != rSurround.GetSurround() ) ? 2 : 1 );
4129 }
4130}
4131
4132void WW8AttributeOutput::FormatVertOrientation( const SwFormatVertOrient& rFlyVert )
4133{
4134
4135 //!!!! anchor type and corresponding borders are still missing
4136 if ( !m_rWW8Export.m_bOutFlyFrameAttrs )
4137 return;
4138
4139 short nPos;
4140 switch( rFlyVert.GetVertOrient() )
4141 {
4142 case text::VertOrientation::NONE:
4143 nPos = static_cast<short>(rFlyVert.GetPos());
4144 break;
4145 case text::VertOrientation::CENTER:
4146 case text::VertOrientation::LINE_CENTER:
4147 nPos = -8;
4148 break;
4149 case text::VertOrientation::BOTTOM:
4150 case text::VertOrientation::LINE_BOTTOM:
4151 nPos = -12;
4152 break;
4153 case text::VertOrientation::TOP:
4154 case text::VertOrientation::LINE_TOP:
4155 default:
4156 nPos = -4;
4157 break;
4158 }
4159
4160 // sprmPDyaAbs
4161 m_rWW8Export.InsUInt16( NS_sprm::PDyaAbs::val );
4162 m_rWW8Export.InsUInt16( nPos );
4163}
4164
4165void WW8AttributeOutput::FormatHorizOrientation( const SwFormatHoriOrient& rFlyHori )
4166{
4167 if ( !m_rWW8Export.m_pParentFrame )
4168 {
4169 OSL_ENSURE( m_rWW8Export.m_pParentFrame, "HoriOrient without mpParentFrame !!" )do { if (true && (!(m_rWW8Export.m_pParentFrame))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4169" ": "), "%s", "HoriOrient without mpParentFrame !!"
); } } while (false)
;
4170 return;
4171 }
4172
4173 //!!!! anchor type and corresponding borders are still missing
4174 if ( !m_rWW8Export.m_bOutFlyFrameAttrs )
4175 return;
4176
4177 short nPos;
4178 switch( rFlyHori.GetHoriOrient() )
4179 {
4180 case text::HoriOrientation::NONE:
4181 nPos = static_cast<short>(rFlyHori.GetPos());
4182 if( !nPos )
4183 nPos = 1; // WW: 0 is reserved
4184 break;
4185 case text::HoriOrientation::LEFT:
4186 nPos = rFlyHori.IsPosToggle() ? -12 : 0;
4187 break;
4188 case text::HoriOrientation::RIGHT:
4189 nPos = rFlyHori.IsPosToggle() ? -16 : -8;
4190 break;
4191 case text::HoriOrientation::CENTER:
4192 case text::HoriOrientation::FULL: // FULL only for tables
4193 default:
4194 nPos = -4;
4195 break;
4196 }
4197
4198 // sprmPDxaAbs
4199 m_rWW8Export.InsUInt16( NS_sprm::PDxaAbs::val );
4200 m_rWW8Export.InsUInt16( nPos );
4201}
4202
4203void WW8AttributeOutput::FormatAnchor( const SwFormatAnchor& rAnchor )
4204{
4205 OSL_ENSURE( m_rWW8Export.m_pParentFrame, "Anchor without mpParentFrame !!" )do { if (true && (!(m_rWW8Export.m_pParentFrame))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4205" ": "), "%s", "Anchor without mpParentFrame !!"); }
} while (false)
;
4206
4207 if ( !m_rWW8Export.m_bOutFlyFrameAttrs )
4208 return;
4209
4210 sal_uInt8 nP = 0;
4211 switch ( rAnchor.GetAnchorId() )
4212 {
4213 case RndStdIds::FLY_AT_PAGE:
4214 // vertical: page | horizontal: page
4215 nP |= (1 << 4) | (2 << 6);
4216 break;
4217 // in case of Fly as characters: set paragraph-bound!!!
4218 case RndStdIds::FLY_AT_FLY:
4219 case RndStdIds::FLY_AT_CHAR:
4220 case RndStdIds::FLY_AT_PARA:
4221 case RndStdIds::FLY_AS_CHAR:
4222 // vertical: page | horizontal: page
4223 nP |= (2 << 4) | (0 << 6);
4224 break;
4225 default:
4226 break;
4227 }
4228
4229 // sprmPPc
4230 m_rWW8Export.InsUInt16( NS_sprm::PPc::val );
4231 m_rWW8Export.pO->push_back( nP );
4232}
4233
4234void WW8AttributeOutput::FormatBackground( const SvxBrushItem& rBrush )
4235{
4236 // WW cannot have background in a section
4237 if ( m_rWW8Export.m_bOutPageDescs )
4238 return;
4239
4240 WW8_SHD aSHD;
4241 WW8Export::TransBrush( rBrush.GetColor(), aSHD );
4242
4243 m_rWW8Export.InsUInt16( NS_sprm::PShd80::val );
4244 m_rWW8Export.InsUInt16( aSHD.GetValue() );
4245
4246 m_rWW8Export.InsUInt16( NS_sprm::PShd::val );
4247 m_rWW8Export.pO->push_back( 10 ); //size of operand: MUST be 10
4248 m_rWW8Export.InsUInt32( 0xFF000000 ); //cvFore: Foreground BGR = cvAuto
4249 m_rWW8Export.InsUInt32( SuitableBGColor( rBrush.GetColor() ) ); //cvBack
4250 m_rWW8Export.InsUInt16( 0x0000 ); //iPat: specifies the pattern used for shading = clear/100% background
4251}
4252
4253void WW8AttributeOutput::FormatFillStyle( const XFillStyleItem& rFillStyle )
4254{
4255 // WW cannot have background in a section
4256 if ( m_rWW8Export.m_bOutPageDescs )
4257 return;
4258
4259 // see MSWordExportBase::OutputItemSet for how _SOLID is handled
4260 if ( rFillStyle.GetValue() != drawing::FillStyle_NONE )
4261 return;
4262
4263 //Shd80Nil
4264 m_rWW8Export.InsUInt16( NS_sprm::PShd80::val );
4265 m_rWW8Export.InsUInt16( 0xffff );
4266
4267 //cvAuto
4268 m_rWW8Export.InsUInt16( NS_sprm::PShd::val );
4269 m_rWW8Export.pO->push_back( 10 );
4270 m_rWW8Export.InsUInt32( 0xFF000000 );
4271 m_rWW8Export.InsUInt32( 0xFF000000 );
4272 m_rWW8Export.InsUInt16( 0x0000 );
4273}
4274
4275void WW8AttributeOutput::FormatFillGradient( const XFillGradientItem& /*rFillGradient*/ )
4276{
4277}
4278
4279WW8_BRCVer9 WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
4280 sal_uInt16 nDist, bool bShadow)
4281{
4282 sal_uInt32 nColBGR = 0;
4283 sal_uInt16 nWidth = ::editeng::ConvertBorderWidthToWord(
4284 rLine.GetBorderLineStyle(), rLine.GetWidth());
4285 sal_uInt8 brcType = 0;
4286
4287 if( nWidth ) // line ?
4288 {
4289 // BRC.brcType
4290 brcType = 0;
4291 // All the border types values are available on
4292 // http://msdn.microsoft.com/en-us/library/dd908142%28v=office.12%29.aspx
4293 switch (rLine.GetBorderLineStyle())
4294 {
4295 case SvxBorderLineStyle::SOLID:
4296 {
4297 if ( rLine.GetWidth( ) == DEF_LINE_WIDTH_01 )
4298 brcType = 5;
4299 else
4300 brcType = 1;
4301 }
4302 break;
4303 case SvxBorderLineStyle::DOTTED:
4304 brcType = 6;
4305 break;
4306 case SvxBorderLineStyle::DASHED:
4307 brcType = 7;
4308 break;
4309 case SvxBorderLineStyle::DOUBLE:
4310 case SvxBorderLineStyle::DOUBLE_THIN:
4311 brcType = 3;
4312 break;
4313 case SvxBorderLineStyle::THINTHICK_SMALLGAP:
4314 brcType = 11;
4315 break;
4316 case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
4317 brcType = 14;
4318 break;
4319 case SvxBorderLineStyle::THINTHICK_LARGEGAP:
4320 brcType = 17;
4321 break;
4322 case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
4323 brcType = 12;
4324 break;
4325 case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
4326 brcType = 15;
4327 break;
4328 case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
4329 brcType = 18;
4330 break;
4331 case SvxBorderLineStyle::EMBOSSED:
4332 brcType = 24;
4333 break;
4334 case SvxBorderLineStyle::ENGRAVED:
4335 brcType = 25;
4336 break;
4337 case SvxBorderLineStyle::OUTSET:
4338 brcType = 26;
4339 break;
4340 case SvxBorderLineStyle::INSET:
4341 brcType = 27;
4342 break;
4343 case SvxBorderLineStyle::FINE_DASHED:
4344 brcType = 22;
4345 break;
4346 case SvxBorderLineStyle::DASH_DOT:
4347 brcType = 8;
4348 break;
4349 case SvxBorderLineStyle::DASH_DOT_DOT:
4350 brcType = 9;
4351 break;
4352 default:
4353 break;
4354 }
4355
4356 // convert width from twips (1/20 pt) to eighths of a point
4357 nWidth = (( nWidth * 8 ) + 10 ) / 20;
4358 if( 0xff < nWidth )
4359 nWidth = 0xff;
4360
4361 if( 0 == nWidth ) // really thin line
4362 nWidth = 1; // don't omit
4363
4364 // BRC.cv
4365 nColBGR = wwUtility::RGBToBGR(rLine.GetColor().GetRGBColor());
4366 }
4367
4368 // BRC.dptSpace
4369 sal_uInt16 nLDist = nDist;
4370 nLDist /= 20; // unit of measurement: pt
4371 if( nLDist > 0x1f )
4372 nLDist = 0x1f;
4373
4374 return WW8_BRCVer9(nColBGR, sal_uInt8(nWidth), brcType, sal_uInt8(nLDist),
4375 bShadow, false);
4376}
4377
4378/**
4379 * Gets passed a WW8Bytes*, so the function also can be used for the table border.
4380 *
4381 * @param nSprmNo If nSprmNo == 0, then the opcode isn't outputted.
4382 * @param bShadow SHOULDN'T be set for table cells !
4383 */
4384void WW8Export::Out_BorderLine(ww::bytes& rO, const SvxBorderLine* pLine,
4385 sal_uInt16 nDist, sal_uInt16 nSprmNo, sal_uInt16 nSprmNoVer9, bool bShadow)
4386{
4387 OSL_ENSURE( ( nSprmNo == 0 ) ||do { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
4388 ( nSprmNo >= 38 && nSprmNo <= 41 ) ||do { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
4389 ( nSprmNo >= NS_sprm::PBrcTop80::valdo { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
4390 && nSprmNo <= NS_sprm::PBrcRight80::val ) ||do { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
4391 ( nSprmNo >= NS_sprm::SBrcTop80::valdo { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
4392 && nSprmNo <= NS_sprm::SBrcRight80::val ),do { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
4393 "Sprm for border out is of range" )do { if (true && (!(( nSprmNo == 0 ) || ( nSprmNo >=
38 && nSprmNo <= 41 ) || ( nSprmNo >= NS_sprm::
PBrcTop80::val && nSprmNo <= NS_sprm::PBrcRight80::
val ) || ( nSprmNo >= NS_sprm::SBrcTop80::val && nSprmNo
<= NS_sprm::SBrcRight80::val )))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4393" ": "), "%s", "Sprm for border out is of range"); }
} while (false)
;
4394
4395 WW8_BRCVer9 aBrcVer9;
4396 WW8_BRC aBrcVer8;
4397
4398 if( pLine && pLine->GetBorderLineStyle() != SvxBorderLineStyle::NONE )
4399 {
4400 aBrcVer9 = TranslateBorderLine( *pLine, nDist, bShadow );
4401 sal_uInt8 ico = msfilter::util::TransColToIco( msfilter::util::BGRToRGB(aBrcVer9.cv()) );
4402 aBrcVer8 = WW8_BRC( aBrcVer9.dptLineWidth(), aBrcVer9.brcType(), ico,
4403 aBrcVer9.dptSpace(), aBrcVer9.fShadow(), aBrcVer9.fFrame() );
4404 }
4405
4406 // WW97-SprmIds
4407 if ( nSprmNo != 0 )
4408 SwWW8Writer::InsUInt16( rO, nSprmNo );
4409
4410 rO.insert( rO.end(), aBrcVer8.aBits1, aBrcVer8.aBits2+2 );
4411
4412 if ( nSprmNoVer9 != 0 )
4413 {
4414 SwWW8Writer::InsUInt16( rO, nSprmNoVer9 );
4415 rO.push_back(sizeof(WW8_BRCVer9));
4416 rO.insert( rO.end(), aBrcVer9.aBits1, aBrcVer9.aBits2+4);
4417 }
4418}
4419
4420/**
4421 * is for all boxes except in tables. pO of the WW8Writer is used
4422 *
4423 * @param rBox
4424 * @param bShadow
4425 */
4426void WW8Export::Out_SwFormatBox(const SvxBoxItem& rBox, bool bShadow)
4427{
4428 static const SvxBoxItemLine aBorders[] =
4429 {
4430 SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
4431 };
4432 static const sal_uInt16 aPBrc[] =
4433 {
4434 // WW8 SPRMs
4435 NS_sprm::PBrcTop80::val, NS_sprm::PBrcLeft80::val,
4436 NS_sprm::PBrcBottom80::val, NS_sprm::PBrcRight80::val,
4437 // WW9 SPRMs
4438 NS_sprm::PBrcTop::val, NS_sprm::PBrcLeft::val,
4439 NS_sprm::PBrcBottom::val, NS_sprm::PBrcRight::val
4440 };
4441 static const sal_uInt16 aSBrc[] =
4442 {
4443 // WW8 SPRMs
4444 NS_sprm::SBrcTop80::val, NS_sprm::SBrcLeft80::val,
4445 NS_sprm::SBrcBottom80::val, NS_sprm::SBrcRight80::val,
4446 // WW9 SPRMs
4447 NS_sprm::SBrcTop::val, NS_sprm::SBrcLeft::val,
4448 NS_sprm::SBrcBottom::val, NS_sprm::SBrcRight::val
4449 };
4450
4451 const SvxBoxItemLine* pBrd = aBorders;
4452 for( sal_uInt16 i = 0; i < 4; ++i, ++pBrd )
4453 {
4454 const SvxBorderLine* pLn = rBox.GetLine( *pBrd );
4455
4456 sal_uInt16 nSprmNo, nSprmNoVer9 = 0;
4457 if (m_bOutPageDescs)
4458 {
4459 nSprmNo = aSBrc[i];
4460 nSprmNoVer9 = aSBrc[i+4];
4461 }
4462 else
4463 {
4464 nSprmNo = aPBrc[i];
4465 nSprmNoVer9 = aPBrc[i+4];
4466 }
4467
4468 Out_BorderLine( *pO, pLn, rBox.GetDistance( *pBrd ), nSprmNo,
4469 nSprmNoVer9, bShadow );
4470 }
4471}
4472
4473/**
4474 * FormatBox2() is for TC structures in tables. The Sprm opcode isn't written
4475 * because it is packed into the TC structure without opcode.
4476 * dxpSpace always becomes 0, because WW requires that in tables
4477 * ( table borders otherwise will fray )
4478 *
4479 * @param rO A WW8Bytes pointer is passed in as output parameter
4480 */
4481void WW8Export::Out_SwFormatTableBox( ww::bytes& rO, const SvxBoxItem * pBox )
4482{
4483 // possible and maybe better would be 0xffff
4484 static const SvxBoxItemLine aBorders[] =
4485 {
4486 SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
4487 };
4488 static const SvxBorderLine aBorderLine;
4489
4490 for(const SvxBoxItemLine & rBorder : aBorders)
4491 {
4492 const SvxBorderLine* pLn;
4493 if (pBox != nullptr)
4494 pLn = pBox->GetLine( rBorder );
4495 else
4496 pLn = & aBorderLine;
4497
4498 Out_BorderLine(rO, pLn, 0, 0, 0, false);
4499 }
4500}
4501
4502void WW8Export::Out_CellRangeBorders( const SvxBoxItem * pBox, sal_uInt8 nStart,
4503 sal_uInt8 nLimit )
4504{
4505 if ( !pBox )
4506 return;
4507
4508 static const SvxBoxItemLine aBorders[] =
4509 {
4510 SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
4511 };
4512
4513 for( int i = 0; i < 4; ++i )
4514 {
4515 const SvxBorderLine* pLn = pBox->GetLine( aBorders[i] );
4516 if (!pLn)
4517 continue;
4518
4519 InsUInt16( NS_sprm::TSetBrc::val );
4520 pO->push_back( 11 );
4521 pO->push_back( nStart );
4522 pO->push_back( nLimit );
4523 pO->push_back( 1<<i );
4524 WW8_BRCVer9 aBrcVer9 = TranslateBorderLine( *pLn, 0, false );
4525 pO->insert( pO->end(), aBrcVer9.aBits1, aBrcVer9.aBits2+4 );
4526 }
4527}
4528
4529void WW8AttributeOutput::FormatBox( const SvxBoxItem& rBox )
4530{
4531 // Fly around graphic -> here no border, because the
4532 // graphics header already has the border
4533 if ( m_rWW8Export.m_bOutGrf )
4534 return;
4535
4536 bool bShadow = false;
4537 const SfxPoolItem* pItem = m_rWW8Export.HasItem( RES_SHADOW );
4538 if ( pItem )
4539 {
4540 const SvxShadowItem* p = static_cast<const SvxShadowItem*>(pItem);
4541 bShadow = ( p->GetLocation() != SvxShadowLocation::NONE )
4542 && ( p->GetWidth() != 0 );
4543 }
4544
4545 SvxBoxItem aBox(rBox);
4546 if (m_rWW8Export.m_bOutPageDescs)
4547 {
4548 editeng::WordBorderDistances aDistances;
4549 editeng::BorderDistancesToWord(aBox, m_pageMargins, aDistances);
4550
4551 aBox.SetDistance(aDistances.nTop, SvxBoxItemLine::TOP);
4552 aBox.SetDistance(aDistances.nLeft, SvxBoxItemLine::LEFT);
4553 aBox.SetDistance(aDistances.nBottom, SvxBoxItemLine::BOTTOM);
4554 aBox.SetDistance(aDistances.nRight, SvxBoxItemLine::RIGHT);
4555
4556 m_bFromEdge = aDistances.bFromEdge;
4557 }
4558
4559 m_rWW8Export.Out_SwFormatBox( aBox, bShadow );
4560}
4561
4562SwTwips WW8Export::CurrentPageWidth(SwTwips &rLeft, SwTwips &rRight) const
4563{
4564 const SwFrameFormat* pFormat = m_pCurrentPageDesc ? &m_pCurrentPageDesc->GetMaster()
4565 : &m_rDoc.GetPageDesc(0).GetMaster();
4566
4567 const SvxLRSpaceItem& rLR = pFormat->GetLRSpace();
4568 SwTwips nPageSize = pFormat->GetFrameSize().GetWidth();
4569 rLeft = rLR.GetLeft();
4570 rRight = rLR.GetRight();
4571 return nPageSize;
4572}
4573
4574void WW8AttributeOutput::FormatColumns_Impl( sal_uInt16 nCols, const SwFormatCol & rCol, bool bEven, SwTwips nPageSize )
4575{
4576 // CColumns
4577 m_rWW8Export.InsUInt16( NS_sprm::SCcolumns::val );
4578 m_rWW8Export.InsUInt16( nCols - 1 );
4579
4580 // DxaColumns
4581 m_rWW8Export.InsUInt16( NS_sprm::SDxaColumns::val );
4582 m_rWW8Export.InsUInt16( rCol.GetGutterWidth( true ) );
4583
4584 // LBetween
4585 m_rWW8Export.InsUInt16( NS_sprm::SLBetween::val );
4586 m_rWW8Export.pO->push_back( COLADJ_NONE == rCol.GetLineAdj( )? 0 : 1 );
4587
4588 const SwColumns & rColumns = rCol.GetColumns( );
4589
4590 // FEvenlySpaced
4591 m_rWW8Export.InsUInt16( NS_sprm::SFEvenlySpaced::val );
4592 m_rWW8Export.pO->push_back( bEven ? 1 : 0 );
4593
4594 if ( bEven )
4595 return;
4596
4597 for ( sal_uInt16 n = 0; n < nCols; ++n )
4598 {
4599 //sprmSDxaColWidth
4600 m_rWW8Export.InsUInt16( NS_sprm::SDxaColWidth::val );
4601 m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(n) );
4602 m_rWW8Export.InsUInt16( rCol.
4603 CalcPrtColWidth( n,
4604 static_cast<sal_uInt16>(nPageSize) ) );
4605
4606 if ( n + 1 != nCols )
4607 {
4608 //sprmSDxaColSpacing
4609 m_rWW8Export.InsUInt16( NS_sprm::SDxaColSpacing::val );
4610 m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(n) );
4611 m_rWW8Export.InsUInt16( rColumns[n].GetRight( ) +
4612 rColumns[n + 1].GetLeft( ) );
4613 }
4614 }
4615}
4616
4617void AttributeOutputBase::FormatColumns( const SwFormatCol& rCol )
4618{
4619 const SwColumns& rColumns = rCol.GetColumns();
4620
4621 sal_uInt16 nCols = rColumns.size();
4622 if (1 >= nCols || GetExport( ).m_bOutFlyFrameAttrs)
4623 return;
4624
4625 // get the page width without borders !!
4626
4627 const SwFrameFormat* pFormat = GetExport( ).m_pCurrentPageDesc ? &GetExport( ).m_pCurrentPageDesc->GetMaster() : &const_cast<const SwDoc&>(GetExport().m_rDoc).GetPageDesc(0).GetMaster();
4628 const SvxFrameDirectionItem &frameDirection = pFormat->GetFrameDir();
4629 SwTwips nPageSize;
4630 if ( frameDirection.GetValue() == SvxFrameDirection::Vertical_RL_TB || frameDirection.GetValue() == SvxFrameDirection::Vertical_LR_TB )
4631 {
4632 const SvxULSpaceItem &rUL = pFormat->GetULSpace();
4633 nPageSize = pFormat->GetFrameSize().GetHeight();
4634 nPageSize -= rUL.GetUpper() + rUL.GetLower();
4635
4636 const SwFormatHeader *header = pFormat->GetAttrSet().GetItem(RES_HEADER);
4637 if ( header )
4638 {
4639 const SwFrameFormat *headerFormat = header->GetHeaderFormat();
4640 if (headerFormat)
4641 {
4642 nPageSize -= headerFormat->GetFrameSize().GetHeight();
4643 }
4644 }
4645 const SwFormatFooter *footer = pFormat->GetAttrSet().GetItem(RES_FOOTER);
4646 if ( footer )
4647 {
4648 const SwFrameFormat *footerFormat = footer->GetFooterFormat();
4649 if ( footerFormat )
4650 {
4651 nPageSize -= footerFormat->GetFrameSize().GetHeight();
4652 }
4653 }
4654 }
4655 else
4656 {
4657 const SvxLRSpaceItem &rLR = pFormat->GetLRSpace();
4658 nPageSize = pFormat->GetFrameSize().GetWidth();
4659 nPageSize -= rLR.GetLeft() + rLR.GetRight();
4660 //i120133: The Section width should consider page indent value.
4661 nPageSize -= rCol.GetAdjustValue();
4662
4663 }
4664
4665 // look if all columns are equal
4666 bool bEven = true;
4667 sal_uInt16 n;
4668 sal_uInt16 nColWidth = rCol.CalcPrtColWidth( 0, static_cast<sal_uInt16>(nPageSize) );
4669 for ( n = 1; n < nCols; n++ )
4670 {
4671 short nDiff = nColWidth -
4672 rCol.CalcPrtColWidth( n, static_cast<sal_uInt16>(nPageSize) );
4673
4674 if ( nDiff > 10 || nDiff < -10 ) // Tolerance: 10 tw
4675 {
4676 bEven = false;
4677 break;
4678 }
4679 }
4680
4681 FormatColumns_Impl( nCols, rCol, bEven, nPageSize );
4682}
4683
4684// "Paragraphs together"
4685void WW8AttributeOutput::FormatKeep( const SvxFormatKeepItem& rKeep )
4686{
4687 // sprmFKeepFollow
4688 m_rWW8Export.InsUInt16( NS_sprm::PFKeepFollow::val );
4689
4690 m_rWW8Export.pO->push_back( rKeep.GetValue() ? 1 : 0 );
4691}
4692
4693// exclude a paragraph from Line Numbering
4694void WW8AttributeOutput::FormatLineNumbering( const SwFormatLineNumber& rNumbering )
4695{
4696 // sprmPFNoLineNumb
4697 m_rWW8Export.InsUInt16( NS_sprm::PFNoLineNumb::val );
4698
4699 m_rWW8Export.pO->push_back( rNumbering.IsCount() ? 0 : 1 );
4700}
4701
4702/* File PARATR.HXX */
4703
4704void WW8AttributeOutput::ParaLineSpacing_Impl( short nSpace, short nMulti )
4705{
4706 // sprmPDyaLine
4707 m_rWW8Export.InsUInt16( NS_sprm::PDyaLine::val );
4708
4709 m_rWW8Export.InsUInt16( nSpace );
4710 m_rWW8Export.InsUInt16( nMulti );
4711}
4712
4713void AttributeOutputBase::ParaLineSpacing( const SvxLineSpacingItem& rSpacing )
4714{
4715 short nSpace = 240, nMulti = 0;
4716
4717 switch ( rSpacing.GetLineSpaceRule() )
4718 {
4719 default:
4720 break;
4721 case SvxLineSpaceRule::Fix: // Fix
4722 nSpace = -static_cast<short>(rSpacing.GetLineHeight());
4723 break;
4724 case SvxLineSpaceRule::Min: // At least
4725 nSpace = static_cast<short>(rSpacing.GetLineHeight());
4726 break;
4727 case SvxLineSpaceRule::Auto:
4728 {
4729 if( rSpacing.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) // Leading
4730 {
4731 // doesn't exist in WW - how do you get the MaxLineHeight?
4732 nSpace = rSpacing.GetInterLineSpace();
4733 sal_uInt16 nScript =
4734 i18n::ScriptType::LATIN;
4735 const SwAttrSet *pSet = nullptr;
4736 if ( auto pFormat = dynamic_cast< const SwFormat *>( GetExport().m_pOutFormatNode ) )
4737 {
4738 pSet = &pFormat->GetAttrSet();
4739 }
4740 else if ( auto pNd = dynamic_cast< const SwTextNode *>( GetExport().m_pOutFormatNode ) )
4741 {
4742 pSet = &pNd->GetSwAttrSet();
4743 nScript = g_pBreakIt->GetBreakIter()->getScriptType(pNd->GetText(), 0);
4744 }
4745 OSL_ENSURE( pSet, "No attrset for lineheight :-(" )do { if (true && (!(pSet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4745" ": "), "%s", "No attrset for lineheight :-("); } }
while (false)
;
4746 if ( pSet )
4747 {
4748 nSpace = nSpace + static_cast<short>( AttrSetToLineHeight( GetExport().m_rDoc.getIDocumentSettingAccess(),
4749 *pSet, *Application::GetDefaultDevice(), nScript ) );
4750 }
4751 }
4752 else // Proportional
4753 {
4754 if ( rSpacing.GetInterLineSpaceRule() != SvxInterLineSpaceRule::Off )
4755 nSpace = static_cast<short>( ( 240L * rSpacing.GetPropLineSpace() ) / 100L );
4756 nMulti = 1;
4757 }
4758 }
4759 break;
4760 }
4761 // if nSpace is negative, it is a fixed size in 1/20 of a point
4762 // if nSpace is positive and nMulti is 1, it is 1/240 of a single line height
4763 // otherwise, it is a minimum size in 1/20 of a point
4764 ParaLineSpacing_Impl( nSpace, nMulti );
4765}
4766
4767void WW8AttributeOutput::ParaAdjust( const SvxAdjustItem& rAdjust )
4768{
4769 // sprmPJc
4770 sal_uInt8 nAdj;
4771 sal_uInt8 nAdjBiDi;
4772 switch ( rAdjust.GetAdjust() )
4773 {
4774 case SvxAdjust::Left:
4775 nAdj = 0;
4776 nAdjBiDi = 2;
4777 break;
4778 case SvxAdjust::Right:
4779 nAdj = 2;
4780 nAdjBiDi = 0;
4781 break;
4782 case SvxAdjust::BlockLine:
4783 case SvxAdjust::Block:
4784 nAdj = nAdjBiDi = 3;
4785 break;
4786 case SvxAdjust::Center:
4787 nAdj = nAdjBiDi = 1;
4788 break;
4789 default:
4790 return; // not a supported Attribute
4791 }
4792
4793 m_rWW8Export.InsUInt16(NS_sprm::PJc80::val);
4794 m_rWW8Export.pO->push_back(nAdj);
4795
4796 /*
4797 Sadly for left to right paragraphs both these values are the same,
4798 for right to left paragraphs the bidi one is the reverse of the
4799 normal one.
4800 */
4801 m_rWW8Export.InsUInt16(NS_sprm::PJc::val); //bidi version ?
4802 bool bBiDiSwap = false;
4803 if (m_rWW8Export.m_pOutFormatNode)
4804 {
4805 SvxFrameDirection nDirection = SvxFrameDirection::Horizontal_LR_TB;
4806 if (dynamic_cast<const SwTextNode*>(m_rWW8Export.m_pOutFormatNode) != nullptr)
4807 {
4808 SwPosition aPos(*static_cast<const SwContentNode*>(m_rWW8Export.m_pOutFormatNode));
4809 nDirection = m_rWW8Export.m_rDoc.GetTextDirection(aPos);
4810 }
4811 else if (dynamic_cast<const SwTextFormatColl*>(m_rWW8Export.m_pOutFormatNode) != nullptr)
4812 {
4813 const SwTextFormatColl* pC =
4814 static_cast<const SwTextFormatColl*>(m_rWW8Export.m_pOutFormatNode);
4815 const SvxFrameDirectionItem &rItem =
4816 ItemGet<SvxFrameDirectionItem>(*pC, RES_FRAMEDIR);
4817 nDirection = rItem.GetValue();
4818 }
4819 if ( ( nDirection == SvxFrameDirection::Horizontal_RL_TB ) ||
4820 ( nDirection == SvxFrameDirection::Environment && AllSettings::GetLayoutRTL() ) )
4821 {
4822 bBiDiSwap = true;
4823 }
4824 }
4825
4826 if (bBiDiSwap)
4827 m_rWW8Export.pO->push_back(nAdjBiDi);
4828 else
4829 m_rWW8Export.pO->push_back(nAdj);
4830}
4831
4832void WW8AttributeOutput::FormatFrameDirection( const SvxFrameDirectionItem& rDirection )
4833{
4834 sal_uInt16 nTextFlow=0;
4835 bool bBiDi = false;
4836 SvxFrameDirection nDir = rDirection.GetValue();
4837
4838 if ( nDir == SvxFrameDirection::Environment )
4839 nDir = GetExport( ).GetDefaultFrameDirection( );
4840
4841
4842 switch ( nDir )
4843 {
4844 default:
4845 //Can't get an unknown type here
4846 OSL_FAIL("Unknown frame direction")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "4846" ": "), "%s", "Unknown frame direction"); } } while
(false)
;
4847 [[fallthrough]];
4848 case SvxFrameDirection::Horizontal_LR_TB:
4849 nTextFlow = 0;
4850 break;
4851 case SvxFrameDirection::Horizontal_RL_TB:
4852 nTextFlow = 0;
4853 bBiDi = true;
4854 break;
4855 case SvxFrameDirection::Vertical_LR_TB: //word doesn't have this
4856 case SvxFrameDirection::Vertical_RL_TB:
4857 nTextFlow = 1;
4858 break;
4859 }
4860
4861 if ( m_rWW8Export.m_bOutPageDescs )
4862 {
4863 m_rWW8Export.InsUInt16( NS_sprm::STextFlow::val );
4864 m_rWW8Export.InsUInt16( nTextFlow );
4865 m_rWW8Export.InsUInt16( NS_sprm::SFBiDi::val );
4866 m_rWW8Export.pO->push_back( bBiDi ? 1 : 0 );
4867 }
4868 else if ( !m_rWW8Export.m_bOutFlyFrameAttrs ) //paragraph/style
4869 {
4870 m_rWW8Export.InsUInt16( NS_sprm::PFBiDi::val );
4871 m_rWW8Export.pO->push_back( bBiDi ? 1 : 0 );
4872 }
4873}
4874
4875void WW8AttributeOutput::ParaGrabBag(const SfxGrabBagItem& /*rItem*/)
4876{
4877}
4878
4879void WW8AttributeOutput::CharGrabBag(const SfxGrabBagItem& /*rItem*/)
4880{
4881}
4882
4883void WW8AttributeOutput::ParaOutlineLevel(const SfxUInt16Item& /*rItem*/)
4884{
4885}
4886
4887// "Separate paragraphs"
4888void WW8AttributeOutput::ParaSplit( const SvxFormatSplitItem& rSplit )
4889{
4890 // sprmPFKeep
4891 m_rWW8Export.InsUInt16( NS_sprm::PFKeep::val );
4892 m_rWW8Export.pO->push_back( rSplit.GetValue() ? 0 : 1 );
4893}
4894
4895/**
4896 * Only convert the item "SvxWidowItem" and not the orphans, because
4897 * in WW only one attribute "paragraph control" exists for both and
4898 * in SW probably both or none is set by the user.
4899 */
4900void WW8AttributeOutput::ParaWidows( const SvxWidowsItem& rWidows )
4901{
4902 // sprmPFWidowControl
4903 m_rWW8Export.InsUInt16( NS_sprm::PFWidowControl::val );
4904 m_rWW8Export.pO->push_back( rWidows.GetValue() ? 1 : 0 );
4905}
4906
4907namespace {
4908
4909class SwWW8WrTabu
4910{
4911 std::unique_ptr<sal_uInt8[]> pDel; // DelArray
4912 std::unique_ptr<sal_uInt8[]> pAddPos; // AddPos-Array
4913 std::unique_ptr<sal_uInt8[]> pAddTyp; // AddTyp-Array
4914 sal_uInt16 nAdd; // number of tabs to be added
4915 sal_uInt16 nDel; // number of tabs to be deleted
4916
4917 SwWW8WrTabu(const SwWW8WrTabu&) = delete;
4918 SwWW8WrTabu& operator=(const SwWW8WrTabu&) = delete;
4919
4920public:
4921 SwWW8WrTabu(sal_uInt16 nDelMax, sal_uInt16 nAddMax);
4922
4923 void Add(const SvxTabStop &rTS, long nAdjustment);
4924 void Del(const SvxTabStop &rTS, long nAdjustment);
4925 void PutAll(WW8Export& rWW8Wrt);
4926};
4927
4928}
4929
4930SwWW8WrTabu::SwWW8WrTabu(sal_uInt16 nDelMax, sal_uInt16 nAddMax)
4931 : nAdd(0), nDel(0)
4932{
4933 if (nDelMax)
4934 pDel.reset( new sal_uInt8[nDelMax * 2] );
4935 pAddPos.reset( new sal_uInt8[nAddMax * 2] );
4936 pAddTyp.reset( new sal_uInt8[nAddMax] );
4937}
4938
4939/**
4940 * insert a tab in the WW structure
4941 */
4942void SwWW8WrTabu::Add(const SvxTabStop & rTS, long nAdjustment)
4943{
4944 // insert tab position
4945 ShortToSVBT16(msword_cast<sal_Int16>(rTS.GetTabPos() + nAdjustment),
4946 pAddPos.get() + (nAdd * 2));
4947
4948 // insert tab type
4949 sal_uInt8 nPara = 0;
4950 switch (rTS.GetAdjustment())
4951 {
4952 case SvxTabAdjust::Right:
4953 nPara = 2;
4954 break;
4955 case SvxTabAdjust::Center:
4956 nPara = 1;
4957 break;
4958 case SvxTabAdjust::Decimal:
4959 /*
4960 There is nothing we can do btw the decimal separator has been
4961 customized, but if you think different remember that different
4962 locales have different separators, i.e. german is a , while english
4963 is a .
4964 */
4965 nPara = 3;
4966 break;
4967 default:
4968 break;
4969 }
4970
4971 switch( rTS.GetFill() )
4972 {
4973 case '.': // dotted leader
4974 nPara |= 1 << 3;
4975 break;
4976 case '_': // Single line leader
4977 nPara |= 3 << 3;
4978 break;
4979 case '-': // hyphenated leader
4980 nPara |= 2 << 3;
4981 break;
4982 case '=': // heavy line leader
4983 nPara |= 4 << 3;
4984 break;
4985 }
4986
4987 pAddTyp[nAdd] = nPara;
4988 ++nAdd;
4989}
4990
4991/**
4992 * Insert a to be deleted tab in the WW structure
4993 */
4994void SwWW8WrTabu::Del(const SvxTabStop &rTS, long nAdjustment)
4995{
4996 // insert tab position
4997 ShortToSVBT16(msword_cast<sal_Int16>(rTS.GetTabPos() + nAdjustment),
4998 pDel.get() + (nDel * 2));
4999 ++nDel;
5000}
5001
5002/**
5003 * Writes the attribute to rWrt.pO
5004 */
5005void SwWW8WrTabu::PutAll(WW8Export& rWrt)
5006{
5007 if (!nAdd && !nDel) //If it's a no-op
5008 return;
5009 OSL_ENSURE(nAdd <= 255, "more than 255 added tabstops?")do { if (true && (!(nAdd <= 255))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "5009" ": "), "%s", "more than 255 added tabstops?"); } }
while (false)
;
5010 OSL_ENSURE(nDel <= 255, "more than 244 removed tabstops?")do { if (true && (!(nDel <= 255))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "5010" ": "), "%s", "more than 244 removed tabstops?"); }
} while (false)
;
5011 if (nAdd > 255)
5012 nAdd = 255;
5013 if (nDel > 255)
5014 nDel = 255;
5015
5016 sal_uInt16 nSiz = 2 * nDel + 3 * nAdd + 2;
5017 if (nSiz > 255)
5018 nSiz = 255;
5019
5020 rWrt.InsUInt16(NS_sprm::PChgTabsPapx::val);
5021 // insert cch
5022 rWrt.pO->push_back(msword_cast<sal_uInt8>(nSiz));
5023 // write DelArr
5024 rWrt.pO->push_back(msword_cast<sal_uInt8>(nDel));
5025 rWrt.OutSprmBytes(pDel.get(), nDel * 2);
5026 // write InsArr
5027 rWrt.pO->push_back(msword_cast<sal_uInt8>(nAdd));
5028 rWrt.OutSprmBytes(pAddPos.get(), 2 * nAdd); // AddPosArray
5029 rWrt.OutSprmBytes(pAddTyp.get(), nAdd); // AddTypArray
5030}
5031
5032static void ParaTabStopAdd( WW8Export& rWrt,
5033 const SvxTabStopItem& rTStops,
5034 const long nLParaMgn )
5035{
5036 SwWW8WrTabu aTab( 0, rTStops.Count());
5037
5038 for( sal_uInt16 n = 0; n < rTStops.Count(); n++ )
5039 {
5040 const SvxTabStop& rTS = rTStops[n];
5041 // ignore default tabs
5042 if (SvxTabAdjust::Default != rTS.GetAdjustment())
5043 aTab.Add(rTS, nLParaMgn);
5044 }
5045 aTab.PutAll( rWrt );
5046}
5047
5048static bool lcl_IsEqual(long nOneLeft, const SvxTabStop &rOne,
5049 long nTwoLeft, const SvxTabStop &rTwo)
5050{
5051 return(
5052 nOneLeft == nTwoLeft &&
5053 rOne.GetAdjustment() == rTwo.GetAdjustment() &&
5054 rOne.GetDecimal() == rTwo.GetDecimal() &&
5055 rOne.GetFill() == rTwo.GetFill()
5056 );
5057}
5058
5059static void ParaTabStopDelAdd( WW8Export& rWrt,
5060 const SvxTabStopItem& rTStyle,
5061 const long nLStypeMgn,
5062 const SvxTabStopItem& rTNew,
5063 const long nLParaMgn )
5064{
5065 SwWW8WrTabu aTab(rTStyle.Count(), rTNew.Count());
5066
5067 sal_uInt16 nO = 0; // rTStyle Index
5068 sal_uInt16 nN = 0; // rTNew Index
5069
5070 do {
5071 const SvxTabStop* pTO;
5072 long nOP;
5073 if( nO < rTStyle.Count() ) // old not yet at the end?
5074 {
5075 pTO = &rTStyle[ nO ];
5076 nOP = pTO->GetTabPos() + nLStypeMgn;
5077 if( SvxTabAdjust::Default == pTO->GetAdjustment() )
5078 {
5079 nO++; // ignore default tab
5080 continue;
5081 }
5082 }
5083 else
5084 {
5085 pTO = nullptr;
5086 nOP = LONG_MAX9223372036854775807L;
5087 }
5088
5089 const SvxTabStop* pTN;
5090 long nNP;
5091 if( nN < rTNew.Count() ) // new not yet at the end
5092 {
5093 pTN = &rTNew[ nN ];
5094 nNP = pTN->GetTabPos() + nLParaMgn;
5095 if( SvxTabAdjust::Default == pTN->GetAdjustment() )
5096 {
5097 nN++; // ignore default tab
5098 continue;
5099 }
5100 }
5101 else
5102 {
5103 pTN = nullptr;
5104 nNP = LONG_MAX9223372036854775807L;
5105 }
5106
5107 if( nOP == LONG_MAX9223372036854775807L && nNP == LONG_MAX9223372036854775807L )
5108 break; // everything done
5109
5110 if( nOP < nNP ) // next tab is old
5111 {
5112 assert(pTO)(static_cast <bool> (pTO) ? void (0) : __assert_fail ("pTO"
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 5112, __extension__ __PRETTY_FUNCTION__))
;
5113 aTab.Del(*pTO, nLStypeMgn); // must be deleted
5114 nO++;
5115 }
5116 else if( nNP < nOP ) // next tab is new
5117 {
5118 assert(pTN)(static_cast <bool> (pTN) ? void (0) : __assert_fail ("pTN"
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 5118, __extension__ __PRETTY_FUNCTION__))
;
5119 aTab.Add(*pTN, nLParaMgn); // must be inserted
5120 nN++;
5121 }
5122 else if (lcl_IsEqual(nOP, *pTO, nNP, *pTN)) // tabs are equal
5123 {
5124 nO++; // nothing to do
5125 nN++;
5126 }
5127 else // tabs same position, different type
5128 {
5129 aTab.Del(*pTO, nLStypeMgn); // delete old one
5130 aTab.Add(*pTN, nLParaMgn); // insert new one
5131 nO++;
5132 nN++;
5133 }
5134 } while( true );
5135
5136 aTab.PutAll( rWrt );
5137}
5138
5139void WW8AttributeOutput::ParaTabStop( const SvxTabStopItem& rTabStops )
5140{
5141 const bool bTabsRelativeToIndex = m_rWW8Export.m_pCurPam->GetDoc().getIDocumentSettingAccess().get( DocumentSettingId::TABS_RELATIVE_TO_INDENT );
5142
5143 long nCurrentLeft = 0;
5144 if ( bTabsRelativeToIndex )
5145 {
5146 const SfxPoolItem* pLR = m_rWW8Export.HasItem( RES_LR_SPACE );
5147
5148 if ( pLR != nullptr )
5149 nCurrentLeft = static_cast<const SvxLRSpaceItem*>(pLR)->GetTextLeft();
5150 }
5151
5152 // #i100264#
5153 if ( m_rWW8Export.m_bStyDef &&
5154 m_rWW8Export.m_pCurrentStyle != nullptr &&
5155 m_rWW8Export.m_pCurrentStyle->DerivedFrom() != nullptr )
5156 {
5157 SvxTabStopItem aParentTabs( 0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP );
5158 const SwFormat *pParentStyle = m_rWW8Export.m_pCurrentStyle->DerivedFrom();
5159 {
5160 if (const SvxTabStopItem* pParentTabs = pParentStyle->GetAttrSet().GetItem<SvxTabStopItem>(RES_PARATR_TABSTOP))
5161 {
5162 aParentTabs.Insert( pParentTabs );
5163 }
5164 }
5165
5166 // #i120938# - consider left indentation of style and its parent style
5167 long nParentLeft = 0;
5168 if ( bTabsRelativeToIndex )
5169 {
5170 const SvxLRSpaceItem &rStyleLR = ItemGet<SvxLRSpaceItem>( pParentStyle->GetAttrSet(), RES_LR_SPACE );
5171 nParentLeft = rStyleLR.GetTextLeft();
5172 }
5173
5174 ParaTabStopDelAdd( m_rWW8Export, aParentTabs, nParentLeft, rTabStops, nCurrentLeft );
5175 return;
5176 }
5177
5178 const SvxTabStopItem* pStyleTabs = nullptr;
5179 if ( !m_rWW8Export.m_bStyDef && m_rWW8Export.m_pStyAttr )
5180 {
5181 pStyleTabs = m_rWW8Export.m_pStyAttr->GetItem<SvxTabStopItem>(RES_PARATR_TABSTOP);
5182 }
5183
5184 if ( !pStyleTabs )
5185 {
5186 ParaTabStopAdd(m_rWW8Export, rTabStops, nCurrentLeft);
5187 }
5188 else
5189 {
5190 long nStyleLeft = 0;
5191 if ( bTabsRelativeToIndex )
5192 {
5193 const SvxLRSpaceItem &rStyleLR = ItemGet<SvxLRSpaceItem>(*m_rWW8Export.m_pStyAttr, RES_LR_SPACE);
5194 nStyleLeft = rStyleLR.GetTextLeft();
5195 }
5196
5197 ParaTabStopDelAdd( m_rWW8Export,
5198 *pStyleTabs, nStyleLeft,
5199 rTabStops, nCurrentLeft);
5200 }
5201}
5202
5203void AttributeOutputBase::OutputItem( const SfxPoolItem& rHt )
5204{
5205 // FIXME maybe use 'item_cast', like 'item_cast<SvxCharHiddenItem>( rHt )'?
5206 switch ( rHt.Which() )
5207 {
5208 case RES_CHRATR_CASEMAP:
5209 CharCaseMap( static_cast< const SvxCaseMapItem& >( rHt ) );
5210 break;
5211 case RES_CHRATR_COLOR:
5212 CharColor( static_cast< const SvxColorItem& >( rHt ) );
5213 break;
5214 case RES_CHRATR_CONTOUR:
5215 CharContour( static_cast< const SvxContourItem& >( rHt ) );
5216 break;
5217 case RES_CHRATR_CROSSEDOUT:
5218 CharCrossedOut( static_cast< const SvxCrossedOutItem& >( rHt ) );
5219 break;
5220 case RES_CHRATR_ESCAPEMENT:
5221 CharEscapement( static_cast< const SvxEscapementItem& >( rHt ) );
5222 break;
5223 case RES_CHRATR_FONT:
5224 CharFont( static_cast< const SvxFontItem& >( rHt ) );
5225 break;
5226 case RES_CHRATR_FONTSIZE:
5227 CharFontSize( static_cast< const SvxFontHeightItem& >( rHt ) );
5228 break;
5229 case RES_CHRATR_KERNING:
5230 CharKerning( static_cast< const SvxKerningItem& >( rHt ) );
5231 break;
5232 case RES_CHRATR_LANGUAGE:
5233 CharLanguage( static_cast< const SvxLanguageItem& >( rHt ) );
5234 break;
5235 case RES_CHRATR_POSTURE:
5236 CharPosture( static_cast< const SvxPostureItem& >( rHt ) );
5237 break;
5238 case RES_CHRATR_SHADOWED:
5239 CharShadow( static_cast< const SvxShadowedItem& >( rHt ) );
5240 break;
5241 case RES_CHRATR_UNDERLINE:
5242 CharUnderline( static_cast< const SvxUnderlineItem& >( rHt ) );
5243 break;
5244 case RES_CHRATR_WEIGHT:
5245 CharWeight( static_cast< const SvxWeightItem& >( rHt ) );
5246 break;
5247 case RES_CHRATR_AUTOKERN:
5248 CharAutoKern( static_cast< const SvxAutoKernItem& >( rHt ) );
5249 break;
5250 case RES_CHRATR_BLINK:
5251 CharAnimatedText( static_cast< const SvxBlinkItem& >( rHt ) );
5252 break;
5253 case RES_CHRATR_BACKGROUND:
5254 CharBackgroundBase( static_cast< const SvxBrushItem& >( rHt ) );
5255 break;
5256
5257 case RES_CHRATR_CJK_FONT:
5258 CharFontCJK( static_cast< const SvxFontItem& >( rHt ) );
5259 break;
5260 case RES_CHRATR_CJK_FONTSIZE:
5261 CharFontSizeCJK( static_cast< const SvxFontHeightItem& >( rHt ) );
5262 break;
5263 case RES_CHRATR_CJK_LANGUAGE:
5264 CharLanguageCJK( static_cast< const SvxLanguageItem& >( rHt ) );
5265 break;
5266 case RES_CHRATR_CJK_POSTURE:
5267 CharPostureCJK( static_cast< const SvxPostureItem& >( rHt ) );
5268 break;
5269 case RES_CHRATR_CJK_WEIGHT:
5270 CharWeightCJK( static_cast< const SvxWeightItem& >( rHt ) );
5271 break;
5272
5273 case RES_CHRATR_CTL_FONT:
5274 CharFontCTL( static_cast< const SvxFontItem& >( rHt ) );
5275 break;
5276 case RES_CHRATR_CTL_FONTSIZE:
5277 CharFontSizeCTL( static_cast< const SvxFontHeightItem& >( rHt ) );
5278 break;
5279 case RES_CHRATR_CTL_LANGUAGE:
5280 CharLanguageCTL( static_cast< const SvxLanguageItem& >( rHt ) );
5281 break;
5282 case RES_CHRATR_CTL_POSTURE:
5283 CharPostureCTL( static_cast< const SvxPostureItem& >( rHt ) );
5284 break;
5285 case RES_CHRATR_CTL_WEIGHT:
5286 CharWeightCTL( static_cast< const SvxWeightItem& >( rHt ) );
5287 break;
5288
5289 case RES_CHRATR_ROTATE:
5290 CharRotate( static_cast< const SvxCharRotateItem& >( rHt ) );
5291 break;
5292 case RES_CHRATR_EMPHASIS_MARK:
5293 CharEmphasisMark( static_cast< const SvxEmphasisMarkItem& >( rHt ) );
5294 break;
5295 case RES_CHRATR_TWO_LINES:
5296 CharTwoLines( static_cast< const SvxTwoLinesItem& >( rHt ) );
5297 break;
5298 case RES_CHRATR_SCALEW:
5299 CharScaleWidth( static_cast< const SvxCharScaleWidthItem& >( rHt ) );
5300 break;
5301 case RES_CHRATR_RELIEF:
5302 CharRelief( static_cast< const SvxCharReliefItem& >( rHt ) );
5303 break;
5304 case RES_CHRATR_HIDDEN:
5305 CharHidden( static_cast< const SvxCharHiddenItem& >( rHt ) );
5306 break;
5307 case RES_CHRATR_BOX:
5308 FormatCharBorder( static_cast< const SvxBoxItem& >( rHt ) );
5309 break;
5310 case RES_CHRATR_HIGHLIGHT:
5311 CharHighlight( static_cast< const SvxBrushItem& >( rHt ) );
5312 break;
5313 case RES_CHRATR_BIDIRTL:
5314 CharBidiRTL( rHt );
5315 break;
5316 case RES_CHRATR_IDCTHINT:
5317 CharIdctHint( rHt );
5318 break;
5319 case RES_TXTATR_INETFMT:
5320 TextINetFormat( static_cast< const SwFormatINetFormat& >( rHt ) );
5321 break;
5322 case RES_TXTATR_CHARFMT:
5323 TextCharFormat( static_cast< const SwFormatCharFormat& >( rHt ) );
5324 break;
5325
5326 case RES_TXTATR_FIELD:
5327 case RES_TXTATR_ANNOTATION:
5328 case RES_TXTATR_INPUTFIELD:
5329 TextField( static_cast< const SwFormatField& >( rHt ) );
5330 break;
5331
5332 case RES_TXTATR_FLYCNT:
5333 TextFlyContent( static_cast< const SwFormatFlyCnt& >( rHt ) );
5334 break;
5335 case RES_TXTATR_FTN:
5336 TextFootnote( static_cast< const SwFormatFootnote& >( rHt ) );
5337 break;
5338
5339 case RES_PARATR_LINESPACING:
5340 ParaLineSpacing( static_cast< const SvxLineSpacingItem& >( rHt ) );
5341 break;
5342 case RES_PARATR_ADJUST:
5343 ParaAdjust( static_cast< const SvxAdjustItem& >( rHt ) );
5344 break;
5345 case RES_PARATR_SPLIT:
5346 ParaSplit( static_cast< const SvxFormatSplitItem& >( rHt ) );
5347 break;
5348 case RES_PARATR_WIDOWS:
5349 ParaWidows( static_cast< const SvxWidowsItem& >( rHt ) );
5350 break;
5351 case RES_PARATR_TABSTOP:
5352 ParaTabStop( static_cast< const SvxTabStopItem& >( rHt ) );
5353 break;
5354 case RES_PARATR_HYPHENZONE:
5355 ParaHyphenZone( static_cast< const SvxHyphenZoneItem& >( rHt ) );
5356 break;
5357 case RES_PARATR_NUMRULE:
5358 ParaNumRule( static_cast< const SwNumRuleItem& >( rHt ) );
5359 break;
5360 case RES_PARATR_SCRIPTSPACE:
5361 ParaScriptSpace( static_cast< const SfxBoolItem& >( rHt ) );
5362 break;
5363 case RES_PARATR_HANGINGPUNCTUATION:
5364 ParaHangingPunctuation( static_cast< const SfxBoolItem& >( rHt ) );
5365 break;
5366 case RES_PARATR_FORBIDDEN_RULES:
5367 ParaForbiddenRules( static_cast< const SfxBoolItem& >( rHt ) );
5368 break;
5369 case RES_PARATR_VERTALIGN:
5370 ParaVerticalAlign( static_cast< const SvxParaVertAlignItem& >( rHt ) );
5371 break;
5372 case RES_PARATR_SNAPTOGRID:
5373 ParaSnapToGrid( static_cast< const SvxParaGridItem& >( rHt ) );
5374 break;
5375
5376 case RES_FRM_SIZE:
5377 FormatFrameSize( static_cast< const SwFormatFrameSize& >( rHt ) );
5378 break;
5379 case RES_PAPER_BIN:
5380 FormatPaperBin( static_cast< const SvxPaperBinItem& >( rHt ) );
5381 break;
5382 case RES_LR_SPACE:
5383 FormatLRSpace( static_cast< const SvxLRSpaceItem& >( rHt ) );
5384 break;
5385 case RES_UL_SPACE:
5386 FormatULSpace( static_cast< const SvxULSpaceItem& >( rHt ) );
5387 break;
5388 case RES_PAGEDESC:
5389 FormatPageDescription( static_cast< const SwFormatPageDesc& >( rHt ) );
5390 break;
5391 case RES_BREAK:
5392 FormatBreak( static_cast< const SvxFormatBreakItem& >( rHt ) );
5393 break;
5394 case RES_SURROUND:
5395 FormatSurround( static_cast< const SwFormatSurround& >( rHt ) );
5396 break;
5397 case RES_VERT_ORIENT:
5398 FormatVertOrientation( static_cast< const SwFormatVertOrient& >( rHt ) );
5399 break;
5400 case RES_HORI_ORIENT:
5401 FormatHorizOrientation( static_cast< const SwFormatHoriOrient& >( rHt ) );
5402 break;
5403 case RES_ANCHOR:
5404 FormatAnchor( static_cast< const SwFormatAnchor& >( rHt ) );
5405 break;
5406 case RES_BACKGROUND:
5407 FormatBackground( static_cast< const SvxBrushItem& >( rHt ) );
5408 break;
5409 case XATTR_FILLSTYLE:
5410 FormatFillStyle( static_cast< const XFillStyleItem& >( rHt ) );
5411 break;
5412 case XATTR_FILLGRADIENT:
5413 FormatFillGradient( static_cast< const XFillGradientItem& >( rHt ) );
5414 break;
5415 case RES_BOX:
5416 FormatBox( static_cast< const SvxBoxItem& >( rHt ) );
5417 break;
5418 case RES_COL:
5419 FormatColumns( static_cast< const SwFormatCol& >( rHt ) );
5420 break;
5421 case RES_KEEP:
5422 FormatKeep( static_cast< const SvxFormatKeepItem& >( rHt ) );
5423 break;
5424 case RES_TEXTGRID:
5425 FormatTextGrid( static_cast< const SwTextGridItem& >( rHt ) );
5426 break;
5427 case RES_LINENUMBER:
5428 FormatLineNumbering( static_cast< const SwFormatLineNumber& >( rHt ) );
5429 break;
5430 case RES_FRAMEDIR:
5431 FormatFrameDirection( static_cast< const SvxFrameDirectionItem& >( rHt ) );
5432 break;
5433 case RES_PARATR_GRABBAG:
5434 ParaGrabBag(static_cast<const SfxGrabBagItem&>(rHt));
5435 break;
5436 case RES_PARATR_OUTLINELEVEL:
5437 ParaOutlineLevel(static_cast<const SfxUInt16Item&>(rHt));
5438 break;
5439 case RES_CHRATR_GRABBAG:
5440 CharGrabBag(static_cast<const SfxGrabBagItem&>(rHt));
5441 break;
5442
5443 default:
5444 SAL_INFO("sw.ww8", "Unhandled SfxPoolItem with id " << rHt.Which() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Unhandled SfxPoolItem with id "
<< rHt.Which()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "5444" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Unhandled SfxPoolItem with id " <<
rHt.Which()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "Unhandled SfxPoolItem with id "
<< rHt.Which(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "5444" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Unhandled SfxPoolItem with id " << rHt.Which
()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), (
"sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "5444" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Unhandled SfxPoolItem with id " <<
rHt.Which()), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "Unhandled SfxPoolItem with id "
<< rHt.Which(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
":" "5444" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5445 break;
5446 }
5447}
5448
5449void AttributeOutputBase::OutputStyleItemSet( const SfxItemSet& rSet, bool bTestForDefault )
5450{
5451 // based on OutputItemSet() from wrt_fn.cxx
5452
5453 const SfxItemPool& rPool = *rSet.GetPool();
5454 const SfxItemSet* pSet = &rSet;
5455 if ( !pSet->Count() )
5456 {
5457 while ( nullptr != ( pSet = pSet->GetParent() ) && !pSet->Count() )
5458 ;
5459
5460 if ( !pSet )
5461 return;
5462 }
5463
5464 const SfxPoolItem* pItem;
5465 if ( !pSet->GetParent() )
5466 {
5467 assert(rSet.Count() && "Was already handled or?")(static_cast <bool> (rSet.Count() && "Was already handled or?"
) ? void (0) : __assert_fail ("rSet.Count() && \"Was already handled or?\""
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8atr.cxx"
, 5467, __extension__ __PRETTY_FUNCTION__))
;
5468 SfxItemIter aIter( *pSet );
5469 pItem = aIter.GetCurItem();
5470 do {
5471 OutputItem( *pItem );
5472 } while ((pItem = aIter.NextItem()));
5473 }
5474 else
5475 {
5476 SfxWhichIter aIter( *pSet );
5477 sal_uInt16 nWhich = aIter.FirstWhich();
5478 while ( nWhich )
5479 {
5480 if ( SfxItemState::SET == pSet->GetItemState( nWhich, true/*bDeep*/, &pItem ) &&
5481 ( !bTestForDefault ||
5482 nWhich == RES_UL_SPACE ||
5483 nWhich == RES_LR_SPACE ||
5484 *pItem != rPool.GetDefaultItem( nWhich ) ||
5485 ( pSet->GetParent() && *pItem != pSet->GetParent()->Get( nWhich ) ) ) )
5486 {
5487 OutputItem( *pItem );
5488 }
5489 nWhich = aIter.NextWhich();
5490 }
5491 }
5492}
5493
5494void AttributeOutputBase::FormatCharBorder( const SvxBoxItem& rBox )
5495{
5496 // Get one of the borders (if there is any border then in docx also will be)
5497 const SvxBorderLine* pBorderLine = nullptr;
5498 sal_uInt16 nDist = 0;
5499 if( rBox.GetTop() )
5500 {
5501 pBorderLine = rBox.GetTop();
5502 nDist = rBox.GetDistance( SvxBoxItemLine::TOP );
5503 }
5504 else if( rBox.GetLeft() )
5505 {
5506 pBorderLine = rBox.GetLeft();
5507 nDist = rBox.GetDistance( SvxBoxItemLine::LEFT );
5508 }
5509 else if( rBox.GetBottom() )
5510 {
5511 pBorderLine = rBox.GetBottom();
5512 nDist = rBox.GetDistance( SvxBoxItemLine::BOTTOM );
5513 }
5514 else if( rBox.GetRight() )
5515 {
5516 pBorderLine = rBox.GetRight();
5517 nDist = rBox.GetDistance( SvxBoxItemLine::RIGHT );
5518 }
5519
5520 // RTF: avoid regressions since RTF doesn't know how to export a border_NONE style-override
5521 if( pBorderLine || GetExport().GetExportFormat() != MSWordExportBase::ExportFormat::RTF )
5522 {
5523 const SfxPoolItem* pItem = GetExport().HasItem( RES_CHRATR_SHADOW );
5524 const SvxShadowItem* pShadowItem = static_cast<const SvxShadowItem*>(pItem);
5525 const bool bShadow = pBorderLine &&
5526 pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE &&
5527 pShadowItem->GetWidth() > 0;
5528
5529 CharBorder( pBorderLine, nDist, bShadow );
5530 }
5531}
5532
5533/*
5534 * This function is used to check if the current SwTextNode (paragraph) has a redline object
5535 * that is attached to the paragraph marker.
5536 * This is done by checking if the range (SwPaM) of the redline is :
5537 * - Start = the last character of the current paragraph
5538 * - End = the first character of the next paragraph
5539 */
5540const SwRedlineData* AttributeOutputBase::GetParagraphMarkerRedline( const SwTextNode& rNode, RedlineType aRedlineType)
5541{
5542 // ToDo : this is not the most ideal ... should start maybe from 'nCurRedlinePos'
5543 for(SwRangeRedline* pRedl : GetExport().m_rDoc.getIDocumentRedlineAccess().GetRedlineTable())
5544 {
5545 // Only check redlines that are of type 'Delete'
5546 if ( pRedl->GetRedlineData().GetType() != aRedlineType )
5547 continue;
5548
5549 sal_uLong uStartNodeIndex = pRedl->Start()->nNode.GetIndex();
5550 sal_uLong uEndNodeIndex = pRedl->End()->nNode.GetIndex();
5551 sal_uLong uNodeIndex = rNode.GetIndex();
5552
5553 if( uStartNodeIndex <= uNodeIndex && uNodeIndex < uEndNodeIndex )
5554 return &( pRedl->GetRedlineData() );
5555 }
5556 return nullptr;
5557}
5558
5559void AttributeOutputBase::CharBackgroundBase( const SvxBrushItem& rBrush )
5560{
5561 bool bConvertToShading = SvtFilterOptions::Get().IsCharBackground2Shading();
5562 bool bHasShadingMarker = false;
5563
5564 // Check shading marker
5565 const SfxPoolItem* pItem = GetExport().HasItem(RES_CHRATR_GRABBAG);
5566 if( pItem )
5567 {
5568 const SfxGrabBagItem aGrabBag = static_cast< const SfxGrabBagItem& >(*pItem);
5569 const std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
5570 auto aIterator = rMap.find("CharShadingMarker");
5571 if( aIterator != rMap.end() )
5572 {
5573 aIterator->second >>= bHasShadingMarker;
5574 }
5575 }
5576
5577 if( bConvertToShading || bHasShadingMarker )
5578 {
5579 CharBackground(rBrush);
5580 }
5581 else
5582 {
5583 CharHighlight(rBrush);
5584 }
5585}
5586
5587/* vim:set shiftwidth=4 softtabstop=4 expandtab: */