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 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
28
29 #include <hintids.hxx>
30 #include <vcl/font.hxx>
31 #include <editeng/fontitem.hxx>
32 #include <editeng/lrspitem.hxx>
33 #include <doc.hxx>
34 #include <docary.hxx>
35 #include <numrule.hxx>
36 #include <paratr.hxx>
37 #include <charfmt.hxx>
38 #include <ndtxt.hxx>
39 #include <com/sun/star/i18n/ScriptType.hdl>
40
41 #include <writerfilter/doctok/sprmids.hxx>
42
43 #include "ww8attributeoutput.hxx"
44 #include "writerhelper.hxx"
45 #include "writerwordglue.hxx"
46 #include "wrtww8.hxx"
47 #include "ww8par.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
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)206 void WW8AttributeOutput::NumberingLevel( sal_uInt8 /*nLevel*/,
207 sal_uInt16 nStart,
208 sal_uInt16 nNumberingType,
209 SvxAdjust eAdjust,
210 const sal_uInt8 *pNumLvlPos,
211 sal_uInt8 nFollow,
212 const wwFont *pFont,
213 const SfxItemSet *pOutSet,
214 sal_Int16 nIndentAt,
215 sal_Int16 nFirstLineIndex,
216 sal_Int16 nListTabPos,
217 const String &rNumberingString,
218 const SvxBrushItem* pBrush //For i120928,to transfer graphic of bullet
219 )
220 {
221 // Start value
222 SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, nStart );
223
224 // Type
225 *m_rWW8Export.pTableStrm << WW8Export::GetNumId( nNumberingType );
226
227 // Justification
228 sal_uInt8 nAlign;
229 switch ( eAdjust )
230 {
231 case SVX_ADJUST_CENTER:
232 nAlign = 1;
233 break;
234 case SVX_ADJUST_RIGHT:
235 nAlign = 2;
236 break;
237 default:
238 nAlign = 0;
239 break;
240 }
241 *m_rWW8Export.pTableStrm << nAlign;
242
243 // Write the rgbxchNums[9], positions of placeholders for paragraph
244 // numbers in the text
245 m_rWW8Export.pTableStrm->Write( pNumLvlPos, WW8ListManager::nMaxLevel );
246
247 // Type of the character between the bullet and the text
248 *m_rWW8Export.pTableStrm << nFollow;
249
250 // dxaSoace/dxaIndent (Word 6 compatibility)
251 SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, 0 );
252 SwWW8Writer::WriteLong( *m_rWW8Export.pTableStrm, 0 );
253
254 // cbGrpprlChpx
255 WW8Bytes aCharAtrs;
256 if ( pOutSet )
257 {
258 WW8Bytes* pOldpO = m_rWW8Export.pO;
259 m_rWW8Export.pO = &aCharAtrs;
260 if ( pFont )
261 {
262 sal_uInt16 nFontID = m_rWW8Export.maFontHelper.GetId( *pFont );
263
264 if ( m_rWW8Export.bWrtWW8 )
265 {
266 m_rWW8Export.InsUInt16( NS_sprm::LN_CRgFtc0 );
267 m_rWW8Export.InsUInt16( nFontID );
268 m_rWW8Export.InsUInt16( NS_sprm::LN_CRgFtc2 );
269 }
270 else
271 m_rWW8Export.pO->Insert( 93, m_rWW8Export.pO->Count() );
272 m_rWW8Export.InsUInt16( nFontID );
273 }
274
275 m_rWW8Export.OutputItemSet( *pOutSet, false, true, i18n::ScriptType::LATIN, m_rWW8Export.mbExportModeRTF );
276 //For i120928,achieve graphic's index of bullet from the bullet bookmark
277 if (SVX_NUM_BITMAP == nNumberingType && pBrush)
278 {
279 int nIndex = m_rWW8Export.GetGrfIndex(*pBrush);
280 if ( nIndex != -1 )
281 {
282 m_rWW8Export.InsUInt16(0x6887);
283 m_rWW8Export.InsUInt32(nIndex);
284 m_rWW8Export.InsUInt16(0x4888);
285 m_rWW8Export.InsUInt16(1);
286 }
287 }
288
289 m_rWW8Export.pO = pOldpO;
290 }
291 *m_rWW8Export.pTableStrm << sal_uInt8( aCharAtrs.Count() );
292
293 // cbGrpprlPapx
294 sal_uInt8 aPapSprms [] = {
295 0x5e, 0x84, 0, 0, // sprmPDxaLeft
296 0x60, 0x84, 0, 0, // sprmPDxaLeft1
297 0x15, 0xc6, 0x05, 0x00, 0x01, 0, 0, 0x06
298 };
299 *m_rWW8Export.pTableStrm << sal_uInt8( sizeof( aPapSprms ) );
300
301 // reserved
302 SwWW8Writer::WriteShort( *m_rWW8Export.pTableStrm, 0 );
303
304 // pap sprms
305 sal_uInt8* pData = aPapSprms + 2;
306 Set_UInt16( pData, nIndentAt );
307 pData += 2;
308 Set_UInt16( pData, nFirstLineIndex );
309 pData += 5;
310 Set_UInt16( pData, nListTabPos );
311
312 m_rWW8Export.pTableStrm->Write( aPapSprms, sizeof( aPapSprms ));
313
314 // write Chpx
315 if( aCharAtrs.Count() )
316 m_rWW8Export.pTableStrm->Write( aCharAtrs.GetData(), aCharAtrs.Count() );
317
318 // write the num string
319 SwWW8Writer::WriteShort( *m_rWW8Export.pTableStrm, rNumberingString.Len() );
320 SwWW8Writer::WriteString16( *m_rWW8Export.pTableStrm, rNumberingString, false );
321 }
322
AbstractNumberingDefinitions()323 void MSWordExportBase::AbstractNumberingDefinitions()
324 {
325 sal_uInt16 nCount = pUsedNumTbl->Count();
326 sal_uInt16 n;
327
328 // prepare the NodeNum to generate the NumString
329 SwNumberTree::tNumberVector aNumVector;
330 for ( n = 0; n < WW8ListManager::nMaxLevel; ++n )
331 aNumVector.push_back( n );
332
333 StarSymbolToMSMultiFont *pConvert = 0;
334 for( n = 0; n < nCount; ++n )
335 {
336 AttrOutput().StartAbstractNumbering( n + 1 );
337
338 const SwNumRule& rRule = *pUsedNumTbl->GetObject( n );
339 sal_uInt8 nLvl;
340 sal_uInt8 nLevels = static_cast< sal_uInt8 >(rRule.IsContinusNum() ?
341 WW8ListManager::nMinLevel : WW8ListManager::nMaxLevel);
342 for( nLvl = 0; nLvl < nLevels; ++nLvl )
343 {
344 // write the static data of the SwNumFmt of this level
345 sal_uInt8 aNumLvlPos[WW8ListManager::nMaxLevel] = { 0,0,0,0,0,0,0,0,0 };
346
347 const SwNumFmt& rFmt = rRule.Get( nLvl );
348
349 sal_uInt8 nFollow = 0;
350 // --> OD 2008-06-03 #i86652#
351 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
352 {
353 nFollow = 2; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
354 }
355 else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
356 {
357 switch ( rFmt.GetLabelFollowedBy() )
358 {
359 case SvxNumberFormat::LISTTAB:
360 {
361 // 0 (tab) unless there would be no content before the tab, in which case 2 (nothing)
362 nFollow = (SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType()) ? 0 : 2;
363 }
364 break;
365 case SvxNumberFormat::SPACE:
366 {
367 // 1 (space) unless there would be no content before the space in which case 2 (nothing)
368 nFollow = (SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType()) ? 1 : 2;
369 }
370 break;
371 case SvxNumberFormat::NOTHING:
372 {
373 nFollow = 2;
374 }
375 break;
376 default:
377 {
378 nFollow = 0;
379 ASSERT( false,
380 "unknown GetLabelFollowedBy() return value" );
381 }
382 }
383 }
384 // <--
385
386 // Build the NumString for this Level
387 String sNumStr;
388 String sFontName;
389 bool bWriteBullet = false;
390 const Font* pBulletFont=0;
391 rtl_TextEncoding eChrSet=0;
392 FontFamily eFamily=FAMILY_DECORATIVE;
393 if( SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType() ||
394 SVX_NUM_BITMAP == rFmt.GetNumberingType() )
395 {
396 sNumStr = rFmt.GetBulletChar();
397 bWriteBullet = true;
398
399 pBulletFont = rFmt.GetBulletFont();
400 if (!pBulletFont)
401 {
402 pBulletFont = &numfunc::GetDefBulletFont();
403 }
404
405 eChrSet = pBulletFont->GetCharSet();
406 sFontName = pBulletFont->GetName();
407 eFamily = pBulletFont->GetFamily();
408
409 if ( sw::util::IsStarSymbol( sFontName ) )
410 SubstituteBullet( sNumStr, eChrSet, sFontName );
411
412 // --> OD 2008-06-03 #i86652#
413 if ( rFmt.GetPositionAndSpaceMode() ==
414 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
415 {
416 // --> OD 2007-07-23 #148661#
417 // <nFollow = 2>, if minimum label width equals 0 and
418 // minimum distance between label and text equals 0
419 nFollow = ( rFmt.GetFirstLineOffset() == 0 &&
420 rFmt.GetCharTextDistance() == 0 )
421 ? 2 : 0; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
422 // <--
423 }
424 // <--
425 }
426 else
427 {
428 if (SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType())
429 {
430 sal_uInt8* pLvlPos = aNumLvlPos;
431 // --> OD 2005-10-17 #126238# - the numbering string
432 // has to be restrict to the level currently working on.
433 sNumStr = rRule.MakeNumString(aNumVector, false, true, nLvl);
434 // <--
435
436 // now search the nums in the string
437 for( sal_uInt8 i = 0; i <= nLvl; ++i )
438 {
439 String sSrch( String::CreateFromInt32( i ));
440 xub_StrLen nFnd = sNumStr.Search( sSrch );
441 if( STRING_NOTFOUND != nFnd )
442 {
443 *pLvlPos = (sal_uInt8)(nFnd + rFmt.GetPrefix().Len() + 1 );
444 ++pLvlPos;
445 sNumStr.SetChar( nFnd, (char)i );
446 }
447 }
448 // --> OD 2008-06-03 #i86652#
449 if ( rFmt.GetPositionAndSpaceMode() ==
450 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
451 {
452 // --> OD 2007-07-23 #148661#
453 // <nFollow = 2>, if minimum label width equals 0 and
454 // minimum distance between label and text equals 0
455 nFollow = ( rFmt.GetFirstLineOffset() == 0 &&
456 rFmt.GetCharTextDistance() == 0 )
457 ? 2 : 0; // ixchFollow: 0 - tab, 1 - blank, 2 - nothing
458 // <--
459 }
460 // <--
461 }
462
463 if( rFmt.GetPrefix().Len() )
464 sNumStr.Insert( rFmt.GetPrefix(), 0 );
465 sNumStr += rFmt.GetSuffix();
466 }
467
468 // Attributes of the numbering
469 wwFont *pPseudoFont = NULL;
470 const SfxItemSet* pOutSet = NULL;
471
472 // cbGrpprlChpx
473 SfxItemSet aSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN,
474 RES_CHRATR_END );
475 if ( rFmt.GetCharFmt() || bWriteBullet )
476 {
477 if ( bWriteBullet )
478 {
479 pOutSet = &aSet;
480
481 if ( rFmt.GetCharFmt() )
482 aSet.Put( rFmt.GetCharFmt()->GetAttrSet() );
483 aSet.ClearItem( RES_CHRATR_CJK_FONT );
484 aSet.ClearItem( RES_CHRATR_FONT );
485
486 if ( !sFontName.Len() )
487 sFontName = pBulletFont->GetName();
488
489 pPseudoFont = new wwFont( sFontName, pBulletFont->GetPitch(),
490 eFamily, eChrSet, HackIsWW8OrHigher() );
491 }
492 else
493 pOutSet = &rFmt.GetCharFmt()->GetAttrSet();
494 }
495
496 sal_Int16 nIndentAt = 0;
497 sal_Int16 nFirstLineIndex = 0;
498 sal_Int16 nListTabPos = 0;
499
500 // --> OD 2008-06-03 #i86652#
501 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
502 {
503 nIndentAt = nListTabPos = rFmt.GetAbsLSpace();
504 nFirstLineIndex = GetWordFirstLineOffset(rFmt);
505 }
506 else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
507 {
508 nIndentAt = static_cast<sal_Int16>(rFmt.GetIndentAt());
509 nFirstLineIndex = static_cast<sal_Int16>(rFmt.GetFirstLineIndent());
510 nListTabPos = rFmt.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB?
511 static_cast<sal_Int16>( rFmt.GetListtabPos() ) : 0;
512 }
513
514 AttrOutput().NumberingLevel( nLvl,
515 rFmt.GetStart(),
516 rFmt.GetNumberingType(),
517 rFmt.GetNumAdjust(),
518 aNumLvlPos,
519 nFollow,
520 pPseudoFont, pOutSet,
521 nIndentAt, nFirstLineIndex, nListTabPos,
522 sNumStr,
523 rFmt.GetNumberingType()==SVX_NUM_BITMAP ? rFmt.GetBrush():0);//Start for i120928,export graphic bullet,2012.9.25
524
525 delete pPseudoFont;
526 }
527 AttrOutput().EndAbstractNumbering();
528 }
529 delete pConvert;
530 }
531
OutOverrideListTab()532 void WW8Export::OutOverrideListTab()
533 {
534 if( !pUsedNumTbl )
535 return ; // no numbering is used
536
537 // write the "list format override" - LFO
538 sal_uInt16 nCount = pUsedNumTbl->Count();
539 sal_uInt16 n;
540
541 pFib->fcPlfLfo = pTableStrm->Tell();
542 SwWW8Writer::WriteLong( *pTableStrm, nCount );
543
544 for( n = 0; n < nCount; ++n )
545 {
546 SwWW8Writer::WriteLong( *pTableStrm, n + 1 );
547 SwWW8Writer::FillCount( *pTableStrm, 12 );
548 }
549 for( n = 0; n < nCount; ++n )
550 SwWW8Writer::WriteLong( *pTableStrm, -1 ); // no overwrite
551
552 // set len to FIB
553 pFib->lcbPlfLfo = pTableStrm->Tell() - pFib->fcPlfLfo;
554 }
555
OutListNamesTab()556 void WW8Export::OutListNamesTab()
557 {
558 if( !pUsedNumTbl )
559 return ; // no numbering is used
560
561 // write the "list format override" - LFO
562 sal_uInt16 nNms = 0, nCount = pUsedNumTbl->Count();
563
564 pFib->fcSttbListNames = pTableStrm->Tell();
565 SwWW8Writer::WriteShort( *pTableStrm, -1 );
566 SwWW8Writer::WriteLong( *pTableStrm, nCount );
567
568 for( ; nNms < nCount; ++nNms )
569 {
570 const SwNumRule& rRule = *pUsedNumTbl->GetObject( nNms );
571 String sNm;
572 if( !rRule.IsAutoRule() )
573 sNm = rRule.GetName();
574
575 SwWW8Writer::WriteShort( *pTableStrm, sNm.Len() );
576 if (sNm.Len())
577 SwWW8Writer::WriteString16(*pTableStrm, sNm, false);
578 }
579
580 SwWW8Writer::WriteLong( *pTableStrm, pFib->fcSttbListNames + 2, nNms );
581 // set len to FIB
582 pFib->lcbSttbListNames = pTableStrm->Tell() - pFib->fcSttbListNames;
583 }
584
585 /* */
586
587 // old WW95-Code
588
OutputOlst(const SwNumRule & rRule)589 void WW8Export::OutputOlst( const SwNumRule& rRule )
590 {
591 if ( bWrtWW8 )
592 return;
593
594 static sal_uInt8 __READONLY_DATA aAnlvBase[] = { // Defaults
595 1,0,0, // Upper Roman
596 0x0C, // Hanging Indent, fPrev
597 0,0,1,0x80,0,0,1,0,0x1b,1,0,0 };
598
599 static sal_uInt8 __READONLY_DATA aSprmOlstHdr[] = { 133, 212 };
600
601 pO->Insert( aSprmOlstHdr, sizeof( aSprmOlstHdr ), pO->Count() );
602 WW8_OLST aOlst;
603 memset( &aOlst, 0, sizeof(aOlst) );
604 sal_uInt8* pC = aOlst.rgch;
605 sal_uInt8* pChars = (sal_uInt8*)pC;
606 sal_uInt16 nCharLen = 64;
607
608 for (sal_uInt16 j = 0; j < WW8ListManager::nMaxLevel; j++ ) // 9 variable ANLVs
609 {
610 memcpy( &aOlst.rganlv[j], aAnlvBase, sizeof( WW8_ANLV ) ); // Defaults
611
612 const SwNumFmt* pFmt = rRule.GetNumFmt( j );
613 if( pFmt )
614 BuildAnlvBase( aOlst.rganlv[j], pChars, nCharLen, rRule,
615 *pFmt, (sal_uInt8)j );
616 }
617
618 pO->Insert( (sal_uInt8*)&aOlst, sizeof( aOlst ), pO->Count() );
619 }
620
621
Out_WwNumLvl(sal_uInt8 nWwLevel)622 void WW8Export::Out_WwNumLvl( sal_uInt8 nWwLevel )
623 {
624 pO->Insert( 13, pO->Count() );
625 pO->Insert( nWwLevel, pO->Count() );
626 }
627
Out_SwNumLvl(sal_uInt8 nSwLevel)628 void WW8Export::Out_SwNumLvl( sal_uInt8 nSwLevel )
629 {
630 // --> OD 2008-04-02 #refactorlists#
631 // ASSERT(IsNum(nSwLevel), "numbered?");
632 ASSERT( nSwLevel < MAXLEVEL, "numbered?");
633 // <--
634 Out_WwNumLvl( nSwLevel + 1 );
635 }
636
BuildAnlvBulletBase(WW8_ANLV & rAnlv,sal_uInt8 * & rpCh,sal_uInt16 & rCharLen,const SwNumFmt & rFmt)637 void WW8Export::BuildAnlvBulletBase(WW8_ANLV& rAnlv, sal_uInt8*& rpCh,
638 sal_uInt16& rCharLen, const SwNumFmt& rFmt)
639 {
640 ByteToSVBT8(11, rAnlv.nfc);
641
642 sal_uInt8 nb = 0; // Zahlentyp
643 switch (rFmt.GetNumAdjust())
644 {
645 case SVX_ADJUST_RIGHT:
646 nb = 2;
647 break;
648 case SVX_ADJUST_CENTER:
649 nb = 1;
650 break;
651 case SVX_ADJUST_BLOCK:
652 case SVX_ADJUST_BLOCKLINE:
653 nb = 3;
654 break;
655 case SVX_ADJUST_LEFT:
656 case SVX_ADJUST_END:
657 break;
658 }
659
660 // --> OD 2008-06-03 #i86652#
661 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
662 {
663 if (GetWordFirstLineOffset(rFmt) < 0)
664 nb |= 0x8; // number will be displayed using a hanging indent
665 }
666 // <--
667 ByteToSVBT8(nb, rAnlv.aBits1);
668
669 if (1 < rCharLen)
670 {
671 // --> OD 2006-06-27 #b6440955#
672 // const Font& rFont = rFmt.GetBulletFont() ? *rFmt.GetBulletFont()
673 // : SwNumRule::GetDefBulletFont();
674 const Font& rFont = rFmt.GetBulletFont()
675 ? *rFmt.GetBulletFont()
676 : numfunc::GetDefBulletFont();
677 // <--
678 String sNumStr = rFmt.GetBulletChar();
679 rtl_TextEncoding eChrSet = rFont.GetCharSet();
680 String sFontName = rFont.GetName();
681
682 sal_uInt16 nFontId;
683 if (sw::util::IsStarSymbol(sFontName))
684 {
685 /*
686 If we are starsymbol then in ww7- mode we will always convert to a
687 windows 8bit symbol font and an index into it, to conversion to
688 8 bit is complete at this stage.
689 */
690 SubstituteBullet(sNumStr, eChrSet, sFontName);
691 wwFont aPseudoFont(sFontName, rFont.GetPitch(), rFont.GetFamily(),
692 eChrSet, bWrtWW8);
693 nFontId = maFontHelper.GetId(aPseudoFont);
694 *rpCh = static_cast<sal_uInt8>(sNumStr.GetChar(0));
695 }
696 else
697 {
698 /*
699 Otherwise we are a unicode char and need to be converted back to
700 an 8 bit format. We happen to know that if the font is already an
701 8 bit windows font currently, staroffice promotes the char into
702 the F000->F0FF range, so we can undo this, and we'll be back to
703 the equivalent 8bit location, otherwise we have to convert from
704 true unicode to an 8bit charset
705 */
706 nFontId = maFontHelper.GetId(rFont);
707 sal_Unicode cChar = sNumStr.GetChar(0);
708 if ( (eChrSet == RTL_TEXTENCODING_SYMBOL) && (cChar >= 0xF000) && (
709 cChar <= 0xF0FF) )
710 {
711 *rpCh = static_cast< sal_uInt8 >(cChar - 0xF000);
712 }
713 else
714 *rpCh = ByteString::ConvertFromUnicode(cChar, eChrSet);
715 }
716 rpCh++;
717 rCharLen--;
718 ShortToSVBT16(nFontId, rAnlv.ftc);
719 ByteToSVBT8( 1, rAnlv.cbTextBefore );
720 }
721 // --> OD 2008-06-03 #i86652#
722 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
723 {
724 ShortToSVBT16( -GetWordFirstLineOffset(rFmt), rAnlv.dxaIndent );
725 ShortToSVBT16( rFmt.GetCharTextDistance(), rAnlv.dxaSpace );
726 }
727 else
728 {
729 ShortToSVBT16( 0, rAnlv.dxaIndent );
730 ShortToSVBT16( 0, rAnlv.dxaSpace );
731 }
732 // <--
733 }
734
SubstituteBullet(String & rNumStr,rtl_TextEncoding & rChrSet,String & rFontName) const735 void MSWordExportBase::SubstituteBullet( String& rNumStr,
736 rtl_TextEncoding& rChrSet, String& rFontName ) const
737 {
738 StarSymbolToMSMultiFont *pConvert = 0;
739 FontFamily eFamily = FAMILY_DECORATIVE;
740
741 if (!bSubstituteBullets)
742 return;
743
744 if (!pConvert)
745 {
746 pConvert = CreateStarSymbolToMSMultiFont();
747 #ifdef DUMPSYMBOLS
748 ::std::ofstream output("fontdebug");
749 for (sal_Unicode i=0xE000;i<0xF8FF;i++)
750 {
751 String sFont = pConvert->ConvertChar(i);
752 if (sFont.Len())
753 output << ::std::hex << i << std::endl;
754 }
755 #endif
756 }
757 sal_Unicode cChar = rNumStr.GetChar(0);
758 String sFont = pConvert->ConvertChar(cChar);
759
760 if (sFont.Len())
761 {
762 rNumStr = static_cast< sal_Unicode >(cChar | 0xF000);
763 rFontName = sFont;
764 rChrSet = RTL_TEXTENCODING_SYMBOL;
765 }
766 else if ( HackIsWW8OrHigher() &&
767 (rNumStr.GetChar(0) < 0xE000 || rNumStr.GetChar(0) > 0xF8FF) )
768 {
769 /*
770 Ok we can't fit into a known windows unicode font, but
771 we are not in the private area, so we are a
772 standardized symbol, so turn off the symbol bit and
773 let words own font substitution kick in
774 */
775 rChrSet = RTL_TEXTENCODING_UNICODE;
776 eFamily = FAMILY_SWISS;
777 rFontName = ::GetFontToken(rFontName, 0);
778 }
779 else
780 {
781 /*
782 Well we don't have an available substition, and we're
783 in our private area, so give up and show a standard
784 bullet symbol
785 */
786 rFontName.ASSIGN_CONST_ASC("Wingdings");
787 rNumStr = static_cast< sal_Unicode >(0x6C);
788 }
789 delete pConvert;
790 }
791
SwWw8_InsertAnlText(const String & rStr,sal_uInt8 * & rpCh,sal_uInt16 & rCharLen,SVBT8 & r8Len)792 static void SwWw8_InsertAnlText( const String& rStr, sal_uInt8*& rpCh,
793 sal_uInt16& rCharLen, SVBT8& r8Len )
794 {
795 sal_uInt8 nb = 0;
796 WW8Bytes aO;
797 SwWW8Writer::InsAsString8( aO, rStr, RTL_TEXTENCODING_MS_1252 );
798
799 sal_uInt16 nCnt = aO.Count();
800 if( nCnt && nCnt < rCharLen )
801 {
802 nb = (sal_uInt8)nCnt;
803 memcpy( rpCh, aO.GetData(), nCnt );
804 rpCh += nCnt;
805 rCharLen = rCharLen - nCnt;
806 }
807 ByteToSVBT8( nb, r8Len );
808 }
809
BuildAnlvBase(WW8_ANLV & rAnlv,sal_uInt8 * & rpCh,sal_uInt16 & rCharLen,const SwNumRule & rRul,const SwNumFmt & rFmt,sal_uInt8 nSwLevel)810 void WW8Export::BuildAnlvBase(WW8_ANLV& rAnlv, sal_uInt8*& rpCh,
811 sal_uInt16& rCharLen, const SwNumRule& rRul, const SwNumFmt& rFmt,
812 sal_uInt8 nSwLevel)
813 {
814 ByteToSVBT8(WW8Export::GetNumId(rFmt.GetNumberingType()), rAnlv.nfc);
815
816 sal_uInt8 nb = 0;
817 switch (rFmt.GetNumAdjust())
818 {
819 case SVX_ADJUST_RIGHT:
820 nb = 2;
821 break;
822 case SVX_ADJUST_CENTER:
823 nb = 1;
824 break;
825 case SVX_ADJUST_BLOCK:
826 case SVX_ADJUST_BLOCKLINE:
827 nb = 3;
828 break;
829 case SVX_ADJUST_LEFT:
830 case SVX_ADJUST_END:
831 break;
832 }
833
834 bool bInclUpper = rFmt.GetIncludeUpperLevels() > 0;
835 if( bInclUpper )
836 nb |= 0x4; // include previous levels
837
838 if (GetWordFirstLineOffset(rFmt) < 0)
839 nb |= 0x8; // number will be displayed using a hanging indent
840 ByteToSVBT8( nb, rAnlv.aBits1 );
841
842 if( bInclUpper && !rRul.IsContinusNum() )
843 {
844 if( (nSwLevel >= WW8ListManager::nMinLevel )
845 && (nSwLevel<= WW8ListManager::nMaxLevel )
846 && (rFmt.GetNumberingType() != SVX_NUM_NUMBER_NONE ) ) // UEberhaupt Nummerierung ?
847 { // -> suche, ob noch Zahlen davor
848 sal_uInt8 nUpper = rFmt.GetIncludeUpperLevels();
849 if( (nUpper <= WW8ListManager::nMaxLevel) &&
850 (rRul.Get(nUpper).GetNumberingType() != SVX_NUM_NUMBER_NONE ) ) // Nummerierung drueber ?
851 {
852 // dann Punkt einfuegen
853 SwWw8_InsertAnlText( aDotStr, rpCh, rCharLen,
854 rAnlv.cbTextBefore );
855 }
856
857 }
858 }
859 else
860 {
861 SwWw8_InsertAnlText( rFmt.GetPrefix(), rpCh, rCharLen,
862 rAnlv.cbTextBefore );
863 SwWw8_InsertAnlText( rFmt.GetSuffix(), rpCh, rCharLen,
864 rAnlv.cbTextAfter );
865 }
866
867 ShortToSVBT16( rFmt.GetStart(), rAnlv.iStartAt );
868 // --> OD 2008-06-03 #i86652#
869 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
870 {
871 ShortToSVBT16( -GetWordFirstLineOffset(rFmt), rAnlv.dxaIndent );
872 ShortToSVBT16( rFmt.GetCharTextDistance(), rAnlv.dxaSpace );
873 }
874 else
875 {
876 ShortToSVBT16( 0, rAnlv.dxaIndent );
877 ShortToSVBT16( 0, rAnlv.dxaSpace );
878 }
879 // <--
880 }
881
Out_NumRuleAnld(const SwNumRule & rRul,const SwNumFmt & rFmt,sal_uInt8 nSwLevel)882 void WW8Export::Out_NumRuleAnld( const SwNumRule& rRul, const SwNumFmt& rFmt,
883 sal_uInt8 nSwLevel )
884 {
885 static sal_uInt8 __READONLY_DATA aSprmAnldDefault[54] = {
886 12, 52,
887 1,0,0,0x0c,0,0,1,0x80,0,0,1,0,0x1b,1,0,0,0x2e,
888 0,0,0,
889 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
890 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
891 sal_uInt8 aSprmAnld[54];
892
893 memcpy( aSprmAnld, aSprmAnldDefault, sizeof( aSprmAnld ) );
894 WW8_ANLD* pA = (WW8_ANLD*)(aSprmAnld + 2); // handlicher Pointer
895
896 sal_uInt8* pChars = (sal_uInt8*)(pA->rgchAnld);
897 sal_uInt16 nCharLen = 31;
898
899 if( nSwLevel == 11 )
900 BuildAnlvBulletBase( pA->eAnlv, pChars, nCharLen, rFmt );
901 else
902 BuildAnlvBase( pA->eAnlv, pChars, nCharLen, rRul, rFmt, nSwLevel );
903
904 // ... und raus damit
905 OutSprmBytes( (sal_uInt8*)&aSprmAnld, sizeof( aSprmAnld ) );
906 }
907
908
909 // Return: ist es eine Gliederung ?
Out_SwNum(const SwTxtNode * pNd)910 bool WW8Export::Out_SwNum(const SwTxtNode* pNd)
911 {
912 int nLevel = pNd->GetActualListLevel();
913
914 if (nLevel < 0 || nLevel >= MAXLEVEL)
915 {
916 ASSERT(sal_False, "Invalid level");
917
918 return false;
919 }
920
921 sal_uInt8 nSwLevel = static_cast< sal_uInt8 >(nLevel);
922
923 const SwNumRule* pRul = pNd->GetNumRule();
924 if( !pRul || nSwLevel == WW8ListManager::nMaxLevel)
925 return false;
926
927 bool bRet = true;
928
929 SwNumFmt aFmt(pRul->Get(nSwLevel));
930 // --> OD 2008-06-03 #i86652#
931 if ( aFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
932 {
933 const SvxLRSpaceItem& rLR = ItemGet<SvxLRSpaceItem>(*pNd, RES_LR_SPACE);
934 aFmt.SetAbsLSpace(writer_cast<short>(aFmt.GetAbsLSpace() + rLR.GetLeft()));
935 }
936
937 if (
938 aFmt.GetNumberingType() == SVX_NUM_NUMBER_NONE ||
939 aFmt.GetNumberingType() == SVX_NUM_CHAR_SPECIAL ||
940 aFmt.GetNumberingType() == SVX_NUM_BITMAP
941 )
942 {
943 // Aufzaehlung
944 // --> OD 2008-04-02 #refactorlists#
945 // Out_WwNumLvl(bNoNum ? 12 : 11);
946 Out_WwNumLvl(11);
947 // <--
948 Out_NumRuleAnld(*pRul, aFmt, 11);
949 bRet = false;
950 }
951 else if (
952 pRul->IsContinusNum() ||
953 (pRul->Get(1).GetIncludeUpperLevels() <= 1)
954 )
955 {
956 // Nummerierung
957 // --> OD 2008-04-02 #refactorlists#
958 // Out_WwNumLvl(bNoNum ? 12 : 10);
959 Out_WwNumLvl(10);
960 // <--
961 Out_NumRuleAnld(*pRul, aFmt, 10);
962 bRet = false;
963 }
964 else
965 {
966 // Gliederung
967 // --> OD 2008-04-02 #refactorlists#
968 // Out_SwNumLvl(bNoNum ? 12 : nSwLevel);
969 Out_SwNumLvl(nSwLevel);
970 // <--
971 Out_NumRuleAnld(*pRul, aFmt, nSwLevel);
972 }
973 return bRet;
974 }
975
976 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
977