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