1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <hintids.hxx>
21 #include <vcl/font.hxx>
22 #include <editeng/langitem.hxx>
25 #include <numrule.hxx>
26 #include <charfmt.hxx>
27 #include <com/sun/star/i18n/ScriptType.hpp>
29 #include "sprmids.hxx"
31 #include "ww8attributeoutput.hxx"
32 #include "writerhelper.hxx"
33 #include "writerwordglue.hxx"
39 using namespace ::com::sun::star
;
40 using namespace sw::types
;
41 using namespace sw::util
;
43 SwNumRule
* MSWordExportBase::DuplicateNumRuleImpl(const SwNumRule
*pRule
)
45 const OUString
sPrefix("WW8TempExport" + OUString::number( m_nUniqueList
++ ));
46 SwNumRule
* pMyNumRule
=
47 new SwNumRule( m_rDoc
.GetUniqueNumRuleName( &sPrefix
),
48 SvxNumberFormat::LABEL_WIDTH_AND_POSITION
);
49 m_pUsedNumTable
->push_back( pMyNumRule
);
51 for ( sal_uInt16 i
= 0; i
< MAXLEVEL
; i
++ )
53 const SwNumFormat
& rSubRule
= pRule
->Get(i
);
54 pMyNumRule
->Set( i
, rSubRule
);
59 sal_uInt16
MSWordExportBase::DuplicateNumRule(const SwNumRule
* pRule
, sal_uInt8 nLevel
, sal_uInt16 nVal
)
61 SwNumRule
* const pMyNumRule
= DuplicateNumRuleImpl(pRule
);
63 SwNumFormat
aNumFormat(pMyNumRule
->Get(nLevel
));
64 aNumFormat
.SetStart(nVal
);
65 pMyNumRule
->Set(nLevel
, aNumFormat
);
67 return GetNumberingId(*pMyNumRule
);
70 // multiple SwList can be based on the same SwNumRule; ensure one w:abstractNum
72 sal_uInt16
MSWordExportBase::DuplicateAbsNum(OUString
const& rListId
,
73 SwNumRule
const& rAbstractRule
)
75 auto const it(m_Lists
.find(rListId
));
76 if (it
!= m_Lists
.end())
82 auto const pNewAbstractRule
= DuplicateNumRuleImpl(&rAbstractRule
);
83 assert(GetNumberingId(*pNewAbstractRule
) == m_pUsedNumTable
->size() - 1);
84 (void) pNewAbstractRule
;
85 m_Lists
.insert(std::make_pair(rListId
, m_pUsedNumTable
->size() - 1));
86 return m_pUsedNumTable
->size() - 1;
90 // Ideally we want to map SwList to w:abstractNum and SwNumRule to w:num
91 // The current approach is to keep exporting every SwNumRule to
92 // 1 w:abstractNum and 1 w:num, and then add extra w:num via this function
93 // that reference an existing w:abstractNum and may override its formatting;
94 // of course this will end up exporting some w:num that aren't actually used.
95 sal_uInt16
MSWordExportBase::OverrideNumRule(
96 SwNumRule
const& rExistingRule
,
97 OUString
const& rListId
,
98 SwNumRule
const& rAbstractRule
)
100 const sal_uInt16 numdef
= GetNumberingId(rExistingRule
);
102 const sal_uInt16 absnumdef
= rListId
== rAbstractRule
.GetDefaultListId()
103 ? GetNumberingId(rAbstractRule
)
104 : DuplicateAbsNum(rListId
, rAbstractRule
);
105 assert(numdef
!= USHRT_MAX
);
106 assert(absnumdef
!= USHRT_MAX
);
107 auto const mapping
= std::make_pair(numdef
, absnumdef
);
109 auto it
= m_OverridingNums
.insert(std::make_pair(m_pUsedNumTable
->size(), mapping
));
111 m_pUsedNumTable
->push_back(nullptr); // dummy, it's unique_ptr...
112 ++m_nUniqueList
; // counter for DuplicateNumRule...
114 return it
.first
->first
;
117 void MSWordExportBase::AddListLevelOverride(sal_uInt16 nListId
,
118 sal_uInt16 nLevelNum
,
121 m_ListLevelOverrides
[nListId
][nLevelNum
] = nStartAt
;
124 sal_uInt16
MSWordExportBase::GetNumberingId( const SwNumRule
& rNumRule
)
126 if ( !m_pUsedNumTable
)
128 m_pUsedNumTable
.reset(new SwNumRuleTable
);
129 m_pUsedNumTable
->insert( m_pUsedNumTable
->begin(), m_rDoc
.GetNumRuleTable().begin(), m_rDoc
.GetNumRuleTable().end() );
130 // Check, if the outline rule is already inserted into <pUsedNumTable>.
131 // If yes, do not insert it again.
132 bool bOutlineRuleAdded( false );
133 for ( sal_uInt16 n
= m_pUsedNumTable
->size(); n
; )
135 const SwNumRule
& rRule
= *(*m_pUsedNumTable
)[ --n
];
136 if (!m_rDoc
.IsUsed(rRule
))
138 m_pUsedNumTable
->erase( m_pUsedNumTable
->begin() + n
);
140 else if ( &rRule
== m_rDoc
.GetOutlineNumRule() )
142 bOutlineRuleAdded
= true;
146 if ( !bOutlineRuleAdded
)
148 // still need to paste the OutlineRule
149 SwNumRule
* pR
= m_rDoc
.GetOutlineNumRule();
150 m_pUsedNumTable
->push_back( pR
);
153 SwNumRule
* p
= const_cast<SwNumRule
*>(&rNumRule
);
154 sal_uInt16 nRet
= o3tl::narrowing
<sal_uInt16
>(m_pUsedNumTable
->GetPos(p
));
159 // GetFirstLineOffset should problem never appear unadorned apart from
160 // here in the ww export filter
161 sal_Int16
GetWordFirstLineOffset(const SwNumFormat
&rFormat
)
163 OSL_ENSURE( rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
,
164 "<GetWordFirstLineOffset> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
166 short nFirstLineOffset
;
167 if (rFormat
.GetNumAdjust() == SvxAdjust::Right
)
168 nFirstLineOffset
= -rFormat
.GetCharTextDistance();
170 nFirstLineOffset
= rFormat
.GetFirstLineOffset(); //TODO: overflow
171 return nFirstLineOffset
;
174 void WW8Export::WriteNumbering()
176 if ( !m_pUsedNumTable
)
177 return; // no numbering is used
179 // list formats - LSTF
180 pFib
->m_fcPlcfLst
= pTableStrm
->Tell();
181 pTableStrm
->WriteUInt16( m_pUsedNumTable
->size() );
182 NumberingDefinitions();
184 pFib
->m_lcbPlcfLst
= pTableStrm
->Tell() - pFib
->m_fcPlcfLst
;
186 // list formats - LVLF
187 AbstractNumberingDefinitions();
189 // list formats - LFO
190 OutOverrideListTab();
192 // list formats - ListNames
196 void WW8AttributeOutput::NumberingDefinition( sal_uInt16 nId
, const SwNumRule
&rRule
)
198 m_rWW8Export
.pTableStrm
->WriteUInt32( nId
);
199 m_rWW8Export
.pTableStrm
->WriteUInt32( nId
);
201 // not associated with a Style
202 for ( int i
= 0; i
< WW8ListManager::nMaxLevel
; ++i
)
203 m_rWW8Export
.pTableStrm
->WriteUInt16( 0xFFF );
205 sal_uInt8 nFlags
= 0;
206 if ( rRule
.IsContinusNum() )
209 m_rWW8Export
.pTableStrm
->WriteUChar( nFlags
).WriteUChar( 0/*nDummy*/ );
212 void MSWordExportBase::NumberingDefinitions()
214 if ( !m_pUsedNumTable
)
215 return; // no numbering is used
217 sal_uInt16 nCount
= m_pUsedNumTable
->size();
219 // Write static data of SwNumRule - LSTF
220 for ( sal_uInt16 n
= 0; n
< nCount
; ++n
)
222 const SwNumRule
* pRule
= (*m_pUsedNumTable
)[ n
];
225 AttrOutput().NumberingDefinition(n
+ 1, *pRule
);
229 auto it
= m_OverridingNums
.find(n
);
230 assert(it
!= m_OverridingNums
.end());
231 pRule
= (*m_pUsedNumTable
)[it
->second
.first
];
233 AttrOutput().OverrideNumberingDefinition(*pRule
, n
+ 1, it
->second
.second
+ 1, m_ListLevelOverrides
[n
]);
239 * Converts the SVX numbering type to MSONFC.
241 * This is used for special paragraph numbering considerations.
243 static sal_uInt8
GetLevelNFC(sal_uInt16 eNumType
, const SfxItemSet
* pOutSet
, sal_uInt8 nDefault
)
245 sal_uInt8 nRet
= nDefault
;
248 case SVX_NUM_NUMBER_LOWER_ZH
:
251 const SvxLanguageItem
& rLang
= pOutSet
->Get( RES_CHRATR_CJK_LANGUAGE
);
252 const LanguageType eLang
= rLang
.GetLanguage();
253 if (LANGUAGE_CHINESE_SIMPLIFIED
==eLang
) {
259 // LVLF can't contain 0x08, msonfcHex.
260 case style::NumberingType::SYMBOL_CHICAGO
:
261 // No SVX_NUM_SYMBOL_CHICAGO here: LVLF can't contain 0x09, msonfcChiManSty.
264 // LVLF can't contain 0x0F / 15, msonfcSbChar / decimalHalfWidth.
265 // LVLF can't contain 0x13 / 19, msonfcDArabic / decimalFullWidth2
271 void WW8AttributeOutput::NumberingLevel( sal_uInt8
/*nLevel*/,
273 sal_uInt16 nNumberingType
,
275 const sal_uInt8
*pNumLvlPos
,
278 const SfxItemSet
*pOutSet
,
280 sal_Int16 nFirstLineIndex
,
281 sal_Int16 nListTabPos
,
282 const OUString
&rNumberingString
,
283 const SvxBrushItem
* pBrush
//For i120928,to transfer graphic of bullet
287 m_rWW8Export
.pTableStrm
->WriteUInt32( nStart
);
290 sal_uInt8 nNumId
= GetLevelNFC(nNumberingType
, pOutSet
, WW8Export::GetNumId(nNumberingType
));
291 m_rWW8Export
.pTableStrm
->WriteUChar(nNumId
);
297 case SvxAdjust::Center
:
300 case SvxAdjust::Right
:
307 m_rWW8Export
.pTableStrm
->WriteUChar( nAlign
);
309 // Write the rgbxchNums[9], positions of placeholders for paragraph
310 // numbers in the text
311 m_rWW8Export
.pTableStrm
->WriteBytes(pNumLvlPos
, WW8ListManager::nMaxLevel
);
313 // Type of the character between the bullet and the text
314 m_rWW8Export
.pTableStrm
->WriteUChar( nFollow
);
316 // dxaSoace/dxaIndent (Word 6 compatibility)
317 m_rWW8Export
.pTableStrm
->WriteUInt32( 0 );
318 m_rWW8Export
.pTableStrm
->WriteUInt32( 0 );
321 std::unique_ptr
<ww::bytes
> pCharAtrs
;
324 std::unique_ptr
<ww::bytes
> pOldpO
= std::move(m_rWW8Export
.pO
);
325 m_rWW8Export
.pO
.reset(new ww::bytes
);
328 sal_uInt16 nFontID
= m_rWW8Export
.m_aFontHelper
.GetId( *pFont
);
330 m_rWW8Export
.InsUInt16( NS_sprm::CRgFtc0::val
);
331 m_rWW8Export
.InsUInt16( nFontID
);
332 m_rWW8Export
.InsUInt16( NS_sprm::CRgFtc2::val
);
333 m_rWW8Export
.InsUInt16( nFontID
);
336 m_rWW8Export
.OutputItemSet( *pOutSet
, false, true, i18n::ScriptType::LATIN
, m_rWW8Export
.m_bExportModeRTF
);
337 //For i120928,achieve graphic's index of bullet from the bullet bookmark
338 if (SVX_NUM_BITMAP
== nNumberingType
&& pBrush
)
340 int nIndex
= m_rWW8Export
.GetGrfIndex(*pBrush
);
343 m_rWW8Export
.InsUInt16(NS_sprm::CPbiIBullet::val
);
344 m_rWW8Export
.InsUInt32(nIndex
);
345 m_rWW8Export
.InsUInt16(NS_sprm::CPbiGrf::val
);
346 m_rWW8Export
.InsUInt16(1);
350 pCharAtrs
= std::move(m_rWW8Export
.pO
);
351 m_rWW8Export
.pO
= std::move(pOldpO
);
353 m_rWW8Export
.pTableStrm
->WriteUChar(sal_uInt8(pCharAtrs
? pCharAtrs
->size() : 0));
356 sal_uInt8 aPapSprms
[] = {
357 0x5e, 0x84, 0, 0, // sprmPDxaLeft
358 0x60, 0x84, 0, 0, // sprmPDxaLeft1
359 0x15, 0xc6, 0x05, 0x00, 0x01, 0, 0, 0x06
361 m_rWW8Export
.pTableStrm
->WriteUChar( sal_uInt8( sizeof( aPapSprms
) ) );
364 m_rWW8Export
.pTableStrm
->WriteUInt16( 0 );
367 sal_uInt8
* pData
= aPapSprms
+ 2;
368 Set_UInt16( pData
, nIndentAt
);
370 Set_UInt16( pData
, nFirstLineIndex
);
372 Set_UInt16( pData
, nListTabPos
);
374 m_rWW8Export
.pTableStrm
->WriteBytes(aPapSprms
, sizeof(aPapSprms
));
377 if (pCharAtrs
&& !pCharAtrs
->empty())
378 m_rWW8Export
.pTableStrm
->WriteBytes(pCharAtrs
->data(), pCharAtrs
->size());
380 // write the num string
381 m_rWW8Export
.pTableStrm
->WriteUInt16( rNumberingString
.getLength() );
382 SwWW8Writer::WriteString16( *m_rWW8Export
.pTableStrm
, rNumberingString
, false );
385 void MSWordExportBase::AbstractNumberingDefinitions()
387 sal_uInt16 nCount
= m_pUsedNumTable
->size();
390 for( n
= 0; n
< nCount
; ++n
)
392 if (nullptr == (*m_pUsedNumTable
)[ n
])
397 AttrOutput().StartAbstractNumbering( n
+ 1 );
399 const SwNumRule
& rRule
= *(*m_pUsedNumTable
)[ n
];
401 sal_uInt8 nLevels
= static_cast< sal_uInt8
>(rRule
.IsContinusNum() ?
402 WW8ListManager::nMinLevel
: WW8ListManager::nMaxLevel
);
403 for( nLvl
= 0; nLvl
< nLevels
; ++nLvl
)
405 NumberingLevel(rRule
, nLvl
);
408 AttrOutput().EndAbstractNumbering();
412 void MSWordExportBase::NumberingLevel(
413 SwNumRule
const& rRule
, sal_uInt8
const nLvl
)
415 // prepare the NodeNum to generate the NumString
416 static const SwNumberTree::tNumberVector aNumVector
= [] {
417 SwNumberTree::tNumberVector
vec(WW8ListManager::nMaxLevel
);
418 std::iota(vec
.begin(), vec
.end(), 0);
422 // write the static data of the SwNumFormat of this level
423 sal_uInt8 aNumLvlPos
[WW8ListManager::nMaxLevel
] = { 0,0,0,0,0,0,0,0,0 };
425 const SwNumFormat
& rFormat
= rRule
.Get( nLvl
);
427 sal_uInt8 nFollow
= 0;
429 if (rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
431 // <nFollow = 2>, if minimum label width equals 0 and
432 // minimum distance between label and text equals 0
433 nFollow
= (rFormat
.GetFirstLineOffset() == 0 &&
434 rFormat
.GetCharTextDistance() == 0)
435 ? 2 : 0; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
437 else if (rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
439 switch (rFormat
.GetLabelFollowedBy())
441 case SvxNumberFormat::LISTTAB
:
443 // 0 (tab) unless there would be no content before the tab, in which case 2 (nothing)
444 nFollow
= (SVX_NUM_NUMBER_NONE
!= rFormat
.GetNumberingType()) ? 0 : 2;
447 case SvxNumberFormat::SPACE
:
449 // 1 (space) unless there would be no content before the space in which case 2 (nothing)
450 nFollow
= (SVX_NUM_NUMBER_NONE
!= rFormat
.GetNumberingType()) ? 1 : 2;
453 case SvxNumberFormat::NOTHING
:
461 OSL_FAIL( "unknown GetLabelFollowedBy() return value" );
466 // Build the NumString for this Level
469 bool bWriteBullet
= false;
470 const vcl::Font
* pBulletFont
=nullptr;
471 rtl_TextEncoding eChrSet
=0;
472 FontFamily eFamily
=FAMILY_DECORATIVE
;
473 if (SVX_NUM_CHAR_SPECIAL
== rFormat
.GetNumberingType() ||
474 SVX_NUM_BITMAP
== rFormat
.GetNumberingType())
477 sal_UCS4 cBullet
= rFormat
.GetBulletChar();
478 sNumStr
= OUString(&cBullet
, 1);
482 // Create level string
483 // For docx it is not the best way: we can just take it from rRule.Get(nLvl).GetListFormat()
484 // But for compatibility with doc we follow same routine
485 if (SVX_NUM_NUMBER_NONE
!= rFormat
.GetNumberingType())
487 sal_uInt8
* pLvlPos
= aNumLvlPos
;
488 // the numbering string has to be restrict
489 // to the level currently working on.
490 sNumStr
= rRule
.MakeNumString(aNumVector
, false, true, nLvl
);
492 // now search the nums in the string
493 for (sal_uInt8 i
= 0; i
<= nLvl
; ++i
)
495 OUString
sSrch(OUString::number(i
));
496 sal_Int32 nFnd
= sNumStr
.indexOf(sSrch
);
499 *pLvlPos
= static_cast<sal_uInt8
>(nFnd
+ 1);
501 sNumStr
= sNumStr
.replaceAt(nFnd
, 1, OUString(static_cast<char>(i
)));
506 if (!rRule
.Get(nLvl
).HasListFormat())
508 if (!rFormat
.GetPrefix().isEmpty())
509 sNumStr
= rFormat
.GetPrefix() + sNumStr
;
510 sNumStr
+= rFormat
.GetSuffix();
514 if (SVX_NUM_CHAR_SPECIAL
== rFormat
.GetNumberingType() ||
515 SVX_NUM_BITMAP
== rFormat
.GetNumberingType())
519 pBulletFont
= rFormat
.GetBulletFont();
522 pBulletFont
= &numfunc::GetDefBulletFont();
525 eChrSet
= pBulletFont
->GetCharSet();
526 sFontName
= pBulletFont
->GetFamilyName();
527 eFamily
= pBulletFont
->GetFamilyType();
529 if (IsStarSymbol(sFontName
))
530 SubstituteBullet(sNumStr
, eChrSet
, sFontName
);
533 // Attributes of the numbering
534 std::unique_ptr
<wwFont
> pPseudoFont
;
535 const SfxItemSet
* pOutSet
= nullptr;
538 SfxItemSet
aSet( m_rDoc
.GetAttrPool(), svl::Items
<RES_CHRATR_BEGIN
,
540 if (rFormat
.GetCharFormat() || bWriteBullet
)
546 if (rFormat
.GetCharFormat())
547 aSet
.Put( rFormat
.GetCharFormat()->GetAttrSet() );
548 aSet
.ClearItem( RES_CHRATR_CJK_FONT
);
549 aSet
.ClearItem( RES_CHRATR_FONT
);
551 if (sFontName
.isEmpty())
552 sFontName
= pBulletFont
->GetFamilyName();
554 pPseudoFont
.reset(new wwFont( sFontName
, pBulletFont
->GetPitch(),
558 pOutSet
= &rFormat
.GetCharFormat()->GetAttrSet();
561 sal_Int16 nIndentAt
= 0;
562 sal_Int16 nFirstLineIndex
= 0;
563 sal_Int16 nListTabPos
= -1;
566 if (rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
)
568 nIndentAt
= nListTabPos
= rFormat
.GetAbsLSpace(); //TODO: overflow
569 nFirstLineIndex
= GetWordFirstLineOffset(rFormat
);
571 else if (rFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
573 nIndentAt
= static_cast<sal_Int16
>(rFormat
.GetIndentAt());
574 nFirstLineIndex
= static_cast<sal_Int16
>(rFormat
.GetFirstLineIndent());
575 nListTabPos
= rFormat
.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB
?
576 static_cast<sal_Int16
>( rFormat
.GetListtabPos() ) : 0;
579 AttrOutput().NumberingLevel( nLvl
,
581 rFormat
.GetNumberingType(),
582 rFormat
.GetNumAdjust(),
585 pPseudoFont
.get(), pOutSet
,
586 nIndentAt
, nFirstLineIndex
, nListTabPos
,
588 rFormat
.GetNumberingType()==SVX_NUM_BITMAP
? rFormat
.GetBrush() : nullptr);
591 void WW8Export::OutOverrideListTab()
593 if( !m_pUsedNumTable
)
594 return ; // no numbering is used
596 // write the "list format override" - LFO
597 sal_uInt16 nCount
= m_pUsedNumTable
->size();
600 pFib
->m_fcPlfLfo
= pTableStrm
->Tell();
601 pTableStrm
->WriteUInt32( nCount
);
603 // LFO ([MS-DOC] 2.9.131)
604 for( n
= 0; n
< nCount
; ++n
)
606 pTableStrm
->WriteUInt32( n
+ 1 );
607 SwWW8Writer::FillCount( *pTableStrm
, 12 );
609 // LFOData ([MS-DOC] 2.9.132)
610 for( n
= 0; n
< nCount
; ++n
)
611 pTableStrm
->WriteInt32( -1 ); // no overwrite
614 pFib
->m_lcbPlfLfo
= pTableStrm
->Tell() - pFib
->m_fcPlfLfo
;
617 void WW8Export::OutListNamesTab()
619 if( !m_pUsedNumTable
)
620 return ; // no numbering is used
622 // write the "list format override" - LFO
623 sal_uInt16 nNms
= 0, nCount
= m_pUsedNumTable
->size();
625 pFib
->m_fcSttbListNames
= pTableStrm
->Tell();
626 pTableStrm
->WriteInt16( -1 );
627 pTableStrm
->WriteUInt32( nCount
);
629 for( ; nNms
< nCount
; ++nNms
)
631 const SwNumRule
& rRule
= *(*m_pUsedNumTable
)[ nNms
];
633 if( !rRule
.IsAutoRule() )
634 sNm
= rRule
.GetName();
636 pTableStrm
->WriteUInt16( sNm
.getLength() );
638 SwWW8Writer::WriteString16(*pTableStrm
, sNm
, false);
641 SwWW8Writer::WriteLong( *pTableStrm
, pFib
->m_fcSttbListNames
+ 2, nNms
);
643 pFib
->m_lcbSttbListNames
= pTableStrm
->Tell() - pFib
->m_fcSttbListNames
;
646 void MSWordExportBase::SubstituteBullet( OUString
& rNumStr
,
647 rtl_TextEncoding
& rChrSet
, OUString
& rFontName
) const
649 if (!m_bSubstituteBullets
)
651 OUString sFontName
= rFontName
;
653 // If Bullet char is "", don't change
654 if (rNumStr
[0] != u
'\0')
656 rNumStr
= rNumStr
.replaceAt(0, 1, OUString(
657 msfilter::util::bestFitOpenSymbolToMSFont(rNumStr
[0], rChrSet
, sFontName
)));
660 rFontName
= sFontName
;
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */