Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <hintids.hxx>
21 : #include <vcl/font.hxx>
22 : #include <editeng/fontitem.hxx>
23 : #include <editeng/lrspitem.hxx>
24 : #include <editeng/langitem.hxx>
25 : #include <doc.hxx>
26 : #include <docary.hxx>
27 : #include <numrule.hxx>
28 : #include <paratr.hxx>
29 : #include <charfmt.hxx>
30 : #include <ndtxt.hxx>
31 : #include <unotools/fontcfg.hxx>
32 : #include <com/sun/star/i18n/ScriptType.hpp>
33 :
34 : #include <sprmids.hxx>
35 :
36 : #include "ww8attributeoutput.hxx"
37 : #include "writerhelper.hxx"
38 : #include "writerwordglue.hxx"
39 : #include "wrtww8.hxx"
40 : #include "ww8par.hxx"
41 :
42 : using namespace ::com::sun::star;
43 : using namespace sw::types;
44 : using namespace sw::util;
45 :
46 6 : sal_uInt16 MSWordExportBase::DuplicateNumRule( const SwNumRule *pRule, sal_uInt8 nLevel, sal_uInt16 nVal )
47 : {
48 6 : sal_uInt16 nNumId = USHRT_MAX;
49 6 : const OUString sPrefix("WW8TempExport" + OUString::number( m_nUniqueList++ ));
50 : SwNumRule* pMyNumRule =
51 : new SwNumRule( m_pDoc->GetUniqueNumRuleName( &sPrefix ),
52 6 : SvxNumberFormat::LABEL_WIDTH_AND_POSITION );
53 6 : m_pUsedNumTable->push_back( pMyNumRule );
54 :
55 66 : for ( sal_uInt16 i = 0; i < MAXLEVEL; i++ )
56 : {
57 60 : const SwNumFormat& rSubRule = pRule->Get(i);
58 60 : pMyNumRule->Set( i, rSubRule );
59 : }
60 :
61 12 : SwNumFormat aNumFormat( pMyNumRule->Get( nLevel ) );
62 6 : aNumFormat.SetStart( nVal );
63 6 : pMyNumRule->Set( nLevel, aNumFormat );
64 :
65 6 : nNumId = GetId( *pMyNumRule );
66 :
67 : // Map the old list to our new list
68 6 : m_aRuleDuplicates[GetId( *pRule )] = nNumId;
69 :
70 12 : return nNumId;
71 : }
72 :
73 1407 : sal_uInt16 MSWordExportBase::GetId( const SwNumRule& rNumRule )
74 : {
75 1407 : if ( !m_pUsedNumTable )
76 : {
77 87 : m_pUsedNumTable = new SwNumRuleTable;
78 87 : m_pUsedNumTable->insert( m_pUsedNumTable->begin(), m_pDoc->GetNumRuleTable().begin(), m_pDoc->GetNumRuleTable().end() );
79 : // Check, if the outline rule is already inserted into <pUsedNumTable>.
80 : // If yes, do not insert it again.
81 87 : bool bOutlineRuleAdded( false );
82 1172 : for ( sal_uInt16 n = m_pUsedNumTable->size(); n; )
83 : {
84 998 : const SwNumRule& rRule = *(*m_pUsedNumTable)[ --n ];
85 998 : if ( !SwDoc::IsUsed( rRule ) )
86 : {
87 856 : m_pUsedNumTable->erase( m_pUsedNumTable->begin() + n );
88 : }
89 142 : else if ( &rRule == m_pDoc->GetOutlineNumRule() )
90 : {
91 36 : bOutlineRuleAdded = true;
92 : }
93 : }
94 :
95 87 : if ( !bOutlineRuleAdded )
96 : {
97 : // still need to paste the OutlineRule
98 51 : SwNumRule* pR = m_pDoc->GetOutlineNumRule();
99 51 : m_pUsedNumTable->push_back( pR );
100 : }
101 : }
102 1407 : SwNumRule* p = const_cast<SwNumRule*>(&rNumRule);
103 1407 : sal_uInt16 nRet = static_cast<sal_uInt16>(m_pUsedNumTable->GetPos(p));
104 :
105 : // Is this list now duplicated into a new list which we should use
106 : // #i77812# - perform 'deep' search in duplication map
107 1407 : ::std::map<sal_uInt16,sal_uInt16>::const_iterator aResult = m_aRuleDuplicates.end();
108 2950 : do {
109 1475 : aResult = m_aRuleDuplicates.find(nRet);
110 1475 : if ( aResult != m_aRuleDuplicates.end() )
111 : {
112 68 : nRet = (*aResult).second;
113 : }
114 2950 : } while ( aResult != m_aRuleDuplicates.end() );
115 :
116 1407 : return nRet;
117 : }
118 :
119 : // GetFirstLineOffset should problem never appear unadorned apart from
120 : // here in the ww export filter
121 518 : sal_Int16 GetWordFirstLineOffset(const SwNumFormat &rFormat)
122 : {
123 : OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
124 : "<GetWordFirstLineOffset> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
125 :
126 : short nFirstLineOffset;
127 518 : if (rFormat.GetNumAdjust() == SVX_ADJUST_RIGHT)
128 0 : nFirstLineOffset = -rFormat.GetCharTextDistance();
129 : else
130 518 : nFirstLineOffset = rFormat.GetFirstLineOffset();
131 518 : return nFirstLineOffset;
132 : }
133 :
134 32 : void WW8Export::WriteNumbering()
135 : {
136 32 : if ( !m_pUsedNumTable )
137 53 : return; // no numbering is used
138 :
139 : // list formats - LSTF
140 11 : pFib->fcPlcfLst = pTableStrm->Tell();
141 11 : SwWW8Writer::WriteShort( *pTableStrm, m_pUsedNumTable->size() );
142 11 : NumberingDefinitions();
143 : // set len to FIB
144 11 : pFib->lcbPlcfLst = pTableStrm->Tell() - pFib->fcPlcfLst;
145 :
146 : // list formats - LVLF
147 11 : AbstractNumberingDefinitions();
148 :
149 : // list formats - LFO
150 11 : OutOverrideListTab();
151 :
152 : // list formats - ListNames
153 11 : OutListNamesTab();
154 : }
155 :
156 21 : void WW8AttributeOutput::NumberingDefinition( sal_uInt16 nId, const SwNumRule &rRule )
157 : {
158 21 : SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, nId );
159 21 : SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, nId );
160 :
161 : // not associated with a Style
162 210 : for ( int i = 0; i < WW8ListManager::nMaxLevel; ++i )
163 189 : SwWW8Writer::WriteShort( *m_rWW8Export.pTableStrm, 0xFFF );
164 :
165 21 : sal_uInt8 nFlags = 0, nDummy = 0;
166 21 : if ( rRule.IsContinusNum() )
167 6 : nFlags |= 0x1;
168 :
169 21 : m_rWW8Export.pTableStrm->WriteUChar( nFlags ).WriteUChar( nDummy );
170 21 : }
171 :
172 87 : void MSWordExportBase::NumberingDefinitions()
173 : {
174 87 : if ( !m_pUsedNumTable )
175 87 : return; // no numbering is used
176 :
177 87 : sal_uInt16 nCount = m_pUsedNumTable->size();
178 :
179 : // Write static data of SwNumRule - LSTF
180 283 : for ( sal_uInt16 n = 0; n < nCount; ++n )
181 : {
182 196 : const SwNumRule& rRule = *(*m_pUsedNumTable)[ n ];
183 :
184 196 : AttrOutput().NumberingDefinition( n + 1, rRule );
185 : }
186 : }
187 :
188 141 : static sal_uInt8 GetLevelNFC( sal_uInt16 eNumType, const SfxItemSet *pOutSet)
189 : {
190 141 : sal_uInt8 nRet = 0;
191 141 : switch( eNumType )
192 : {
193 : case SVX_NUM_CHARS_UPPER_LETTER:
194 0 : case SVX_NUM_CHARS_UPPER_LETTER_N: nRet = 3; break;
195 : case SVX_NUM_CHARS_LOWER_LETTER:
196 0 : case SVX_NUM_CHARS_LOWER_LETTER_N: nRet = 4; break;
197 0 : case SVX_NUM_ROMAN_UPPER: nRet = 1; break;
198 0 : case SVX_NUM_ROMAN_LOWER: nRet = 2; break;
199 :
200 : case SVX_NUM_BITMAP:
201 2 : case SVX_NUM_CHAR_SPECIAL: nRet = 23; break;
202 0 : case SVX_NUM_FULL_WIDTH_ARABIC: nRet = 14; break;
203 0 : case SVX_NUM_CIRCLE_NUMBER: nRet = 18;break;
204 : case SVX_NUM_NUMBER_LOWER_ZH:
205 1 : nRet = 35;
206 1 : if ( pOutSet ) {
207 1 : const SvxLanguageItem rLang = static_cast<const SvxLanguageItem&>( pOutSet->Get( RES_CHRATR_CJK_LANGUAGE,true) );
208 1 : const LanguageType eLang = rLang.GetLanguage();
209 1 : if (LANGUAGE_CHINESE_SIMPLIFIED ==eLang) {
210 1 : nRet = 39;
211 1 : }
212 : }
213 1 : break;
214 0 : case SVX_NUM_NUMBER_UPPER_ZH: nRet = 38; break;
215 1 : case SVX_NUM_NUMBER_UPPER_ZH_TW: nRet = 34;break;
216 1 : case SVX_NUM_TIAN_GAN_ZH: nRet = 30; break;
217 1 : case SVX_NUM_DI_ZI_ZH: nRet = 31; break;
218 0 : case SVX_NUM_NUMBER_TRADITIONAL_JA: nRet = 16; break;
219 0 : case SVX_NUM_AIU_FULLWIDTH_JA: nRet = 20; break;
220 0 : case SVX_NUM_AIU_HALFWIDTH_JA: nRet = 12; break;
221 0 : case SVX_NUM_IROHA_FULLWIDTH_JA: nRet = 21; break;
222 0 : case SVX_NUM_IROHA_HALFWIDTH_JA: nRet = 13; break;
223 0 : case style::NumberingType::HANGUL_SYLLABLE_KO: nRet = 24; break;// ganada
224 0 : case style::NumberingType::HANGUL_JAMO_KO: nRet = 25; break;// chosung
225 0 : case style::NumberingType::HANGUL_CIRCLED_SYLLABLE_KO: nRet = 24; break;
226 0 : case style::NumberingType::HANGUL_CIRCLED_JAMO_KO: nRet = 25; break;
227 0 : case style::NumberingType::NUMBER_HANGUL_KO: nRet = 41; break;
228 0 : case style::NumberingType::NUMBER_UPPER_KO: nRet = 44; break;
229 111 : case SVX_NUM_NUMBER_NONE: nRet = 0xff; break;
230 : }
231 141 : return nRet;
232 : }
233 :
234 :
235 141 : void WW8AttributeOutput::NumberingLevel( sal_uInt8 /*nLevel*/,
236 : sal_uInt16 nStart,
237 : sal_uInt16 nNumberingType,
238 : SvxAdjust eAdjust,
239 : const sal_uInt8 *pNumLvlPos,
240 : sal_uInt8 nFollow,
241 : const wwFont *pFont,
242 : const SfxItemSet *pOutSet,
243 : sal_Int16 nIndentAt,
244 : sal_Int16 nFirstLineIndex,
245 : sal_Int16 nListTabPos,
246 : const OUString &rNumberingString,
247 : const SvxBrushItem* pBrush //For i120928,to transfer graphic of bullet
248 : )
249 : {
250 : // Start value
251 141 : SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, nStart );
252 :
253 : // Type
254 141 : m_rWW8Export.pTableStrm->WriteUChar( GetLevelNFC( nNumberingType ,pOutSet) );
255 :
256 : // Justification
257 : sal_uInt8 nAlign;
258 141 : switch ( eAdjust )
259 : {
260 : case SVX_ADJUST_CENTER:
261 0 : nAlign = 1;
262 0 : break;
263 : case SVX_ADJUST_RIGHT:
264 0 : nAlign = 2;
265 0 : break;
266 : default:
267 141 : nAlign = 0;
268 141 : break;
269 : }
270 141 : m_rWW8Export.pTableStrm->WriteUChar( nAlign );
271 :
272 : // Write the rgbxchNums[9], positions of placeholders for paragraph
273 : // numbers in the text
274 141 : m_rWW8Export.pTableStrm->Write( pNumLvlPos, WW8ListManager::nMaxLevel );
275 :
276 : // Type of the character between the bullet and the text
277 141 : m_rWW8Export.pTableStrm->WriteUChar( nFollow );
278 :
279 : // dxaSoace/dxaIndent (Word 6 compatibility)
280 141 : SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, 0 );
281 141 : SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, 0 );
282 :
283 : // cbGrpprlChpx
284 141 : ww::bytes aCharAtrs;
285 141 : if ( pOutSet )
286 : {
287 78 : ww::bytes* pOldpO = m_rWW8Export.pO;
288 78 : m_rWW8Export.pO = &aCharAtrs;
289 78 : if ( pFont )
290 : {
291 2 : sal_uInt16 nFontID = m_rWW8Export.m_aFontHelper.GetId( *pFont );
292 :
293 2 : if ( m_rWW8Export.bWrtWW8 )
294 : {
295 2 : m_rWW8Export.InsUInt16( NS_sprm::LN_CRgFtc0 );
296 2 : m_rWW8Export.InsUInt16( nFontID );
297 2 : m_rWW8Export.InsUInt16( NS_sprm::LN_CRgFtc2 );
298 : }
299 : else
300 0 : m_rWW8Export.pO->push_back( 93 );
301 2 : m_rWW8Export.InsUInt16( nFontID );
302 : }
303 :
304 78 : m_rWW8Export.OutputItemSet( *pOutSet, false, true, i18n::ScriptType::LATIN, m_rWW8Export.m_bExportModeRTF );
305 : //For i120928,achieve graphic's index of bullet from the bullet bookmark
306 78 : if (SVX_NUM_BITMAP == nNumberingType && pBrush)
307 : {
308 0 : int nIndex = m_rWW8Export.GetGrfIndex(*pBrush);
309 0 : if ( nIndex != -1 )
310 : {
311 0 : m_rWW8Export.InsUInt16(NS_sprm::LN_CPbiIBullet);
312 0 : m_rWW8Export.InsUInt32(nIndex);
313 0 : m_rWW8Export.InsUInt16(NS_sprm::LN_CPbiGrf);
314 0 : m_rWW8Export.InsUInt16(1);
315 : }
316 : }
317 :
318 78 : m_rWW8Export.pO = pOldpO;
319 : }
320 141 : m_rWW8Export.pTableStrm->WriteUChar( sal_uInt8( aCharAtrs.size() ) );
321 :
322 : // cbGrpprlPapx
323 : sal_uInt8 aPapSprms [] = {
324 : 0x5e, 0x84, 0, 0, // sprmPDxaLeft
325 : 0x60, 0x84, 0, 0, // sprmPDxaLeft1
326 : 0x15, 0xc6, 0x05, 0x00, 0x01, 0, 0, 0x06
327 141 : };
328 141 : m_rWW8Export.pTableStrm->WriteUChar( sal_uInt8( sizeof( aPapSprms ) ) );
329 :
330 : // reserved
331 141 : SwWW8Writer::WriteShort( *m_rWW8Export.pTableStrm, 0 );
332 :
333 : // pap sprms
334 141 : sal_uInt8* pData = aPapSprms + 2;
335 141 : Set_UInt16( pData, nIndentAt );
336 141 : pData += 2;
337 141 : Set_UInt16( pData, nFirstLineIndex );
338 141 : pData += 5;
339 141 : Set_UInt16( pData, nListTabPos );
340 :
341 141 : m_rWW8Export.pTableStrm->Write( aPapSprms, sizeof( aPapSprms ));
342 :
343 : // write Chpx
344 141 : if( !aCharAtrs.empty() )
345 6 : m_rWW8Export.pTableStrm->Write( aCharAtrs.data(), aCharAtrs.size() );
346 :
347 : // write the num string
348 141 : SwWW8Writer::WriteShort( *m_rWW8Export.pTableStrm, rNumberingString.getLength() );
349 141 : SwWW8Writer::WriteString16( *m_rWW8Export.pTableStrm, rNumberingString, false );
350 141 : }
351 :
352 87 : void MSWordExportBase::AbstractNumberingDefinitions()
353 : {
354 87 : sal_uInt16 nCount = m_pUsedNumTable->size();
355 : sal_uInt16 n;
356 :
357 : // prepare the NodeNum to generate the NumString
358 87 : SwNumberTree::tNumberVector aNumVector;
359 870 : for ( n = 0; n < WW8ListManager::nMaxLevel; ++n )
360 783 : aNumVector.push_back( n );
361 :
362 283 : for( n = 0; n < nCount; ++n )
363 : {
364 196 : AttrOutput().StartAbstractNumbering( n + 1 );
365 :
366 196 : const SwNumRule& rRule = *(*m_pUsedNumTable)[ n ];
367 : sal_uInt8 nLvl;
368 196 : sal_uInt8 nLevels = static_cast< sal_uInt8 >(rRule.IsContinusNum() ?
369 196 : WW8ListManager::nMinLevel : WW8ListManager::nMaxLevel);
370 1904 : for( nLvl = 0; nLvl < nLevels; ++nLvl )
371 : {
372 : // write the static data of the SwNumFormat of this level
373 1708 : sal_uInt8 aNumLvlPos[WW8ListManager::nMaxLevel] = { 0,0,0,0,0,0,0,0,0 };
374 :
375 1708 : const SwNumFormat& rFormat = rRule.Get( nLvl );
376 :
377 1708 : sal_uInt8 nFollow = 0;
378 : // #i86652#
379 1708 : if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
380 : {
381 373 : nFollow = 2; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
382 : }
383 1335 : else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
384 : {
385 1335 : switch ( rFormat.GetLabelFollowedBy() )
386 : {
387 : case SvxNumberFormat::LISTTAB:
388 : {
389 : // 0 (tab) unless there would be no content before the tab, in which case 2 (nothing)
390 1297 : nFollow = (SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType()) ? 0 : 2;
391 : }
392 1297 : break;
393 : case SvxNumberFormat::SPACE:
394 : {
395 : // 1 (space) unless there would be no content before the space in which case 2 (nothing)
396 0 : nFollow = (SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType()) ? 1 : 2;
397 : }
398 0 : break;
399 : case SvxNumberFormat::NOTHING:
400 : {
401 38 : nFollow = 2;
402 : }
403 38 : break;
404 : default:
405 : {
406 0 : nFollow = 0;
407 : OSL_FAIL( "unknown GetLabelFollowedBy() return value" );
408 : }
409 : }
410 : }
411 :
412 : // Build the NumString for this Level
413 1708 : OUString sNumStr;
414 3416 : OUString sFontName;
415 1708 : bool bWriteBullet = false;
416 1708 : const vcl::Font* pBulletFont=0;
417 1708 : rtl_TextEncoding eChrSet=0;
418 1708 : FontFamily eFamily=FAMILY_DECORATIVE;
419 3154 : if( SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType() ||
420 1446 : SVX_NUM_BITMAP == rFormat.GetNumberingType() )
421 : {
422 266 : sNumStr = OUString(rFormat.GetBulletChar());
423 266 : bWriteBullet = true;
424 :
425 266 : pBulletFont = rFormat.GetBulletFont();
426 266 : if (!pBulletFont)
427 : {
428 3 : pBulletFont = &numfunc::GetDefBulletFont();
429 : }
430 :
431 266 : eChrSet = pBulletFont->GetCharSet();
432 266 : sFontName = pBulletFont->GetName();
433 266 : eFamily = pBulletFont->GetFamily();
434 :
435 266 : if ( IsStarSymbol(sFontName) )
436 147 : SubstituteBullet( sNumStr, eChrSet, sFontName );
437 :
438 : // #i86652#
439 266 : if ( rFormat.GetPositionAndSpaceMode() ==
440 : SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
441 : {
442 : // <nFollow = 2>, if minimum label width equals 0 and
443 : // minimum distance between label and text equals 0
444 149 : nFollow = ( rFormat.GetFirstLineOffset() == 0 &&
445 2 : rFormat.GetCharTextDistance() == 0 )
446 149 : ? 2 : 0; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
447 : }
448 : }
449 : else
450 : {
451 1442 : if (SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType())
452 : {
453 725 : sal_uInt8* pLvlPos = aNumLvlPos;
454 : // the numbering string has to be restrict
455 : // to the level currently working on.
456 725 : sNumStr = rRule.MakeNumString(aNumVector, false, true, nLvl);
457 :
458 : // now search the nums in the string
459 4187 : for( sal_uInt8 i = 0; i <= nLvl; ++i )
460 : {
461 3462 : OUString sSrch( OUString::number( i ));
462 3462 : sal_Int32 nFnd = sNumStr.indexOf( sSrch );
463 3462 : if( -1 != nFnd )
464 : {
465 1211 : *pLvlPos = (sal_uInt8)(nFnd + rFormat.GetPrefix().getLength() + 1 );
466 1211 : ++pLvlPos;
467 1211 : sNumStr = sNumStr.replaceAt( nFnd, 1, OUString((char)i) );
468 : }
469 3462 : }
470 : // #i86652#
471 725 : if ( rFormat.GetPositionAndSpaceMode() ==
472 : SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
473 : {
474 : // <nFollow = 2>, if minimum label width equals 0 and
475 : // minimum distance between label and text equals 0
476 194 : nFollow = ( rFormat.GetFirstLineOffset() == 0 &&
477 49 : rFormat.GetCharTextDistance() == 0 )
478 194 : ? 2 : 0; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
479 : }
480 : }
481 :
482 1442 : if( !rFormat.GetPrefix().isEmpty() )
483 41 : sNumStr = rFormat.GetPrefix() + sNumStr;
484 1442 : sNumStr += rFormat.GetSuffix();
485 : }
486 :
487 : // Attributes of the numbering
488 1708 : wwFont *pPseudoFont = NULL;
489 1708 : const SfxItemSet* pOutSet = NULL;
490 :
491 : // cbGrpprlChpx
492 1708 : SfxItemSet aSet( m_pDoc->GetAttrPool(), RES_CHRATR_BEGIN,
493 3416 : RES_CHRATR_END );
494 1708 : if ( rFormat.GetCharFormat() || bWriteBullet )
495 : {
496 627 : if ( bWriteBullet )
497 : {
498 266 : pOutSet = &aSet;
499 :
500 266 : if ( rFormat.GetCharFormat() )
501 216 : aSet.Put( rFormat.GetCharFormat()->GetAttrSet() );
502 266 : aSet.ClearItem( RES_CHRATR_CJK_FONT );
503 266 : aSet.ClearItem( RES_CHRATR_FONT );
504 :
505 266 : if ( sFontName.isEmpty() )
506 0 : sFontName = pBulletFont->GetName();
507 :
508 : pPseudoFont = new wwFont( sFontName, pBulletFont->GetPitch(),
509 266 : eFamily, eChrSet, SupportsUnicode() );
510 : }
511 : else
512 361 : pOutSet = &rFormat.GetCharFormat()->GetAttrSet();
513 : }
514 :
515 1708 : sal_Int16 nIndentAt = 0;
516 1708 : sal_Int16 nFirstLineIndex = 0;
517 1708 : sal_Int16 nListTabPos = 0;
518 :
519 : // #i86652#
520 1708 : if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
521 : {
522 373 : nIndentAt = nListTabPos = rFormat.GetAbsLSpace();
523 373 : nFirstLineIndex = GetWordFirstLineOffset(rFormat);
524 : }
525 1335 : else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
526 : {
527 1335 : nIndentAt = static_cast<sal_Int16>(rFormat.GetIndentAt());
528 1335 : nFirstLineIndex = static_cast<sal_Int16>(rFormat.GetFirstLineIndent());
529 1335 : nListTabPos = rFormat.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB?
530 1335 : static_cast<sal_Int16>( rFormat.GetListtabPos() ) : 0;
531 : }
532 :
533 1708 : AttrOutput().NumberingLevel( nLvl,
534 1708 : rFormat.GetStart(),
535 1708 : rFormat.GetNumberingType(),
536 : rFormat.GetNumAdjust(),
537 : aNumLvlPos,
538 : nFollow,
539 : pPseudoFont, pOutSet,
540 : nIndentAt, nFirstLineIndex, nListTabPos,
541 : sNumStr,
542 5124 : rFormat.GetNumberingType()==SVX_NUM_BITMAP ? rFormat.GetBrush():0);
543 :
544 1708 : delete pPseudoFont;
545 1708 : }
546 196 : AttrOutput().EndAbstractNumbering();
547 87 : }
548 87 : }
549 :
550 11 : void WW8Export::OutOverrideListTab()
551 : {
552 11 : if( !m_pUsedNumTable )
553 11 : return ; // no numbering is used
554 :
555 : // write the "list format override" - LFO
556 11 : sal_uInt16 nCount = m_pUsedNumTable->size();
557 : sal_uInt16 n;
558 :
559 11 : pFib->fcPlfLfo = pTableStrm->Tell();
560 11 : SwWW8Writer::WriteLong( *pTableStrm, nCount );
561 :
562 32 : for( n = 0; n < nCount; ++n )
563 : {
564 21 : SwWW8Writer::WriteLong( *pTableStrm, n + 1 );
565 21 : SwWW8Writer::FillCount( *pTableStrm, 12 );
566 : }
567 32 : for( n = 0; n < nCount; ++n )
568 21 : SwWW8Writer::WriteLong( *pTableStrm, -1 ); // no overwrite
569 :
570 : // set len to FIB
571 11 : pFib->lcbPlfLfo = pTableStrm->Tell() - pFib->fcPlfLfo;
572 : }
573 :
574 11 : void WW8Export::OutListNamesTab()
575 : {
576 11 : if( !m_pUsedNumTable )
577 11 : return ; // no numbering is used
578 :
579 : // write the "list format override" - LFO
580 11 : sal_uInt16 nNms = 0, nCount = m_pUsedNumTable->size();
581 :
582 11 : pFib->fcSttbListNames = pTableStrm->Tell();
583 11 : SwWW8Writer::WriteShort( *pTableStrm, -1 );
584 11 : SwWW8Writer::WriteLong( *pTableStrm, nCount );
585 :
586 32 : for( ; nNms < nCount; ++nNms )
587 : {
588 21 : const SwNumRule& rRule = *(*m_pUsedNumTable)[ nNms ];
589 21 : OUString sNm;
590 21 : if( !rRule.IsAutoRule() )
591 10 : sNm = rRule.GetName();
592 :
593 21 : SwWW8Writer::WriteShort( *pTableStrm, sNm.getLength() );
594 21 : if (!sNm.isEmpty())
595 10 : SwWW8Writer::WriteString16(*pTableStrm, sNm, false);
596 21 : }
597 :
598 11 : SwWW8Writer::WriteLong( *pTableStrm, pFib->fcSttbListNames + 2, nNms );
599 : // set len to FIB
600 11 : pFib->lcbSttbListNames = pTableStrm->Tell() - pFib->fcSttbListNames;
601 : }
602 :
603 : // old WW95-Code
604 :
605 0 : void WW8Export::OutputOlst( const SwNumRule& rRule )
606 : {
607 0 : if ( bWrtWW8 )
608 0 : return;
609 :
610 : static const sal_uInt8 aAnlvBase[] = { // Defaults
611 : 1,0,0, // Upper Roman
612 : 0x0C, // Hanging Indent, fPrev
613 : 0,0,1,0x80,0,0,1,0,0x1b,1,0,0 };
614 :
615 : static const sal_uInt8 aSprmOlstHdr[] = { 133, 212 };
616 :
617 0 : pO->insert( pO->end(), aSprmOlstHdr, aSprmOlstHdr+sizeof( aSprmOlstHdr ) );
618 : WW8_OLST aOlst;
619 0 : memset( &aOlst, 0, sizeof(aOlst) );
620 0 : sal_uInt8* pC = aOlst.rgch;
621 0 : sal_uInt8* pChars = pC;
622 0 : sal_uInt16 nCharLen = 64;
623 :
624 0 : for (sal_uInt16 j = 0; j < WW8ListManager::nMaxLevel; j++ ) // 9 variable ANLVs
625 : {
626 0 : memcpy( &aOlst.rganlv[j], aAnlvBase, sizeof( WW8_ANLV ) ); // Defaults
627 :
628 0 : const SwNumFormat* pFormat = rRule.GetNumFormat( j );
629 0 : if( pFormat )
630 0 : BuildAnlvBase( aOlst.rganlv[j], pChars, nCharLen, rRule,
631 0 : *pFormat, (sal_uInt8)j );
632 : }
633 :
634 0 : pO->insert( pO->end(), reinterpret_cast<sal_uInt8*>(&aOlst), reinterpret_cast<sal_uInt8*>(&aOlst)+sizeof( aOlst ) );
635 : }
636 :
637 0 : void WW8Export::Out_WwNumLvl( sal_uInt8 nWwLevel )
638 : {
639 0 : pO->push_back( 13 );
640 0 : pO->push_back( nWwLevel );
641 0 : }
642 :
643 0 : void WW8Export::Out_SwNumLvl( sal_uInt8 nSwLevel )
644 : {
645 : OSL_ENSURE( nSwLevel < MAXLEVEL, "numbered?");
646 0 : Out_WwNumLvl( nSwLevel + 1 );
647 0 : }
648 :
649 0 : void WW8Export::BuildAnlvBulletBase(WW8_ANLV& rAnlv, sal_uInt8*& rpCh,
650 : sal_uInt16& rCharLen, const SwNumFormat& rFormat)
651 : {
652 0 : rAnlv.nfc = 11;
653 :
654 0 : sal_uInt8 nb = 0; // type of number
655 0 : switch (rFormat.GetNumAdjust())
656 : {
657 : case SVX_ADJUST_RIGHT:
658 0 : nb = 2;
659 0 : break;
660 : case SVX_ADJUST_CENTER:
661 0 : nb = 1;
662 0 : break;
663 : case SVX_ADJUST_BLOCK:
664 : case SVX_ADJUST_BLOCKLINE:
665 0 : nb = 3;
666 0 : break;
667 : case SVX_ADJUST_LEFT:
668 : case SVX_ADJUST_END:
669 0 : break;
670 : }
671 :
672 : // #i86652#
673 0 : if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
674 : {
675 0 : if (GetWordFirstLineOffset(rFormat) < 0)
676 0 : nb |= 0x8; // number will be displayed using a hanging indent
677 : }
678 0 : rAnlv.aBits1 = nb;
679 :
680 0 : if (1 < rCharLen)
681 : {
682 0 : const vcl::Font& rFont = rFormat.GetBulletFont()
683 0 : ? *rFormat.GetBulletFont()
684 0 : : numfunc::GetDefBulletFont();
685 0 : OUString sNumStr = OUString(rFormat.GetBulletChar());
686 0 : rtl_TextEncoding eChrSet = rFont.GetCharSet();
687 0 : OUString sFontName = rFont.GetName();
688 :
689 : sal_uInt16 nFontId;
690 0 : if ( IsStarSymbol(sFontName) )
691 : {
692 : /*
693 : If we are starsymbol then in ww7- mode we will always convert to a
694 : windows 8bit symbol font and an index into it, to conversion to
695 : 8 bit is complete at this stage.
696 : */
697 0 : SubstituteBullet(sNumStr, eChrSet, sFontName);
698 : wwFont aPseudoFont(sFontName, rFont.GetPitch(), rFont.GetFamily(),
699 0 : eChrSet, bWrtWW8);
700 0 : nFontId = m_aFontHelper.GetId(aPseudoFont);
701 0 : *rpCh = static_cast<sal_uInt8>(sNumStr[0]);
702 : }
703 : else
704 : {
705 : /*
706 : Otherwise we are a unicode char and need to be converted back to
707 : an 8 bit format. We happen to know that if the font is already an
708 : 8 bit windows font currently, staroffice promotes the char into
709 : the F000->F0FF range, so we can undo this, and we'll be back to
710 : the equivalent 8bit location, otherwise we have to convert from
711 : true unicode to an 8bit charset
712 : */
713 0 : nFontId = m_aFontHelper.GetId(rFont);
714 0 : sal_Unicode cChar = sNumStr[0];
715 0 : if ( (eChrSet == RTL_TEXTENCODING_SYMBOL) && (cChar >= 0xF000) && (
716 : cChar <= 0xF0FF) )
717 : {
718 0 : *rpCh = static_cast< sal_uInt8 >(cChar - 0xF000);
719 : }
720 : else
721 0 : *rpCh = OUStringToOString(OUString(cChar), eChrSet).toChar();
722 : }
723 0 : rpCh++;
724 0 : rCharLen--;
725 0 : ShortToSVBT16(nFontId, rAnlv.ftc);
726 0 : rAnlv.cbTextBefore = 1;
727 : }
728 : // #i86652#
729 0 : if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
730 : {
731 0 : ShortToSVBT16( -GetWordFirstLineOffset(rFormat), rAnlv.dxaIndent );
732 0 : ShortToSVBT16( rFormat.GetCharTextDistance(), rAnlv.dxaSpace );
733 : }
734 : else
735 : {
736 0 : ShortToSVBT16( 0, rAnlv.dxaIndent );
737 0 : ShortToSVBT16( 0, rAnlv.dxaSpace );
738 : }
739 0 : }
740 :
741 147 : void MSWordExportBase::SubstituteBullet( OUString& rNumStr,
742 : rtl_TextEncoding& rChrSet, OUString& rFontName ) const
743 : {
744 147 : if (!m_bSubstituteBullets)
745 165 : return;
746 129 : OUString sFontName = rFontName;
747 :
748 : // If Bullet char is "", don't change
749 129 : if (rNumStr[0] != sal_Unicode(0x0))
750 : {
751 129 : rNumStr = rNumStr.replaceAt(0, 1, OUString( msfilter::util::bestFitOpenSymbolToMSFont(rNumStr[0], rChrSet, sFontName, !SupportsUnicode()) ));
752 : }
753 :
754 129 : rFontName = sFontName;
755 : }
756 :
757 0 : static void SwWw8_InsertAnlText( const OUString& rStr, sal_uInt8*& rpCh,
758 : sal_uInt16& rCharLen, sal_uInt8& r8Len )
759 : {
760 0 : sal_uInt8 nb = 0;
761 0 : ww::bytes aO;
762 0 : SwWW8Writer::InsAsString8( aO, rStr, RTL_TEXTENCODING_MS_1252 );
763 :
764 0 : sal_uInt16 nCnt = aO.size();
765 0 : if( nCnt && nCnt < rCharLen )
766 : {
767 0 : nb = (sal_uInt8)nCnt;
768 0 : std::copy( aO.begin(), aO.end(), rpCh );
769 0 : rpCh += nCnt;
770 0 : rCharLen = rCharLen - nCnt;
771 : }
772 0 : r8Len = nb;
773 0 : }
774 :
775 0 : void WW8Export::BuildAnlvBase(WW8_ANLV& rAnlv, sal_uInt8*& rpCh,
776 : sal_uInt16& rCharLen, const SwNumRule& rRul, const SwNumFormat& rFormat,
777 : sal_uInt8 nSwLevel)
778 : {
779 0 : const SfxItemSet *pOutSet = NULL;
780 0 : if (rFormat.GetCharFormat())
781 0 : pOutSet = &rFormat.GetCharFormat()->GetAttrSet();
782 0 : rAnlv.nfc = GetLevelNFC(rFormat.GetNumberingType(),pOutSet );
783 :
784 0 : sal_uInt8 nb = 0;
785 0 : switch (rFormat.GetNumAdjust())
786 : {
787 : case SVX_ADJUST_RIGHT:
788 0 : nb = 2;
789 0 : break;
790 : case SVX_ADJUST_CENTER:
791 0 : nb = 1;
792 0 : break;
793 : case SVX_ADJUST_BLOCK:
794 : case SVX_ADJUST_BLOCKLINE:
795 0 : nb = 3;
796 0 : break;
797 : case SVX_ADJUST_LEFT:
798 : case SVX_ADJUST_END:
799 0 : break;
800 : }
801 :
802 0 : bool bInclUpper = rFormat.GetIncludeUpperLevels() > 0;
803 0 : if( bInclUpper )
804 0 : nb |= 0x4; // include previous levels
805 :
806 0 : if (GetWordFirstLineOffset(rFormat) < 0)
807 0 : nb |= 0x8; // number will be displayed using a hanging indent
808 0 : rAnlv.aBits1 = nb;
809 :
810 0 : if( bInclUpper && !rRul.IsContinusNum() )
811 : {
812 0 : if( (nSwLevel >= WW8ListManager::nMinLevel )
813 0 : && (nSwLevel<= WW8ListManager::nMaxLevel )
814 0 : && (rFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE ) ) // UEberhaupt Nummerierung ?
815 : { // -> suche, ob noch Zahlen davor
816 0 : sal_uInt8 nUpper = rFormat.GetIncludeUpperLevels();
817 0 : if( (nUpper <= WW8ListManager::nMaxLevel) &&
818 0 : (rRul.Get(nUpper).GetNumberingType() != SVX_NUM_NUMBER_NONE ) ) // Nummerierung drueber ?
819 : {
820 : // dann Punkt einfuegen
821 : SwWw8_InsertAnlText( ".", rpCh, rCharLen,
822 0 : rAnlv.cbTextBefore );
823 : }
824 :
825 : }
826 : }
827 : else
828 : {
829 0 : SwWw8_InsertAnlText( rFormat.GetPrefix(), rpCh, rCharLen,
830 0 : rAnlv.cbTextBefore );
831 0 : SwWw8_InsertAnlText( rFormat.GetSuffix(), rpCh, rCharLen,
832 0 : rAnlv.cbTextAfter );
833 : }
834 :
835 0 : ShortToSVBT16( rFormat.GetStart(), rAnlv.iStartAt );
836 : // #i86652#
837 0 : if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
838 : {
839 0 : ShortToSVBT16( -GetWordFirstLineOffset(rFormat), rAnlv.dxaIndent );
840 0 : ShortToSVBT16( rFormat.GetCharTextDistance(), rAnlv.dxaSpace );
841 : }
842 : else
843 : {
844 0 : ShortToSVBT16( 0, rAnlv.dxaIndent );
845 0 : ShortToSVBT16( 0, rAnlv.dxaSpace );
846 : }
847 0 : }
848 :
849 0 : void WW8Export::Out_NumRuleAnld( const SwNumRule& rRul, const SwNumFormat& rFormat,
850 : sal_uInt8 nSwLevel )
851 : {
852 : static const sal_uInt8 aSprmAnldDefault[54] = {
853 : 12, 52,
854 : 1,0,0,0x0c,0,0,1,0x80,0,0,1,0,0x1b,1,0,0,0x2e,
855 : 0,0,0,
856 : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
857 : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
858 : sal_uInt8 aSprmAnld[54];
859 :
860 0 : memcpy( aSprmAnld, aSprmAnldDefault, sizeof( aSprmAnld ) );
861 0 : WW8_ANLD* pA = reinterpret_cast<WW8_ANLD*>(aSprmAnld + 2); // handy pointer
862 :
863 0 : sal_uInt8* pChars = pA->rgchAnld;
864 0 : sal_uInt16 nCharLen = 31;
865 :
866 0 : if( nSwLevel == 11 )
867 0 : BuildAnlvBulletBase( pA->eAnlv, pChars, nCharLen, rFormat );
868 : else
869 0 : BuildAnlvBase( pA->eAnlv, pChars, nCharLen, rRul, rFormat, nSwLevel );
870 :
871 : // ... spit it out
872 0 : OutSprmBytes( reinterpret_cast<sal_uInt8*>(&aSprmAnld), sizeof( aSprmAnld ) );
873 0 : }
874 :
875 : // Return: is it an outline?
876 0 : bool WW8Export::Out_SwNum(const SwTextNode* pNd)
877 : {
878 0 : int nLevel = pNd->GetActualListLevel();
879 :
880 0 : if (nLevel < 0 || nLevel >= MAXLEVEL)
881 : {
882 : OSL_FAIL("Invalid level");
883 :
884 0 : return false;
885 : }
886 :
887 0 : sal_uInt8 nSwLevel = static_cast< sal_uInt8 >(nLevel);
888 :
889 0 : const SwNumRule* pRul = pNd->GetNumRule();
890 0 : if( !pRul || nSwLevel == WW8ListManager::nMaxLevel)
891 0 : return false;
892 :
893 0 : bool bRet = true;
894 :
895 0 : SwNumFormat aFormat(pRul->Get(nSwLevel));
896 : // #i86652#
897 0 : if ( aFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
898 : {
899 0 : const SvxLRSpaceItem& rLR = ItemGet<SvxLRSpaceItem>(*pNd, RES_LR_SPACE);
900 0 : aFormat.SetAbsLSpace(writer_cast<short>(aFormat.GetAbsLSpace() + rLR.GetLeft()));
901 : }
902 :
903 0 : if (
904 0 : aFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE ||
905 0 : aFormat.GetNumberingType() == SVX_NUM_CHAR_SPECIAL ||
906 0 : aFormat.GetNumberingType() == SVX_NUM_BITMAP
907 : )
908 : {
909 0 : Out_WwNumLvl(11);
910 0 : Out_NumRuleAnld(*pRul, aFormat, 11);
911 0 : bRet = false;
912 : }
913 0 : else if (
914 0 : pRul->IsContinusNum() ||
915 0 : (pRul->Get(1).GetIncludeUpperLevels() <= 1)
916 : )
917 : {
918 0 : Out_WwNumLvl(10);
919 0 : Out_NumRuleAnld(*pRul, aFormat, 10);
920 0 : bRet = false;
921 : }
922 : else
923 : {
924 0 : Out_SwNumLvl(nSwLevel);
925 0 : Out_NumRuleAnld(*pRul, aFormat, nSwLevel);
926 : }
927 0 : return bRet;
928 60 : }
929 :
930 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|