View
212
Download
0
Category
Preview:
Citation preview
LibreOffice Module sw (master): ww8atr.cxx Source File
LibreOffice Module sw (master) 1
MainPageRelatedPagesModulesNamespacesClassesFilesExamples
FileListFileMembers
swsourcefilterww8
ww8atr.cxx
Go to the documentation of this file. 1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20/*
21 * This file contains methods for the WW8 output
22 * (nodes, attributes, formats and chars).
23 */
24
25#include
26
27#include
28#include
29#include
30
31#include
32#include
33#include
34#include
35#include
36#include
37#include
38#include
39#include
40#include
41#include
42#include
43#include
44#include
45#include
46#include
47#include
48#include
49#include
50#include
51#include
52#include
53#include
54#include
55#include
56#include
57#include
58#include
59#include
60#include
61#include
62#include
63#include
64#include
65#include
66#include
67#include
68#include
69#include
70#include
71#include
72#include
73#include
74#include
75#include
76#include
77#include
78#include
79#include
80#include
81#include
82#include
83#include
84#include
85#include
86#include
87#include
88#include
89#include
90#include
91#include
92#include
93#include
94#include
95#include
96#include
97#include
98#include
99#include
100#include
101#include
102#include
103#include
104#include
105#include
106#include
107#include
108#include
109#include
110#include
111#include
112#include
113#include
114#include
115#include
116#include
117#include
118#include
119#include
120#include
121#include
122#include
123#include
124#include
125#include
126#include
127
128#include "sprmids.hxx"
129
130#include
131#include "writerhelper.hxx"
132#include "writerwordglue.hxx"
133#include "wrtww8.hxx"
134#include "ww8par.hxx"
135#include "ww8attributeoutput.hxx"
136#include "fields.hxx"
137#include
138#include
139#include
140#include
141#include
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 ww8::cPoolItemIter aEnd = rItems.end();
212 for ( ww8::cPoolItemIter aI = rItems.begin(); aI != aEnd; ++aI )
213 {
214 const SfxPoolItem *pItem = aI->second;
215 sal_uInt16 nWhich = pItem->Which();
216 if ( ( isCHRATR( nWhich ) || isTXTATR( nWhich ) ) && CollapseScriptsforWordOk( nScript, nWhich ) )
217 {
218 //In the id definition, RES_TXTATR_INETFMT must precede RES_TXTATR_CHARFMT, so that link style can overwrite char style.
219 //and in #i24291# it describes "All we want to do is ensure for now is that if a charfmt exist in the character
220 //properties that it rises to the top and is exported first."
221 //In bug 119649, it is in such situation, so we need to ignore the link style when doing ms word filter exports and
222 //add the second judgement for #i24291# definition.
223 if ( nWhich == RES_TXTATR_INETFMT && ( rItems.begin()->second->Which() == RES_TXTATR_CHARFMT ) )
224 continue;
225
226 // tdf#38778 Fix output of the font in DOC run for fields
227 if (pFont &&
228 nWhich == RES_TXTATR_FIELD)
229 {
230 AttrOutput().OutputItem( *pFont );
231 }
232
233 // tdf#66401 For Combined Characters in docx, MS Word uses half the normal font-size for the field's
234 // font-size, but only for . Therefore, we check if we are currently writing a field of type
235 // Combined Characters and if so, we half the font size.
236 if (bWriteCombChars &&
237 nWhich == RES_CHRATR_FONTSIZE)
238 {
239 SvxFontHeightItem fontHeight(item_cast( *pItem ));
240 fontHeight.SetHeight( fontHeight.GetHeight() / 2 );
241
242 AttrOutput().OutputItem( fontHeight );
243 }
244 else
245 {
246 AttrOutput().OutputItem( *pItem );
247 }
248 }
249 }
250}
251
252/*
253 * Output format as follows:
254 * - output the attributes; without parents!
255 */
256
257void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, bool bChpFormat, sal_uInt16 nScript,
258 bool bExportParentItemSet )
259{
260 if( bExportParentItemSet || rSet.Count() )
261 {
262 const SfxPoolItem* pItem;
263 m_pISet = &rSet; // for double attributes
264
265 // If frame dir is set, but not adjust, then force adjust as well
266 if ( bPapFormat && SfxItemState::SET == rSet.GetItemState( RES_FRAMEDIR, bExportParentItemSet ) )
267 {
268 // No explicit adjust set ?
269 if ( SfxItemState::SET != rSet.GetItemState( RES_PARATR_ADJUST, bExportParentItemSet ) )
270 {
271 if ( nullptr != ( pItem = rSet.GetItem( RES_PARATR_ADJUST, bExportParentItemSet ) ) )
272 {
273 // then set the adjust used by the parent format
274 AttrOutput().OutputItem( *pItem );
275 }
276 }
277 }
278
279 if ( bPapFormat && SfxItemState::SET == rSet.GetItemState( RES_PARATR_NUMRULE, bExportParentItemSet, &pItem ) )
280 {
281 AttrOutput().OutputItem( *pItem );
282
283 // switch off the numbering?
284 if ( static_cast(pItem)->GetValue().isEmpty() &&
285 SfxItemState::SET != rSet.GetItemState( RES_LR_SPACE, false) &&
286 SfxItemState::SET == rSet.GetItemState( RES_LR_SPACE, true, &pItem ) )
287 {
288 // the set the LR-Space of the parentformat!
289 AttrOutput().OutputItem( *pItem );
290 }
291 }
292
293 ww8::PoolItems aItems;
294 GetPoolItems( rSet, aItems, bExportParentItemSet );
295 if ( bChpFormat )
296 ExportPoolItemsToCHP(aItems, nScript, nullptr);
297 if ( bPapFormat )
298 {
299 ww8::cPoolItemIter aEnd = aItems.end();
300 for ( ww8::cPoolItemIter aI = aItems.begin(); aI != aEnd; ++aI )
301 {
302 pItem = aI->second;
303 sal_uInt16 nWhich = pItem->Which();
304 // Handle fill attributes just like frame attributes for now.
305 if ( (nWhich >= RES_PARATR_BEGIN && nWhich < RES_FRMATR_END && nWhich != RES_PARATR_NUMRULE ) ||
306 (nWhich >= XATTR_FILL_FIRST && nWhich < XATTR_FILL_LAST))
307 AttrOutput().OutputItem( *pItem );
308 }
309
310 // Has to be called after RES_PARATR_GRABBAG is processed.
311 const XFillStyleItem* pXFillStyleItem(rSet.GetItem(XATTR_FILLSTYLE));
312 if (pXFillStyleItem && pXFillStyleItem->GetValue() == drawing::FillStyle_SOLID && !rSet.HasItem(RES_BACKGROUND))
313 {
314 // Construct an SvxBrushItem, as expected by the exporters.
315 AttrOutput().OutputItem(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND));
316 }
317 }
318 m_pISet = nullptr; // for double attributes
319 }
320}
321
322void MSWordExportBase::GatherChapterFields()
323{
324 //If the header/footer contains a chapter field
325 SwFieldType* pType = m_pDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Chapter );
326 SwIterator aFormatFields( *pType );
327 for ( SwFormatField* pField = aFormatFields.First(); pField; pField = aFormatFields.Next() )
328 {
329 if (const SwTextField *pTextField = pField->GetTextField())
330 {
331 const SwTextNode &rTextNode = pTextField->GetTextNode();
332 m_aChapterFieldLocs.push_back(rTextNode.GetIndex());
333 }
334 }
335}
336
337bool MSWordExportBase::ContentContainsChapterField(const SwFormatContent &rContent) const
338{
339 bool bRet = false;
340 if ( const SwNodeIndex* pSttIdx = rContent.GetContentIdx() )
341 {
342 SwNodeIndex aIdx( *pSttIdx, 1 );
343 SwNodeIndex aEnd( *pSttIdx->GetNode().EndOfSectionNode() );
344 sal_uLong nStart = aIdx.GetIndex();
345 sal_uLong nEnd = aEnd.GetIndex();
346 //If the header/footer contains a chapter field
347 mycCFIter aIEnd = m_aChapterFieldLocs.end();
348 for ( mycCFIter aI = m_aChapterFieldLocs.begin(); aI != aIEnd; ++aI )
349 {
350 if ( ( nStart GetContent() );
373}
374
375bool MSWordExportBase::SetCurrentPageDescFromNode(const SwNode &rNd)
376{
377 bool bNewPageDesc = false;
378 const SwPageDesc* pCurrent = SwPageDesc::GetPageDescOfNode(rNd);
379 OSL_ENSURE(pCurrent && m_pCurrentPageDesc, "Not possible surely");
380 if (m_pCurrentPageDesc && pCurrent)
381 {
382 if (pCurrent != m_pCurrentPageDesc)
383 {
384 if (m_pCurrentPageDesc->GetFollow() != pCurrent)
385 bNewPageDesc = true;
386 else
387 {
388 const SwFrameFormat& rTitleFormat = m_pCurrentPageDesc->GetFirstMaster();
389 const SwFrameFormat& rFollowFormat = pCurrent->GetMaster();
390
391 bNewPageDesc = !IsPlausableSingleWordSection(rTitleFormat,
392 rFollowFormat);
393 }
394 m_pCurrentPageDesc = pCurrent;
395 }
396 else
397 {
398 const SwFrameFormat &rFormat = pCurrent->GetMaster();
399 bNewPageDesc = FormatHdFtContainsChapterField(rFormat);
400 }
401 }
402 return bNewPageDesc;
403}
404
415void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen, bool isTextNodeEmpty)
416{
417 if ( m_bStyDef || m_bOutKF || m_bInWriteEscher || m_bOutPageDescs )
418 return;
419
420 m_bBreakBefore = true;
421 bool bNewPageDesc = false;
422 const SfxPoolItem* pItem=nullptr;
423 const SwFormatPageDesc *pPgDesc=nullptr;
424
425 //Output a sectionbreak if there's a new pagedescriptor. Otherwise output a
426 //pagebreak if there is a pagebreak here, unless the new page (follow
427 //style) is different to the current one, in which case plump for a
428 //section.
429 bool bBreakSet = false;
430
431 const SwPageDesc * pPageDesc = rNd.FindPageDesc();
432
433 // Even if pAktPageDesc != pPageDesc ,it might be because of the different header & footer types.
434 if (m_pCurrentPageDesc != pPageDesc)
435 {
436 if ( ( isCellOpen && ( m_pCurrentPageDesc->GetName() != pPageDesc->GetName() )) ||
437 ( isTextNodeEmpty || m_bPrevTextNodeIsEmpty ))
438 {
439 /* Do not output a section break in the following scenarios.
440 1) Table cell is open and page header types are different
441 2) PageBreak is present but text node has no string - it is an empty node.
442 3) If the previous node was an empty text node and current node is a non empty text node or vice versa.
443 4) If previous node and current node both are empty text nodes.
444 Converting a page break to section break would cause serious issues while importing
445 the RT files with different first page being set.
446 */
447 bNewPageDesc = false;
448
449 /*
450 * If Table cell is open and page header types are different
451 * set pSet to NULL as we don't want to add any section breaks.
452 */
453 if ( isCellOpen && ( m_pCurrentPageDesc->GetName() != pPageDesc->GetName() ) )
454 pSet = nullptr;
455 }
456 else if (!sw::util::IsPlausableSingleWordSection(m_pCurrentPageDesc->GetFirstMaster(), pPageDesc->GetMaster()))
457 {
458 bBreakSet = true;
459 bNewPageDesc = true;
460 m_pCurrentPageDesc = pPageDesc;
461 }
462 }
463
464 if ( pSet && pSet->Count() )
465 {
466 if ( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, false, &pItem ) &&
467 static_cast(pItem)->GetRegisteredIn() != nullptr)
468 {
469 bBreakSet = true;
470 bNewPageDesc = true;
471 pPgDesc = static_cast(pItem);
472 m_pCurrentPageDesc = pPgDesc->GetPageDesc();
473 }
474 else if ( SfxItemState::SET == pSet->GetItemState( RES_BREAK, false, &pItem ) )
475 {
476 // Word does not like hard break attributes in some table cells
477 bool bRemoveHardBreakInsideTable = false;
478 if ( m_bOutTable )
479 {
480 const SwTableNode* pTableNode = rNd.FindTableNode();
481 if ( pTableNode )
482 {
483 const SwTableBox* pBox = rNd.GetTableBox();
484 const SwTableLine* pLine = pBox ? pBox->GetUpper() : nullptr;
485 // but only for non-complex tables
486 if ( pLine && !pLine->GetUpper() )
487 {
488 // check if box is not first in that line:
489 if ( 0 < pLine->GetBoxPos( pBox ) && pBox->GetSttNd() )
490 {
491 bRemoveHardBreakInsideTable = true;
492 }
493 }
494 }
495 }
496 bNewPageDesc = false; // if next node has RES_BREAK(page break) then bNewPageDesc value should be false.
497 bBreakSet = true;
498
499 if ( !bRemoveHardBreakInsideTable )
500 {
501 OSL_ENSURE(m_pCurrentPageDesc, "should not be possible");
502 /*
503 If because of this pagebreak the page desc following the page
504 break is the follow style of the current page desc then output a
505 section break using that style instead. At least in those cases
506 we end up with the same style in word and writer, nothing can be
507 done when it happens when we get a new pagedesc because we
508 overflow from the first page style.
509 */
510 if ( m_pCurrentPageDesc )
511 {
512 // #i76301# - assure that there is a page break before set at the node.
513 const SvxFormatBreakItem* pBreak = dynamic_cast(pItem);
514 if ( pBreak &&
515 pBreak->GetBreak() == SvxBreak::PageBefore )
516 {
517 bNewPageDesc |= SetCurrentPageDescFromNode( rNd );
518 }
519 if( isTextNodeEmpty )
520 bNewPageDesc = false;
521 }
522 if ( !bNewPageDesc )
523 AttrOutput().OutputItem( *pItem );
524 }
525 }
526 }
527
528 /*
529 #i9301#
530 No explicit page break, lets see if the style had one and we've moved to a
531 new page style because of it, if we have to then we take the opportunity to
532 set the equivalent word section here. We *could* do it for every paragraph
533 that moves onto a new page because of layout, but that would be insane.
534 */
535 bool bHackInBreak = false;
536 if ( !bBreakSet )
537 {
538 if ( const SwContentNode *pNd = rNd.GetContentNode() )
539 {
540 const SvxFormatBreakItem &rBreak =
541 ItemGet( *pNd, RES_BREAK );
542 if ( rBreak.GetBreak() == SvxBreak::PageBefore )
543 bHackInBreak = true;
544 else
545 { // Even a pagedesc item is set, the break item can be set 'NONE',
546 // but a pagedesc item is an implicit page break before...
547 const SwFormatPageDesc &rPageDesc =
548 ItemGet( *pNd, RES_PAGEDESC );
549 if ( rPageDesc.KnowsPageDesc() )
550 bHackInBreak = true;
551 }
552 }
553 }
554
555 if ( bHackInBreak )
556 {
557 OSL_ENSURE( m_pCurrentPageDesc, "should not be possible" );
558 if ( m_pCurrentPageDesc )
559 bNewPageDesc = SetCurrentPageDescFromNode( rNd );
560 }
561
562 if ( bNewPageDesc && m_pCurrentPageDesc )
563 {
564 PrepareNewPageDesc( pSet, rNd, pPgDesc, m_pCurrentPageDesc );
565 }
566 m_bBreakBefore = false;
567 m_bPrevTextNodeIsEmpty = isTextNodeEmpty ;
568}
569
570// #i76300#
571bool MSWordExportBase::OutputFollowPageDesc( const SfxItemSet* pSet, const SwTextNode* pNd )
572{
573 bool bRet = false;
574
575 if ( pNd &&
576 m_pCurrentPageDesc &&
577 m_pCurrentPageDesc != m_pCurrentPageDesc->GetFollow() )
578 {
579 PrepareNewPageDesc( pSet, *pNd, nullptr, m_pCurrentPageDesc->GetFollow() );
580 bRet = true;
581 }
582
583 return bRet;
584}
585
586const SwSectionFormat* MSWordExportBase::GetSectionFormat( const SwNode& rNd )
587{
588 const SwSectionFormat* pFormat = nullptr;
589 const SwSectionNode* pSect = rNd.FindSectionNode();
590 if ( pSect &&
591 CONTENT_SECTION == pSect->GetSection().GetType() )
592 {
593 pFormat = pSect->GetSection().GetFormat();
594 }
595
596 return pFormat;
597}
598
599sal_uLong MSWordExportBase::GetSectionLineNo( const SfxItemSet* pSet, const SwNode& rNd )
600{
601 const SwFormatLineNumber* pNItem = nullptr;
602 if ( pSet )
603 {
604 pNItem = &( ItemGet( *pSet, RES_LINENUMBER ) );
605 }
606 else if ( const SwContentNode *pNd = rNd.GetContentNode() )
607 {
608 pNItem = &( ItemGet( *pNd, RES_LINENUMBER ) );
609 }
610
611 return pNItem? pNItem->GetStartValue() : 0;
612}
613
614void WW8Export::PrepareNewPageDesc( const SfxItemSet*pSet,
615 const SwNode& rNd,
616 const SwFormatPageDesc* pNewPgDescFormat,
617 const SwPageDesc* pNewPgDesc )
618{
619 // The PageDescs will only be inserted in WW8Writer::pSepx with the corresponding
620 // position by the occurrences of PageDesc attributes. The construction and
621 // output of the attributes and header/footer of the PageDesc are done
622 // after the main text and its attributes.
623
624 sal_uLong nFcPos = ReplaceCr( msword::PageBreak ); // Page/Section-Break
625
626 // actually nothing is outputted here, rather the arrays aCps, aSects
627 // accordingly completed
628 if ( !nFcPos )
629 return;
630
631 const SwSectionFormat* pFormat = GetSectionFormat( rNd );
632 const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
633
634 OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." );
635
636 if ( pNewPgDescFormat )
637 {
638 pSepx->AppendSep( Fc2Cp( nFcPos ), *pNewPgDescFormat, rNd, pFormat, nLnNm );
639 }
640 else if ( pNewPgDesc )
641 {
642 pSepx->AppendSep( Fc2Cp( nFcPos ), pNewPgDesc, rNd, pFormat, nLnNm );
643 }
644}
645
646void MSWordExportBase::CorrectTabStopInSet( SfxItemSet& rSet, short nAbsLeft )
647{
648 if (const SvxTabStopItem *pItem = rSet.GetItem(RES_PARATR_TABSTOP))
649 {
650 // then it must be corrected for the output
651 SvxTabStopItem aTStop(*pItem);
652 for ( sal_uInt16 nCnt = 0; nCnt < aTStop.Count(); ++nCnt )
653 {
654 SvxTabStop& rTab = const_cast(aTStop[ nCnt ]);
655 if ( SvxTabAdjust::Default != rTab.GetAdjustment() &&
656 rTab.GetTabPos() >= nAbsLeft )
657 {
658 rTab.GetTabPos() -= nAbsLeft;
659 }
660 else
661 {
662 aTStop.Remove( nCnt );
663 --nCnt;
664 }
665 }
666 rSet.Put( aTStop );
667 }
668}
669
670sal_uInt8 WW8Export::GetNumId( sal_uInt16 eNumType )
671{
672 sal_uInt8 nRet = 0;
673 switch( eNumType )
674 {
675 case SVX_NUM_CHARS_UPPER_LETTER:
676 case SVX_NUM_CHARS_UPPER_LETTER_N: nRet = 3; break;
677 case SVX_NUM_CHARS_LOWER_LETTER:
678 case SVX_NUM_CHARS_LOWER_LETTER_N: nRet = 4; break;
679 case SVX_NUM_ROMAN_UPPER: nRet = 1; break;
680 case SVX_NUM_ROMAN_LOWER: nRet = 2; break;
681
682 case SVX_NUM_BITMAP:
683 case SVX_NUM_CHAR_SPECIAL: nRet = 23; break;
684
685 // nothing, WW does the same (undocumented)
686 case SVX_NUM_NUMBER_NONE: nRet = 0xff; break;
687 }
688 return nRet;
689}
690
691void WW8AttributeOutput::OutlineNumbering(sal_uInt8 nLvl)
692{
693 if ( nLvl >= WW8ListManager::nMaxLevel )
694 nLvl = WW8ListManager::nMaxLevel-1;
695
696 // write sprmPOutLvl sprmPIlvl and sprmPIlfo
697 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::sprmPOutLvl );
698 m_rWW8Export.pO->push_back( nLvl );
699 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::sprmPIlvl );
700 m_rWW8Export.pO->push_back( nLvl );
701 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::sprmPIlfo );
702 SwWW8Writer::InsUInt16( *m_rWW8Export.pO,
703 1 + m_rWW8Export.GetId( *m_rWW8Export.m_pDoc->GetOutlineNumRule() ) );
704}
705
706// #i77805#
707bool WW8Export::DisallowInheritingOutlineNumbering(const SwFormat &rFormat)
708{
709 bool bRet( false );
710
711 //If there is no numbering on this fmt, but its parent was outline
712 //numbered, then in writer this is no inheritied, but in word it would
713 //be, so we must export "no numbering" and "body level" to make word
714 //behave like writer (see #i25755)
715 if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
716 {
717 if (const SwFormat *pParent = rFormat.DerivedFrom())
718 {
719 if (static_cast(pParent)->IsAssignedToListLevelOfOutlineStyle())
720 {
721 SwWW8Writer::InsUInt16(*pO, NS_sprm::sprmPOutLvl);
722 pO->push_back(sal_uInt8(9));
723 SwWW8Writer::InsUInt16(*pO, NS_sprm::sprmPIlfo);
724 SwWW8Writer::InsUInt16(*pO, 0);
725
726 bRet = true;
727 }
728 }
729 }
730
731 return bRet;
732}
733
734void MSWordExportBase::OutputFormat( const SwFormat& rFormat, bool bPapFormat, bool bChpFormat, bool bFlyFormat )
735{
736 bool bCallOutSet = true;
737 const SwModify* pOldMod = m_pOutFormatNode;
738 m_pOutFormatNode = &rFormat;
739
740 switch( rFormat.Which() )
741 {
742 case RES_CONDTXTFMTCOLL:
743 case RES_TXTFMTCOLL:
744 if( bPapFormat )
745 {
746 int nLvl = MAXLEVEL;
747
748 if (static_cast(rFormat).IsAssignedToListLevelOfOutlineStyle())
749 nLvl = static_cast(rFormat).GetAssignedOutlineStyleLevel();
750
751 if (nLvl >= 0 && nLvl < MAXLEVEL)
752 {
753 //if outline numbered
754 // if Write StyleDefinition then write the OutlineRule
755 const SwNumFormat& rNFormat = m_pDoc->GetOutlineNumRule()->Get( static_cast( nLvl ) );
756 if ( m_bStyDef )
757 AttrOutput().OutlineNumbering(static_cast(nLvl));
758
759 if ( rNFormat.GetPositionAndSpaceMode() ==
760 SvxNumberFormat::LABEL_WIDTH_AND_POSITION &&
761 rNFormat.GetAbsLSpace() )
762 {
763 SfxItemSet aSet( rFormat.GetAttrSet() );
764 SvxLRSpaceItem aLR(
765 ItemGet(aSet, RES_LR_SPACE));
766
767 aLR.SetTextLeft( aLR.GetTextLeft() + rNFormat.GetAbsLSpace() );
768 aLR.SetTextFirstLineOfst( GetWordFirstLineOffset(rNFormat));
769
770 aSet.Put( aLR );
771 CorrectTabStopInSet( aSet, rNFormat.GetAbsLSpace() );
772 OutputItemSet( aSet, bPapFormat, bChpFormat,
773 i18n::ScriptType::LATIN, m_bExportModeRTF);
774 bCallOutSet = false;
775 }
776 }
777 else
778 {
779 //otherwise we might have to remove outline numbering from
780 //what gets exported if the parent style was outline numbered
781 // #i77805#
782 // If inherited outline numbering is suppress, the left/right
783 // margins has to be exported explicitly.
784 if ( m_bStyDef && DisallowInheritingOutlineNumbering(rFormat) )
785 {
786 SfxItemSet aSet( rFormat.GetAttrSet() );
787 const SvxLRSpaceItem& aLR(
788 ItemGet(aSet, RES_LR_SPACE));
789 aSet.Put( aLR );
790 OutputItemSet( aSet, bPapFormat, bChpFormat,
791 css::i18n::ScriptType::LATIN, m_bExportModeRTF);
792 bCallOutSet = false;
793 }
794 }
795 }
796 break;
797
798 case RES_CHRFMT:
799 break;
800 case RES_FLYFRMFMT:
801 if (bFlyFormat)
802 {
803 OSL_ENSURE(m_pParentFrame, "No parent frame, all broken");
804
805 if (m_pParentFrame)
806 {
807 const SwFrameFormat &rFrameFormat = m_pParentFrame->GetFrameFormat();
808
809 SfxItemSet aSet(m_pDoc->GetAttrPool(), svl::Items{});
812 aSet.Set(rFrameFormat.GetAttrSet());
813
814 // Fly as character becomes a paragraph bound
815 // now set the distance to paragraph margin
816 if (m_pFlyOffset)
817 {
818 aSet.Put(SwFormatHoriOrient(m_pFlyOffset->X()));
819 aSet.Put(SwFormatVertOrient(m_pFlyOffset->Y()));
820 SwFormatAnchor aAnchor(rFrameFormat.GetAnchor());
821 aAnchor.SetType(m_eNewAnchorType);
822 aSet.Put(aAnchor);
823 }
824
825 if (SfxItemState::SET != aSet.GetItemState(RES_SURROUND))
826 aSet.Put(SwFormatSurround(css::text::WrapTextMode_NONE));
827
828 const XFillStyleItem* pXFillStyleItem(rFrameFormat.GetAttrSet().GetItem(XATTR_FILLSTYLE));
829 if (pXFillStyleItem)
830 {
831 switch (pXFillStyleItem->GetValue())
832 {
833 case drawing::FillStyle_NONE:
834 break;
835 case drawing::FillStyle_SOLID:
836 {
837 // Construct an SvxBrushItem, as expected by the exporters.
838 aSet.Put(getSvxBrushItemFromSourceSet(rFrameFormat.GetAttrSet(), RES_BACKGROUND));
839 break;
840 }
841 default:
842 break;
843 }
844 }
845
846 m_bOutFlyFrameAttrs = true;
847 //script doesn't matter if not exporting chp
848 OutputItemSet(aSet, true, false,
849 i18n::ScriptType::LATIN, m_bExportModeRTF);
850 m_bOutFlyFrameAttrs = false;
851
852 bCallOutSet = false;
853 }
854 }
855 break;
856 case RES_FRMFMT:
857 break;
858 default:
859 OSL_ENSURE( false, "Which format is exported here?" );
860 break;
861 }
862
863 if( bCallOutSet )
864 OutputItemSet( rFormat.GetAttrSet(), bPapFormat, bChpFormat,
865 i18n::ScriptType::LATIN, m_bExportModeRTF);
866 m_pOutFormatNode = pOldMod;
867}
868
869bool MSWordExportBase::HasRefToObject( sal_uInt16 nTyp, const OUString* pName, sal_uInt16 nSeqNo )
870{
871
872 SwFieldType* pType = m_pDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::GetRef );
873 SwIterator aFormatFields( *pType );
874 for ( SwFormatField* pFormatField = aFormatFields.First(); pFormatField; pFormatField = aFormatFields.Next() )
875 {
876 const SwTextNode* pNd;
877 if ( pFormatField->GetTextField() && nTyp == pFormatField->GetField()->GetSubType() &&
878 nullptr != ( pNd = pFormatField->GetTextField()->GetpTextNode() ) &&
879 pNd->GetNodes().IsDocNodes() )
880 {
881 const SwGetRefField& rRField = *static_cast< SwGetRefField* >( pFormatField->GetField() );
882 switch ( nTyp )
883 {
884 case REF_BOOKMARK:
885 case REF_SETREFATTR:
886 if ( pName && *pName == rRField.GetSetRefName() )
887 return true;
888 break;
889 case REF_FOOTNOTE:
890 case REF_ENDNOTE:
891 if ( nSeqNo == rRField.GetSeqNo() )
892 return true;
893 break;
894 case REF_SEQUENCEFLD:
895 break; // ???
896 case REF_OUTLINE:
897 break; // ???
898 }
899 }
900 }
901
902 return false;
903}
904
905OUString MSWordExportBase::GetBookmarkName( sal_uInt16 nTyp, const OUString* pName, sal_uInt16 nSeqNo )
906{
907 OUString sRet;
908 switch ( nTyp )
909 {
910 case REF_SETREFATTR:
911 if ( pName )
912 {
913 sRet += "Ref_";
914 sRet += *pName;
915 }
916 break;
917 case REF_SEQUENCEFLD:
918 {
919 assert(pName);
920 sRet += "Ref_";
921 sRet += *pName;
922 break;
923 }
924 case REF_BOOKMARK:
925 if ( pName )
926 sRet = *pName;
927 break;
928 case REF_OUTLINE:
929 break; // ???
930 case REF_FOOTNOTE:
931 sRet += "_RefF";
932 sRet += OUString::number( nSeqNo );
933 break;
934 case REF_ENDNOTE:
935 sRet += "_RefE";
936 sRet += OUString::number( nSeqNo );
937 break;
938 }
939 return BookmarkToWord( sRet ); // #i43956# - encode bookmark accordingly
940}
941
942/* File CHRATR.HXX: */
943void WW8AttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript )
944{
945 if (bIsRTL)
946 {
947 if( m_rWW8Export.m_pDoc->GetDocumentType() != SwDoc::DOCTYPE_MSWORD )
948 {
949 m_rWW8Export.InsUInt16( NS_sprm::sprmCFBiDi );
950 m_rWW8Export.pO->push_back( sal_uInt8(1) );
951 }
952 }
953
954 // #i46087# patch from james_clark; complex texts needs the undocumented SPRM CComplexScript with param 0x81.
955 if (nScript == i18n::ScriptType::COMPLEX && !bIsRTL)
956 {
957 m_rWW8Export.InsUInt16( NS_sprm::sprmCFComplexScripts );
958 m_rWW8Export.pO->push_back( sal_uInt8(0x81) );
959 m_rWW8Export.pDop->bUseThaiLineBreakingRules = true;
960 }
961}
962
963void WW8AttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner )
964{
965 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() - (mbOnTOXEnding?2:0), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
966 mbOnTOXEnding = false;
967 m_rWW8Export.pO->clear();
968
969 if ( pTextNodeInfoInner.get() != nullptr )
970 {
971 if ( pTextNodeInfoInner->isEndOfLine() )
972 {
973 TableRowEnd( pTextNodeInfoInner->getDepth() );
974
975 SVBT16 nSty;
976 ShortToSVBT16( 0, nSty );
977 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nSty, nSty+2 ); // Style #
978 TableInfoRow( pTextNodeInfoInner );
979 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data());
980 m_rWW8Export.pO->clear();
981 }
982 }
983
984 // Clear bookmarks of the current paragraph
985 m_aBookmarksOfParagraphStart.clear();
986 m_aBookmarksOfParagraphEnd.clear();
987}
988
989void WW8AttributeOutput::StartRunProperties()
990{
991 WW8_WrPlcField* pCurrentFields = m_rWW8Export.CurrentFieldPlc();
992 m_nFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
993}
994
995void WW8AttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool /*bSingleEmptyRun*/ )
996{
997 if (pRedlineData)
998 {
999 const OUString &rComment = pRedlineData->GetComment();
1000 //Only possible to export to main text
1001 if (!rComment.isEmpty() && (m_rWW8Export.m_nTextTyp == TXT_MAINTEXT))
1002 {
1003 if (m_rWW8Export.m_pAtn->IsNewRedlineComment(pRedlineData))
1004 {
1005 m_rWW8Export.m_pAtn->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), pRedlineData );
1006 m_rWW8Export.WritePostItBegin( m_rWW8Export.pO );
1007 }
1008 }
1009 }
1010
1012 auto aRange = m_aBookmarksOfParagraphStart.equal_range(nPos);
1013 for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
1014 {
1015 GetExport().AppendBookmark(BookmarkToWord(aIter->second));
1016 }
1017}
1018
1019void WW8AttributeOutput::OnTOXEnding()
1020{
1021 mbOnTOXEnding = true;
1022}
1023
1024void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, bool bLastRun )
1025{
1027 auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nPos);
1028 for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
1029 {
1030 if(bLastRun)
1031 GetExport().AppendBookmarkEndWithCorrection(BookmarkToWord(aIter->second));
1032 else
1033 GetExport().AppendBookmark(BookmarkToWord(aIter->second));
1034 }
1035}
1036
1037void WW8AttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData )
1038{
1039 Redline( pRedlineData );
1040
1041 WW8_WrPlcField* pCurrentFields = m_rWW8Export.CurrentFieldPlc();
1042 sal_uInt16 nNewFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
1043
1044 bool bExportedFieldResult = ( m_nFieldResults != nNewFieldResults );
1045
1046 // If we have exported a field result, then we will have been forced to
1047 // split up the text into a 0x13, 0x14, 0x15 sequence with the
1048 // properties forced out at the end of the result, so the 0x15 itself
1049 // should remain clean of all other attributes to avoid #iXXXXX#
1050 if ( !bExportedFieldResult )
1051 {
1052 m_rWW8Export.m_pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(),
1053 m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1054 }
1055 m_rWW8Export.pO->clear();
1056}
1057
1058void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet )
1059{
1060 RawText(rText, eCharSet);
1061}
1062
1063void WW8AttributeOutput::RawText(const OUString& rText, rtl_TextEncoding)
1064{
1065 m_rWW8Export.OutSwString(rText, 0, rText.getLength());
1066}
1067
1068void WW8AttributeOutput::OutputFKP(bool bForce)
1069{
1070 if (!m_rWW8Export.pO->empty() || bForce)
1071 {
1072 m_rWW8Export.m_pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(),
1073 m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1074 m_rWW8Export.pO->clear();
1075 }
1076}
1077
1078void WW8AttributeOutput::ParagraphStyle( sal_uInt16 nStyle )
1079{
1080 OSL_ENSURE( m_rWW8Export.pO->empty(), " pO is not empty at line end" );
1081
1082 SVBT16 nSty;
1083 ShortToSVBT16( nStyle, nSty );
1084 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nSty, nSty+2 ); // style #
1085}
1086
1087void WW8AttributeOutput::OutputWW8Attribute( sal_uInt8 nId, bool bVal )
1088{
1089 m_rWW8Export.InsUInt16( 8 == nId ? NS_sprm::sprmCFDStrike : NS_sprm::sprmCFBold + nId );
1090
1091 m_rWW8Export.pO->push_back( bVal ? 1 : 0 );
1092}
1093
1094void WW8AttributeOutput::OutputWW8AttributeCTL( sal_uInt8 nId, bool bVal )
1095{
1096 OSL_ENSURE( nId 1)
1098 return;
1099
1100 m_rWW8Export.InsUInt16( NS_sprm::sprmCFBoldBi + nId );
1101 m_rWW8Export.pO->push_back( bVal ? 1 : 0 );
1102}
1103
1104void WW8AttributeOutput::CharFont( const SvxFontItem& rFont )
1105{
1106 sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1107
1108 m_rWW8Export.InsUInt16( NS_sprm::sprmCRgFtc0 );
1109 m_rWW8Export.InsUInt16( nFontID );
1110 m_rWW8Export.InsUInt16( NS_sprm::sprmCRgFtc2 );
1111
1112 m_rWW8Export.InsUInt16( nFontID );
1113}
1114
1115void WW8AttributeOutput::CharFontCTL( const SvxFontItem& rFont )
1116{
1117 sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1118 m_rWW8Export.InsUInt16( NS_sprm::sprmCFtcBi );
1119 m_rWW8Export.InsUInt16( nFontID );
1120}
1121
1122void WW8AttributeOutput::CharFontCJK( const SvxFontItem& rFont )
1123{
1124 sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1125 m_rWW8Export.InsUInt16( NS_sprm::sprmCRgFtc1 );
1126 m_rWW8Export.InsUInt16( nFontID );
1127}
1128
1129void WW8AttributeOutput::CharWeightCTL( const SvxWeightItem& rWeight )
1130{
1131 OutputWW8AttributeCTL( 0, WEIGHT_BOLD == rWeight.GetWeight());
1132}
1133
1134void WW8AttributeOutput::CharPostureCTL( const SvxPostureItem& rPosture )
1135{
1136 OutputWW8AttributeCTL( 1, ITALIC_NONE != rPosture.GetPosture() );
1137}
1138
1139void WW8AttributeOutput::CharPosture( const SvxPostureItem& rPosture )
1140{
1141 OutputWW8Attribute( 1, ITALIC_NONE != rPosture.GetPosture() );
1142}
1143
1144void WW8AttributeOutput::CharWeight( const SvxWeightItem& rWeight )
1145{
1146 OutputWW8Attribute( 0, WEIGHT_BOLD == rWeight.GetWeight() );
1147}
1148
1149// Shadowed and Contour are not in WW-UI. JP: ??
1150void WW8AttributeOutput::CharContour( const SvxContourItem& rContour )
1151{
1152 OutputWW8Attribute( 3, rContour.GetValue() );
1153}
1154
1155void WW8AttributeOutput::CharShadow( const SvxShadowedItem& rShadow )
1156{
1157 OutputWW8Attribute( 4, rShadow.GetValue() );
1158}
1159
1160void WW8AttributeOutput::CharKerning( const SvxKerningItem& rKerning )
1161{
1162 m_rWW8Export.InsUInt16( NS_sprm::sprmCDxaSpace );
1163
1164 m_rWW8Export.InsUInt16( rKerning.GetValue() );
1165}
1166
1167void WW8AttributeOutput::CharAutoKern( const SvxAutoKernItem& rAutoKern )
1168{
1169 m_rWW8Export.InsUInt16( NS_sprm::sprmCHpsKern );
1170
1171 m_rWW8Export.InsUInt16( rAutoKern.GetValue() ? 2 : 0 );
1172}
1173
1174void WW8AttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink )
1175{
1176 m_rWW8Export.InsUInt16( NS_sprm::sprmCSfxText );
1177 // At the moment the only animated text effect we support is blinking
1178 m_rWW8Export.pO->push_back( rBlink.GetValue() ? 2 : 0 );
1179}
1180
1181void WW8AttributeOutput::CharCrossedOut( const SvxCrossedOutItem& rCrossed )
1182{
1183 FontStrikeout eSt = rCrossed.GetStrikeout();
1184 if ( STRIKEOUT_DOUBLE == eSt )
1185 {
1186 OutputWW8Attribute( 8, true );
1187 return;
1188 }
1189 if ( STRIKEOUT_NONE != eSt )
1190 {
1191 OutputWW8Attribute( 2, true );
1192 return;
1193 }
1194
1195 // otherwise both off
1196 OutputWW8Attribute( 8, false );
1197 OutputWW8Attribute( 2, false );
1198}
1199
1200void WW8AttributeOutput::CharCaseMap( const SvxCaseMapItem& rCaseMap )
1201{
1202 SvxCaseMap eSt = rCaseMap.GetValue();
1203 switch ( eSt )
1204 {
1205 case SvxCaseMap::SmallCaps:
1206 OutputWW8Attribute( 5, true );
1207 return;
1208 case SvxCaseMap::Uppercase:
1209 OutputWW8Attribute( 6, true );
1210 return;
1211 case SvxCaseMap::Capitalize:
1212 // no such feature in word
1213 break;
1214 default:
1215 // otherwise both off
1216 OutputWW8Attribute( 5, false );
1217 OutputWW8Attribute( 6, false );
1218 return;
1219 }
1220}
1221
1222void WW8AttributeOutput::CharHidden( const SvxCharHiddenItem& rHidden )
1223{
1224 OutputWW8Attribute( 7, rHidden.GetValue() );
1225}
1226
1227void WW8AttributeOutput::CharBorder( const SvxBorderLine* pAllBorder, const sal_uInt16 /*nDist*/, const bool bShadow )
1228{
1229 WW8Export::Out_BorderLine( *m_rWW8Export.pO, pAllBorder, 0, NS_sprm::sprmCBrc80, NS_sprm::sprmCBrc, bShadow );
1230}
1231
1232void WW8AttributeOutput::CharHighlight( const SvxBrushItem& rBrush )
1233{
1234 if (rBrush.GetColor() != COL_TRANSPARENT)
1235 {
1236 sal_uInt8 nColor = msfilter::util::TransColToIco( rBrush.GetColor() );
1237 // sprmCHighlight
1238 m_rWW8Export.InsUInt16( NS_sprm::sprmCHighlight );
1239 m_rWW8Export.pO->push_back( nColor );
1240 }
1241}
1242
1243void WW8AttributeOutput::CharUnderline( const SvxUnderlineItem& rUnderline )
1244{
1245 m_rWW8Export.InsUInt16( NS_sprm::sprmCKul );
1246
1247 const SfxPoolItem* pItem = m_rWW8Export.HasItem( RES_CHRATR_WORDLINEMODE );
1248 bool bWord = false;
1249 if (pItem)
1250 bWord = static_cast(pItem)->GetValue();
1251
1252 // WW95 - parameters: 0 = none, 1 = single, 2 = by Word,
1253 // 3 = double, 4 = dotted, 5 = hidden
1254 // WW97 - additional parameters:
1255 // 6 = thick, 7 = dash, 8 = dot(not used)
1256 // 9 = dotdash 10 = dotdotdash, 11 = wave
1257 sal_uInt8 b = 0;
1258 switch ( rUnderline.GetLineStyle() )
1259 {
1260 case LINESTYLE_SINGLE:
1261 b = bWord ? 2 : 1;
1262 break;
1263 case LINESTYLE_BOLD:
1264 b = 6;
1265 break;
1266 case LINESTYLE_DOUBLE:
1267 b = 3;
1268 break;
1269 case LINESTYLE_DOTTED:
1270 b = 4;
1271 break;
1272 case LINESTYLE_DASH:
1273 b = 7;
1274 break;
1275 case LINESTYLE_DASHDOT:
1276 b = 9;
1277 break;
1278 case LINESTYLE_DASHDOTDOT:
1279 b = 10;
1280 break;
1281 case LINESTYLE_WAVE:
1282 b = 11;
1283 break;
1284 // new in WW2000
1285 case LINESTYLE_BOLDDOTTED:
1286 b = 20;
1287 break;
1288 case LINESTYLE_BOLDDASH:
1289 b = 23;
1290 break;
1291 case LINESTYLE_LONGDASH:
1292 b = 39;
1293 break;
1294 case LINESTYLE_BOLDLONGDASH:
1295 b = 55;
1296 break;
1297 case LINESTYLE_BOLDDASHDOT:
1298 b = 25;
1299 break;
1300 case LINESTYLE_BOLDDASHDOTDOT:
1301 b = 26;
1302 break;
1303 case LINESTYLE_BOLDWAVE:
1304 b = 27;
1305 break;
1306 case LINESTYLE_DOUBLEWAVE:
1307 b = 43;
1308 break;
1309 case LINESTYLE_NONE:
1310 b = 0;
1311 break;
1312 default:
1313 OSL_ENSURE( rUnderline.GetLineStyle() == LINESTYLE_NONE, "Unhandled underline type" );
1314 break;
1315 }
1316
1317 m_rWW8Export.pO->push_back( b );
1318 Color aColor = rUnderline.GetColor();
1319 if( aColor != COL_TRANSPARENT )
1320 {
1321 m_rWW8Export.InsUInt16( NS_sprm::sprmCCvUl );
1322
1323 m_rWW8Export.InsUInt32( wwUtility::RGBToBGR( aColor ) );
1324 }
1325}
1326
1327void WW8AttributeOutput::CharLanguage( const SvxLanguageItem& rLanguage )
1328{
1329 sal_uInt16 nId = 0;
1330 switch ( rLanguage.Which() )
1331 {
1332 case RES_CHRATR_LANGUAGE:
1333 nId = NS_sprm::sprmCRgLid0_80;
1334 break;
1335 case RES_CHRATR_CJK_LANGUAGE:
1336 nId = NS_sprm::sprmCRgLid1_80;
1337 break;
1338 case RES_CHRATR_CTL_LANGUAGE:
1339 nId = NS_sprm::sprmCLidBi;
1340 break;
1341 }
1342
1343 if ( nId )
1344 {
1345 // use sprmCRgLid0_80 rather than sprmCLid
1346 m_rWW8Export.InsUInt16( nId );
1347 m_rWW8Export.InsUInt16( static_cast(rLanguage.GetLanguage()) );
1348
1349 // Word 2000 and above apparently require both old and new versions of
1350 // these sprms to be set, without it spellchecking doesn't work
1351 if ( nId == NS_sprm::sprmCRgLid0_80 )
1352 {
1353 m_rWW8Export.InsUInt16( NS_sprm::sprmCRgLid0 );
1354 m_rWW8Export.InsUInt16( static_cast(rLanguage.GetLanguage()) );
1355 }
1356 else if ( nId == NS_sprm::sprmCRgLid1_80 )
1357 {
1358 m_rWW8Export.InsUInt16( NS_sprm::sprmCRgLid1 );
1359 m_rWW8Export.InsUInt16( static_cast(rLanguage.GetLanguage()) );
1360 }
1361 }
1362}
1363
1364void WW8AttributeOutput::CharEscapement( const SvxEscapementItem& rEscapement )
1365{
1366 sal_uInt8 b = 0xFF;
1367 short nEsc = rEscapement.GetEsc(), nProp = rEscapement.GetProportionalHeight();
1368 if ( !nEsc )
1369 {
1370 b = 0;
1371 nEsc = 0;
1372 nProp = 100;
1373 }
1374 else if ( DFLT_ESC_PROP == nProp )
1375 {
1376 if ( DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc )
1377 b = 2;
1378 else if ( DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc )
1379 b = 1;
1380 }
1381
1382 if ( 0xFF != b )
1383 {
1384 m_rWW8Export.InsUInt16( NS_sprm::sprmCIss );
1385
1386 m_rWW8Export.pO->push_back( b );
1387 }
1388
1389 if ( 0 == b || 0xFF == b )
1390 {
1391 long nHeight = m_rWW8Export.GetItem( RES_CHRATR_FONTSIZE ).GetHeight();
1392 m_rWW8Export.InsUInt16( NS_sprm::sprmCHpsPos );
1393
1394 m_rWW8Export.InsUInt16( static_cast(( nHeight * nEsc + 500 ) / 1000 ));
1395
1396 if( 100 != nProp || !b )
1397 {
1398 m_rWW8Export.InsUInt16( NS_sprm::sprmCHps );
1399
1400 m_rWW8Export.InsUInt16(
1401 msword_cast((nHeight * nProp + 500 ) / 1000));
1402 }
1403 }
1404}
1405
1406void WW8AttributeOutput::CharFontSize( const SvxFontHeightItem& rHeight )
1407{
1408 sal_uInt16 nId = 0;
1409 switch ( rHeight.Which() )
1410 {
1411 case RES_CHRATR_FONTSIZE:
1412 case RES_CHRATR_CJK_FONTSIZE:
1413 nId = NS_sprm::sprmCHps;
1414 break;
1415 case RES_CHRATR_CTL_FONTSIZE:
1416 nId = NS_sprm::sprmCHpsBi;
1417 break;
1418 }
1419
1420 if ( nId )
1421 {
1422 m_rWW8Export.InsUInt16( nId );
1423
1424 m_rWW8Export.InsUInt16( static_cast(( rHeight.GetHeight() + 5 ) / 10 ) );
1425 }
1426}
1427
1428void WW8AttributeOutput::CharScaleWidth( const SvxCharScaleWidthItem& rScaleWidth )
1429{
1430 m_rWW8Export.InsUInt16( NS_sprm::sprmCCharScale );
1431 m_rWW8Export.InsUInt16( rScaleWidth.GetValue() );
1432}
1433
1434void WW8AttributeOutput::CharRelief( const SvxCharReliefItem& rRelief )
1435{
1436 sal_uInt16 nId;
1437 switch ( rRelief.GetValue() )
1438 {
1439 case FontRelief::Embossed: nId = NS_sprm::sprmCFEmboss; break;
1440 case FontRelief::Engraved: nId = NS_sprm::sprmCFImprint; break;
1441 default: nId = 0; break;
1442 }
1443
1444 if( nId )
1445 {
1446 m_rWW8Export.InsUInt16( nId );
1447 m_rWW8Export.pO->push_back( sal_uInt8(0x81) );
1448 }
1449 else
1450 {
1451 // switch both flags off
1452 m_rWW8Export.InsUInt16( NS_sprm::sprmCFEmboss );
1453 m_rWW8Export.pO->push_back( sal_uInt8(0x0) );
1454 m_rWW8Export.InsUInt16( NS_sprm::sprmCFImprint );
1455 m_rWW8Export.pO->push_back( sal_uInt8(0x0) );
1456 }
1457}
1458
1459void WW8AttributeOutput::CharBidiRTL( const SfxPoolItem& rHt )
1460{
1461 const SfxInt16Item& rAttr = static_cast(rHt);
1462 if( rAttr.GetValue() == 1 )
1463 {
1464 m_rWW8Export.InsUInt16(0x85a);
1465 m_rWW8Export.pO->push_back(sal_uInt8(1));
1466 }
1467}
1468
1469void WW8AttributeOutput::CharIdctHint( const SfxPoolItem& rHt )
1470{
1471 const SfxInt16Item& rAttr = static_cast(rHt);
1472 m_rWW8Export.InsUInt16(0x286F);
1473 m_rWW8Export.pO->push_back(static_cast(rAttr.GetValue()));
1474}
1475
1476void WW8AttributeOutput::CharRotate( const SvxCharRotateItem& rRotate )
1477{
1478 // #i28331# - check that a Value is set
1479 if ( !rRotate.GetValue() )
1480 return;
1481
1482 if (!m_rWW8Export.IsInTable())
1483 {
1484 // #i36867 In word the text in a table is rotated via the TC or NS_sprm::sprmTTextFlow
1485 // This means you can only rotate all or none of the text adding NS_sprm::sprmCFELayout
1486 // here corrupts the table, hence !m_rWW8Export.bIsInTable
1487
1488 m_rWW8Export.InsUInt16( NS_sprm::sprmCFELayout );
1489 m_rWW8Export.pO->push_back( sal_uInt8(0x06) ); //len 6
1490 m_rWW8Export.pO->push_back( sal_uInt8(0x01) );
1491
1492 m_rWW8Export.InsUInt16( rRotate.IsFitToLine() ? 1 : 0 );
1493 static const sal_uInt8 aZeroArr[ 3 ] = { 0, 0, 0 };
1494 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aZeroArr, aZeroArr+3);
1495 }
1496}
1497
1498void WW8AttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisMark )
1499{
1500 sal_uInt8 nVal;
1501 const FontEmphasisMark v = rEmphasisMark.GetEmphasisMark();
1502 if (v == FontEmphasisMark::NONE)
1503 nVal = 0;
1504 else if (v == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove))
1505 nVal = 2;
1506 else if (v == (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove))
1507 nVal = 3;
1508 else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow))
1509 nVal = 4;
1510 else
1511 // case 1:
1512 nVal = 1;
1513
1514 m_rWW8Export.InsUInt16( NS_sprm::sprmCKcd );
1515 m_rWW8Export.pO->push_back( nVal );
1516}
1517
1526bool WW8Export::TransBrush(const Color& rCol, WW8_SHD& rShd)
1527{
1528 if( rCol.GetTransparency() )
1529 rShd = WW8_SHD(); // all zeros: transparent
1530 else
1531 {
1532 rShd.SetFore( 0);
1533 rShd.SetBack( msfilter::util::TransColToIco( rCol ) );
1534 rShd.SetStyle( 0 );
1535 }
1536 return !rCol.GetTransparency();
1537}
1538
1539sal_uInt32 SuitableBGColor(Color nIn)
1540{
1541 if (nIn == COL_AUTO)
1542 return 0xFF000000;
1543 return wwUtility::RGBToBGR(nIn);
1544}
1545
1546void WW8AttributeOutput::CharColor( const SvxColorItem& rColor )
1547{
1548 m_rWW8Export.InsUInt16( NS_sprm::sprmCIco );
1549
1550 sal_uInt8 nColor = msfilter::util::TransColToIco( rColor.GetValue() );
1551 m_rWW8Export.pO->push_back( nColor );
1552
1553 if (nColor)
1554 {
1555 m_rWW8Export.InsUInt16( NS_sprm::sprmCCv );
1556 m_rWW8Export.InsUInt32( wwUtility::RGBToBGR( rColor.GetValue() ) );
1557 }
1558}
1559
1560void WW8AttributeOutput::CharBackground( const SvxBrushItem& rBrush )
1561{
1562 WW8_SHD aSHD;
1563
1564 WW8Export::TransBrush( rBrush.GetColor(), aSHD );
1565 // sprmCShd80
1566 m_rWW8Export.InsUInt16( NS_sprm::sprmCShd80 );
1567 m_rWW8Export.InsUInt16( aSHD.GetValue() );
1568
1569 //Quite a few unknowns, some might be transparency or something
1570 //of that nature...
1571 m_rWW8Export.InsUInt16( NS_sprm::sprmCShd );
1572 m_rWW8Export.pO->push_back( 10 );
1573 m_rWW8Export.InsUInt32( 0xFF000000 );
1574 m_rWW8Export.InsUInt32( SuitableBGColor( rBrush.GetColor() ) );
1575 m_rWW8Export.InsUInt16( 0x0000);
1576}
1577
1578void WW8AttributeOutput::TextINetFormat( const SwFormatINetFormat& rINet )
1579{
1580 if ( !rINet.GetValue().isEmpty() )
1581 {
1582 const sal_uInt16 nId = rINet.GetINetFormatId();
1583 const OUString& rStr = rINet.GetINetFormat();
1584 if (rStr.isEmpty())
1585 {
1586 OSL_ENSURE( false, "WW8AttributeOutput::TextINetFormat(..) - missing unvisited character format at hyperlink attribute" );
1587 }
1588
1589 const SwCharFormat* pFormat = IsPoolUserFormat( nId )
1590 ? m_rWW8Export.m_pDoc->FindCharFormatByName( rStr )
1591 : m_rWW8Export.m_pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( nId );
1592
1593 m_rWW8Export.InsUInt16( NS_sprm::sprmCIstd );
1594
1595 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( pFormat ) );
1596 }
1597}
1598
1599// #i43956# - add optional parameter
1600// It's needed to write the hyperlink data for a certain cross-reference
1601// - it contains the name of the link target, which is a bookmark.
1602// add optional parameter
1603// It is needed to write an empty picture location for page number field separators
1604static void InsertSpecialChar( WW8Export& rWrt, sal_uInt8 c,
1605 OUString const * pLinkStr,
1606 bool bIncludeEmptyPicLocation = false )
1607{
1608 ww::bytes aItems;
1609 rWrt.GetCurrentItems(aItems);
1610
1611 if (c == 0x13)
1612 rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell());
1613 else
1614 rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell(), aItems.size(), aItems.data());
1615
1616 rWrt.WriteChar(c);
1617
1618 // store empty sprmCPicLocation for field separator
1619 if ( bIncludeEmptyPicLocation &&
1620 ( c == 0x13 || c == 0x14 || c == 0x15 ) )
1621 {
1622 SwWW8Writer::InsUInt16( aItems, NS_sprm::sprmCPicLocation );
1623 SwWW8Writer::InsUInt32( aItems, 0x00000000 );
1624 }
1625
1626 // #i43956# - write hyperlink data and attributes
1627 if ( c == 0x01 && pLinkStr)
1628 {
1629 // write hyperlink data to data stream
1630 SvStream& rStrm = *rWrt.pDataStrm;
1631 // position of hyperlink data
1632 const sal_uInt32 nLinkPosInDataStrm = rStrm.Tell();
1633 // write empty header
1634 const sal_uInt16 nEmptyHdrLen = 0x44;
1635 sal_uInt8 aEmptyHeader[ nEmptyHdrLen ] = { 0 };
1636 aEmptyHeader[ 4 ] = 0x44;
1637 rStrm.WriteBytes( aEmptyHeader, nEmptyHdrLen );
1638 // writer fixed header
1639 const sal_uInt16 nFixHdrLen = 0x19;
1640 sal_uInt8 const aFixHeader[ nFixHdrLen ] =
1641 {
1642 0x08, 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE,
1643 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9,
1644 0x0B, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
1645 0x00,
1646 };
1647 rStrm.WriteBytes( aFixHeader, nFixHdrLen );
1648 // write reference string including length+1
1649 sal_uInt32 nStrLen( pLinkStr->getLength() + 1 );
1650 SwWW8Writer::WriteLong( rStrm, nStrLen );
1651 SwWW8Writer::WriteString16( rStrm, *pLinkStr, false );
1652 // write additional two NULL Bytes
1653 SwWW8Writer::WriteLong( rStrm, 0 );
1654 // write length of hyperlink data
1655 const sal_uInt32 nCurrPos = rStrm.Tell();
1656 rStrm.Seek( nLinkPosInDataStrm );
1657 rStrm.WriteUInt32(nCurrPos - nLinkPosInDataStrm);
1658 rStrm.Seek( nCurrPos );
1659
1660 // write attributes of hyperlink character 0x01
1661 SwWW8Writer::InsUInt16( aItems, NS_sprm::sprmCFFldVanish );
1662 aItems.push_back( sal_uInt8(0x81) );
1663 SwWW8Writer::InsUInt16( aItems, NS_sprm::sprmCPicLocation );
1664 SwWW8Writer::InsUInt32( aItems, nLinkPosInDataStrm );
1665 SwWW8Writer::InsUInt16( aItems, NS_sprm::sprmCFData );
1666 aItems.push_back( sal_uInt8(0x01) );
1667 }
1668
1669 //Technically we should probably Remove all attribs
1670 //here for the 0x13, 0x14, 0x15, but our import
1671 //is slightly lacking
1672 //aItems.Remove(0, aItems.Count());
1673 // fSpec-Attribute true
1674 SwWW8Writer::InsUInt16( aItems, NS_sprm::sprmCFSpec );
1675 aItems.push_back( 1 );
1676
1677 rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell(), aItems.size(), aItems.data());
1678}
1679
1680static OUString lcl_GetExpandedField(const SwField &rField)
1681{
1682 OUString sRet(rField.ExpandField(true));
1683
1684 //replace LF 0x0A with VT 0x0B
1685 return sRet.replace(0x0A, 0x0B);
1686}
1687
1688WW8_WrPlcField* WW8Export::CurrentFieldPlc() const
1689{
1690 WW8_WrPlcField* pFieldP = nullptr;
1691 switch (m_nTextTyp)
1692 {
1693 case TXT_MAINTEXT:
1694 pFieldP = m_pFieldMain;
1695 break;
1696 case TXT_HDFT:
1697 pFieldP = m_pFieldHdFt;
1698 break;
1699 case TXT_FTN:
1700 pFieldP = m_pFieldFootnote;
1701 break;
1702 case TXT_EDN:
1703 pFieldP = m_pFieldEdn;
1704 break;
1705 case TXT_ATN:
1706 pFieldP = m_pFieldAtn;
1707 break;
1708 case TXT_TXTBOX:
1709 pFieldP = m_pFieldTextBxs;
1710 break;
1711 case TXT_HFTXTBOX:
1712 pFieldP = m_pFieldHFTextBxs;
1713 break;
1714 default:
1715 OSL_ENSURE( false, "what type of SubDoc is that?" );
1716 }
1717 return pFieldP;
1718}
1719
1720void WW8Export::OutputField( const SwField* pField, ww::eField eFieldType,
1721 const OUString& rFieldCmd, FieldFlags nMode )
1722{
1723 OUString sFieldCmd(rFieldCmd);
1724 switch (eFieldType)
1725 {
1726 // map fields that are not supported in WW8 as of Word 2003
1727 case ww::eBIBLIOGRPAHY:
1728 eFieldType = ww::eQUOTE;
1729 assert(rFieldCmd == FieldString(ww::eBIBLIOGRPAHY));
1730 sFieldCmd = FieldString(ww::eQUOTE);
1731 break;
1732 case ww::eCITATION:
1733 eFieldType = ww::eQUOTE;
1734 assert(rFieldCmd.trim().startsWith("CITATION"));
1735 sFieldCmd = rFieldCmd.replaceFirst(FieldString(ww::eCITATION),
1736 FieldString(ww::eQUOTE));
1737 break;
1738 default:
1739 break;
1740 }
1741
1742 assert(eFieldType (eFieldType); // add type
1754 pFieldP->Append( Fc2Cp( Strm().Tell() ), aField13 );
1755 InsertSpecialChar( *this, 0x13, nullptr, bIncludeEmptyPicLocation );
1756 }
1757 if (FieldFlags::CmdStart & nMode)
1758 {
1759 SwWW8Writer::WriteString16(Strm(), sFieldCmd, false);
1760 // #i43956# - write hyperlink character including
1761 // attributes and corresponding binary data for certain reference fields.
1762 bool bHandleBookmark = false;
1763
1764 if (pField)
1765 {
1766 if (pField->GetTyp()->Which() == SwFieldIds::GetRef &&
1767 ( eFieldType == ww::ePAGEREF || eFieldType == ww::eREF ||
1768 eFieldType == ww::eNOTEREF || eFieldType == ww::eFOOTREF ))
1769 bHandleBookmark = true;
1770 }
1771
1772 if ( bHandleBookmark )
1773 {
1774 // retrieve reference destination - the name of the bookmark
1775 OUString aLinkStr;
1776 const sal_uInt16 nSubType = pField->GetSubType();
1777 const SwGetRefField& rRField = *static_cast(pField);
1778 if ( nSubType == REF_SETREFATTR ||
1779 nSubType == REF_BOOKMARK )
1780 {
1781 const OUString& aRefName(rRField.GetSetRefName());
1782 aLinkStr = GetBookmarkName( nSubType, &aRefName, 0 );
1783 }
1784 else if ( nSubType == REF_FOOTNOTE ||
1785 nSubType == REF_ENDNOTE )
1786 {
1787 aLinkStr = GetBookmarkName( nSubType, nullptr, rRField.GetSeqNo() );
1788 }
1789 else if ( nSubType == REF_SEQUENCEFLD )
1790 {
1791 aLinkStr = pField->GetPar2();
1792 }
1793 // insert hyperlink character including attributes and data.
1794 InsertSpecialChar( *this, 0x01, &aLinkStr );
1795 }
1796 }
1797 if (FieldFlags::CmdEnd & nMode)
1798 {
1799 static const sal_uInt8 aField14[2] = { 0x14, 0xff };
1800 pFieldP->Append( Fc2Cp( Strm().Tell() ), aField14 );
1801 pFieldP->ResultAdded();
1802 InsertSpecialChar( *this, 0x14, nullptr, bIncludeEmptyPicLocation );
1803 }
1804 if (FieldFlags::End & nMode)
1805 {
1806 OUString sOut;
1807 if( pField )
1808 sOut = lcl_GetExpandedField(*pField);
1809 else
1810 sOut = sFieldCmd;
1811 if( !sOut.isEmpty() )
1812 {
1813 SwWW8Writer::WriteString16(Strm(), sOut, false);
1814
1815 if (pField)
1816 {
1817 if (pField->GetTyp()->Which() == SwFieldIds::Input &&
1818 eFieldType == ww::eFORMTEXT)
1819 {
1820 sal_uInt8 aArr[12];
1821 sal_uInt8 *pArr = aArr;
1822
1823 Set_UInt16( pArr, NS_sprm::sprmCPicLocation );
1824 Set_UInt32( pArr, 0x0 );
1825
1826 Set_UInt16( pArr, NS_sprm::sprmCFSpec );
1827 Set_UInt8( pArr, 1 );
1828
1829 Set_UInt16( pArr, NS_sprm::sprmCFNoProof );
1830 Set_UInt8( pArr, 1 );
1831
1832 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
1833 }
1834 }
1835 }
1836 }
1837 if (FieldFlags::Close & nMode)
1838 {
1839 sal_uInt8 aField15[2] = { 0x15, 0x80 };
1840
1841 if (pField)
1842 {
1843 if (pField->GetTyp()->Which() == SwFieldIds::Input &&
1844 eFieldType == ww::eFORMTEXT)
1845 {
1846 sal_uInt16 nSubType = pField->GetSubType();
1847
1848 if (nSubType == REF_SEQUENCEFLD)
1849 aField15[0] |= (0x4 Append( Fc2Cp( Strm().Tell() ), aField15 );
1854 InsertSpecialChar( *this, 0x15, nullptr, bIncludeEmptyPicLocation );
1855 }
1856}
1857
1858void WW8Export::StartCommentOutput(const OUString& rName)
1859{
1860 OUString sStr(FieldString(ww::eQUOTE));
1861 sStr += "[" + rName + "] ";
1862 OutputField(nullptr, ww::eQUOTE, sStr, FieldFlags::Start | FieldFlags::CmdStart);
1863}
1864
1865void WW8Export::EndCommentOutput(const OUString& rName)
1866{
1867 OUString sStr(" [");
1868 sStr += rName + "] ";
1869 OutputField(nullptr, ww::eQUOTE, sStr, FieldFlags::CmdEnd | FieldFlags::End |
1870 FieldFlags::Close);
1871}
1872
1873sal_uInt16 MSWordExportBase::GetId( const SwTOXType& rTOXType )
1874{
1875 std::vector::iterator it
1876 = std::find( m_aTOXArr.begin(), m_aTOXArr.end(), &rTOXType );
1877 if ( it != m_aTOXArr.end() )
1878 {
1879 return it - m_aTOXArr.begin();
1880 }
1881 m_aTOXArr.push_back( &rTOXType );
1882 return m_aTOXArr.size() - 1;
1883}
1884
1885// return values: 1 - no PageNum,
1886// 2 - TabStop before PageNum,
1887// 3 - Text before PageNum - rText hold the text
1888// 4 - no Text and no TabStop before PageNum
1889static int lcl_CheckForm( const SwForm& rForm, sal_uInt8 nLvl, OUString& rText )
1890{
1891 int nRet = 4;
1892 rText.clear();
1893
1894 // #i21237#
1895 SwFormTokens aPattern = rForm.GetPattern(nLvl);
1896 SwFormTokens::iterator aIt = aPattern.begin();
1897 FormTokenType eTType;
1898
1899 // #i61362#
1900 if (! aPattern.empty())
1901 {
1902 bool bPgNumFnd = false;
1903
1904 // #i21237#
1905 while( ++aIt != aPattern.end() && !bPgNumFnd )
1906 {
1907 eTType = aIt->eTokenType;
1908
1909 switch( eTType )
1910 {
1911 case TOKEN_PAGE_NUMS:
1912 bPgNumFnd = true;
1913 break;
1914
1915 case TOKEN_TAB_STOP:
1916 nRet = 2;
1917 break;
1918 case TOKEN_TEXT:
1919 {
1920 nRet = 3;
1921 sal_Int32 nCount = std::min(5, aIt->sText.getLength());
1922 rText = aIt->sText.copy(0, nCount); // #i21237#
1923 break;
1924 }
1925 case TOKEN_LINK_START:
1926 case TOKEN_LINK_END:
1927 break;
1928
1929 default:
1930 nRet = 4;
1931 break;
1932 }
1933 }
1934
1935 if( !bPgNumFnd )
1936 nRet = 1;
1937 }
1938
1939 return nRet;
1940}
1941
1942static bool lcl_IsHyperlinked(const SwForm& rForm, sal_uInt16 nTOXLvl)
1943{
1944 bool bRes = false;
1945 for (sal_uInt16 nI = 1; nI < nTOXLvl; ++nI)
1946 {
1947 // #i21237#
1948 SwFormTokens aPattern = rForm.GetPattern(nI);
1949
1950 if ( !aPattern.empty() )
1951 {
1952 SwFormTokens::iterator aIt = aPattern.begin();
1953
1954 FormTokenType eTType;
1955
1956 // #i21237#
1957 while ( ++aIt != aPattern.end() )
1958 {
1959 eTType = aIt->eTokenType;
1960 switch (eTType)
1961 {
1962 case TOKEN_LINK_START:
1963 case TOKEN_LINK_END:
1964 bRes = true;
1965 break;
1966 default:
1967 ;
1968 }
1969 }
1970 }
1971 }
1972 return bRes;
1973}
1974
1975void AttributeOutputBase::GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter)
1976{
1977 if(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF) // Not implemented for RTF
1978 return;
1979
1980 if (const SwpHints* pTextAttrs = rNode.GetpSwpHints())
1981 {
1982 for( size_t i = 0; i < pTextAttrs->Count(); ++i )
1983 {
1984 const SwTextAttr* pHt = pTextAttrs->Get(i);
1985 if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
1986 {
1987 const SwFormatField& rField = static_cast(pHt->GetAttr());
1988 const SwField* pField = rField.GetField();
1989 // Need to have bookmarks only for sequence fields
1990 if (pField && pField->GetTyp()->Which() == SwFieldIds::SetExp && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
1991 {
1992 const sal_uInt16 nSeqFieldNumber = static_cast(pField)->GetSeqNumber();
1993 const OUString sObjectName = static_cast(pField->GetTyp())->GetName();
1994 const SwFieldTypes* pFieldTypes = GetExport().m_pDoc->getIDocumentFieldsAccess().GetFieldTypes();
1995 bool bHaveFullBkm = false;
1996 bool bHaveLabelAndNumberBkm = false;
1997 bool bHaveCaptionOnlyBkm = false;
1998 bool bHaveNumberOnlyBkm = false;
1999 bool bRunSplittedAtSep = false;
2000 for( auto pFieldType : *pFieldTypes )
2001 {
2002 if( SwFieldIds::GetRef == pFieldType->Which() )
2003 {
2004 SwIterator aIter( *pFieldType );
2005 for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
2006 {
2007 SwGetRefField* pRefField = static_cast(pFormatField->GetField());
2008 // If we have a reference to the current sequence field
2009 if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
2010 {
2011 // Need to create a separate run for separator character
2012 SwWW8AttrIter aLocalAttrIter( GetExport(), rNode ); // We need a local iterator having the right number of runs
2013 const OUString aText = rNode.GetText();
2014 const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
2015 const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
2016 bool bCategoryFirst = nCategoryStart < pHt->GetStart();
2017 sal_Int32 nSeparatorPos = 0;
2018 if (bCategoryFirst)
2019 {
2020 nSeparatorPos = aLocalAttrIter.WhereNext();
2021 while (nSeparatorPos GetSetRefName().getLength();
2030 }
2031 sal_Int32 nRefTextPos = 0;
2032 if(nSeparatorPos < aText.getLength())
2033 {
2034 nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), *GetExport().m_pDoc, nSeparatorPos);
2035 if(nRefTextPos != nSeparatorPos)
2036 {
2037 if(!bRunSplittedAtSep)
2038 {
2039 if(!bCategoryFirst)
2040 rAttrIter.SplitRun(nSeparatorPos);
2041 rAttrIter.SplitRun(nRefTextPos);
2042 bRunSplittedAtSep = true;
2043 }
2044 if(!bCategoryFirst)
2045 aLocalAttrIter.SplitRun(nSeparatorPos);
2046 aLocalAttrIter.SplitRun(nRefTextPos);
2047 }
2048 else if (bCategoryFirst)
2049 {
2050 if(!bRunSplittedAtSep)
2051 {
2052
Recommended