xref: /aoo4110/main/sw/source/filter/ww8/wrtw8num.cxx (revision b1cdbd2c)
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