xref: /trunk/main/sc/source/filter/excel/xestyle.cxx (revision b77af630)
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_scfilt.hxx"
26 #include "xestyle.hxx"
27 
28 #include <algorithm>
29 #include <iterator>
30 #include <set>
31 #include <com/sun/star/i18n/ScriptType.hpp>
32 #include <vcl/font.hxx>
33 #include <svl/zformat.hxx>
34 #include <svl/languageoptions.hxx>
35 #include <sfx2/printer.hxx>
36 #include "scitems.hxx"
37 #include <svx/algitem.hxx>
38 #include <editeng/boxitem.hxx>
39 #include <editeng/bolnitem.hxx>
40 #include <svx/rotmodit.hxx>
41 #include <editeng/colritem.hxx>
42 #include <editeng/brshitem.hxx>
43 #include <editeng/frmdiritem.hxx>
44 #include <editeng/eeitem.hxx>
45 #include <editeng/escpitem.hxx>
46 #include "document.hxx"
47 #include "stlpool.hxx"
48 #include "stlsheet.hxx"
49 #include "patattr.hxx"
50 #include "attrib.hxx"
51 #include "globstr.hrc"
52 #include "xestring.hxx"
53 
54 using namespace ::oox;
55 
56 using ::rtl::OString;
57 using ::rtl::OUString;
58 
59 // PALETTE record - color information =========================================
60 
61 namespace {
62 
lclGetWeighting(XclExpColorType eType)63 sal_uInt32 lclGetWeighting( XclExpColorType eType )
64 {
65     switch( eType )
66     {
67         case EXC_COLOR_CHARTLINE:   return 1;
68         case EXC_COLOR_CELLBORDER:
69         case EXC_COLOR_CHARTAREA:   return 2;
70         case EXC_COLOR_CELLTEXT:
71         case EXC_COLOR_CHARTTEXT:
72         case EXC_COLOR_CTRLTEXT:    return 10;
73         case EXC_COLOR_TABBG:
74         case EXC_COLOR_CELLAREA:    return 20;
75         case EXC_COLOR_GRID:        return 50;
76         default:    DBG_ERRORFILE( "lclGetWeighting - unknown color type" );
77     }
78     return 1;
79 }
80 
lclGetColorDistance(const Color & rColor1,const Color & rColor2)81 sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
82 {
83     sal_Int32 nDist = rColor1.GetRed() - rColor2.GetRed();
84     nDist *= nDist * 77;
85     sal_Int32 nDummy = rColor1.GetGreen() - rColor2.GetGreen();
86     nDist += nDummy * nDummy * 151;
87     nDummy = rColor1.GetBlue() - rColor2.GetBlue();
88     nDist += nDummy * nDummy * 28;
89     return nDist;
90 }
91 
lclGetMergedColorComp(sal_uInt8 nComp1,sal_uInt32 nWeight1,sal_uInt8 nComp2,sal_uInt32 nWeight2)92 sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
93 {
94     sal_uInt8 nComp1Dist = ::std::min< sal_uInt8 >( nComp1, 0xFF - nComp1 );
95     sal_uInt8 nComp2Dist = ::std::min< sal_uInt8 >( nComp2, 0xFF - nComp2 );
96     if( nComp1Dist != nComp2Dist )
97     {
98         /*  #i36945# One of the passed RGB components is nearer at the limits (0x00 or 0xFF).
99             Increase its weighting to prevent fading of the colors during reduction. */
100         const sal_uInt8& rnCompNearer = (nComp1Dist < nComp2Dist) ? nComp1 : nComp2;
101         sal_uInt32& rnWeight = (nComp1Dist < nComp2Dist) ? nWeight1 : nWeight2;
102         rnWeight *= ((rnCompNearer - 0x80L) * (rnCompNearer - 0x7FL) / 0x1000L + 1);
103     }
104     sal_uInt32 nWSum = nWeight1 + nWeight2;
105     return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
106 }
107 
lclSetMixedColor(Color & rDest,const Color & rSrc1,const Color & rSrc2)108 void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
109 {
110     rDest.SetRed( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetRed() ) + rSrc2.GetRed()) / 2 ) );
111     rDest.SetGreen( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetGreen() ) + rSrc2.GetGreen()) / 2 ) );
112     rDest.SetBlue( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetBlue() ) + rSrc2.GetBlue()) / 2 ) );
113 }
114 
115 } // namespace
116 
117 // additional classes for color reduction -------------------------------------
118 
119 namespace {
120 
121 /** Represents an entry in a color list.
122 
123     The color stores a weighting value, which increases the more the color is
124     used in the document. Heavy-weighted colors will change less than others on
125     color reduction.
126  */
127 class XclListColor
128 {
129     DECL_FIXEDMEMPOOL_NEWDEL( XclListColor )
130 
131 private:
132     Color               maColor;        /// The color value of this palette entry.
133     sal_uInt32          mnColorId;      /// Unique color ID for color reduction.
134     sal_uInt32          mnWeight;       /// Weighting for color reduction.
135     bool                mbBaseColor;    /// true = Handle as base color, (don't remove/merge).
136 
137 public:
138     explicit            XclListColor( const Color& rColor, sal_uInt32 nColorId );
139 
140     /** Returns the RGB color value of the color. */
GetColor() const141     inline const Color& GetColor() const { return maColor; }
142     /** Returns the unique ID of the color. */
GetColorId() const143     inline sal_uInt32   GetColorId() const { return mnColorId; }
144     /** Returns the current weighting of the color. */
GetWeighting() const145     inline sal_uInt32   GetWeighting() const { return mnWeight; }
146     /** Returns true, if this color is a base color, i.e. it will not be removed or merged. */
IsBaseColor() const147     inline bool         IsBaseColor() const { return mbBaseColor; }
148 
149     /** Adds the passed weighting to this color. */
AddWeighting(sal_uInt32 nWeight)150     inline void         AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
151     /** Merges this color with rColor, regarding weighting settings. */
152     void                Merge( const XclListColor& rColor );
153 };
154 
155 IMPL_FIXEDMEMPOOL_NEWDEL( XclListColor, 100, 100 )
156 
XclListColor(const Color & rColor,sal_uInt32 nColorId)157 XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
158     maColor( rColor ),
159     mnColorId( nColorId ),
160     mnWeight( 0 )
161 {
162     mbBaseColor =
163         ((rColor.GetRed()   == 0x00) || (rColor.GetRed()   == 0xFF)) &&
164         ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
165         ((rColor.GetBlue()  == 0x00) || (rColor.GetBlue()  == 0xFF));
166 }
167 
Merge(const XclListColor & rColor)168 void XclListColor::Merge( const XclListColor& rColor )
169 {
170     sal_uInt32 nWeight2 = rColor.GetWeighting();
171     // do not change RGB value of base colors
172     if( !mbBaseColor )
173     {
174         maColor.SetRed(   lclGetMergedColorComp( maColor.GetRed(),   mnWeight, rColor.maColor.GetRed(),   nWeight2 ) );
175         maColor.SetGreen( lclGetMergedColorComp( maColor.GetGreen(), mnWeight, rColor.maColor.GetGreen(), nWeight2 ) );
176         maColor.SetBlue(  lclGetMergedColorComp( maColor.GetBlue(),  mnWeight, rColor.maColor.GetBlue(),  nWeight2 ) );
177     }
178     AddWeighting( nWeight2 );
179 }
180 
181 // ----------------------------------------------------------------------------
182 
183 /** Data for each inserted original color, represented by a color ID. */
184 struct XclColorIdData
185 {
186     Color               maColor;        /// The original inserted color.
187     sal_uInt32          mnIndex;        /// Maps current color ID to color list or export color vector.
188     /** Sets the contents of this struct. */
Set__anona89dda770211::XclColorIdData189     inline void         Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
190 };
191 
192 /** A color that will be written to the Excel file. */
193 struct XclPaletteColor
194 {
195     Color               maColor;        /// Resulting color to export.
196     bool                mbUsed;         /// true = Entry is used in the document.
197 
XclPaletteColor__anona89dda770211::XclPaletteColor198     inline explicit     XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
SetColor__anona89dda770211::XclPaletteColor199     inline void         SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
200 };
201 
202 /** Maps a color list index to a palette index.
203     @descr  Used to remap the color ID data vector from list indexes to palette indexes. */
204 struct XclRemap
205 {
206     sal_uInt32          mnPalIndex;     /// Index to palette.
207     bool                mbProcessed;    /// true = List color already processed.
208 
XclRemap__anona89dda770211::XclRemap209     inline explicit     XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
SetIndex__anona89dda770211::XclRemap210     inline void         SetIndex( sal_uInt32 nPalIndex )
211                             { mnPalIndex = nPalIndex; mbProcessed = true; }
212 };
213 
214 /** Stores the nearest palette color index of a list color. */
215 struct XclNearest
216 {
217     sal_uInt32          mnPalIndex;     /// Index to nearest palette color.
218     sal_Int32           mnDist;         /// Distance to palette color.
219 
XclNearest__anona89dda770211::XclNearest220     inline explicit     XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
221 };
222 
223 typedef ::std::vector< XclRemap >   XclRemapVec;
224 typedef ::std::vector< XclNearest > XclNearestVec;
225 
226 } // namespace
227 
228 // ----------------------------------------------------------------------------
229 
230 class XclExpPaletteImpl
231 {
232 public:
233     explicit            XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
234 
235     /** Inserts the color into the list and updates weighting.
236         @param nAutoDefault  The Excel palette index for automatic color.
237         @return  A unique ID for this color. */
238     sal_uInt32          InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault = 0 );
239     /** Returns the color ID representing a fixed Excel palette index (i.e. for auto colors). */
240     static sal_uInt32   GetColorIdFromIndex( sal_uInt16 nIndex );
241 
242     /** Reduces the color list to the maximum count of the current BIFF version. */
243     void                Finalize();
244 
245     /** Returns the Excel palette index of the color with passed color ID. */
246     sal_uInt16          GetColorIndex( sal_uInt32 nColorId ) const;
247 
248     /** Returns a foreground and background color for the two passed color IDs.
249         @descr  If rnXclPattern contains a solid pattern, this function tries to find
250         the two best fitting colors and a mix pattern (25%, 50% or 75%) for nForeColorId.
251         This will result in a better approximation to the passed foreground color. */
252     void                GetMixedColors(
253                             sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
254                             sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const;
255 
256     /** Returns the RGB color data for a (non-zero-based) Excel palette entry.
257         @return  The color from current or default palette or COL_AUTO, if nothing else found. */
258     ColorData           GetColorData( sal_uInt16 nXclIndex ) const;
259     /** Returns the color for a (non-zero-based) Excel palette entry.
260         @return  The color from current or default palette or COL_AUTO, if nothing else found. */
GetColor(sal_uInt16 nXclIndex) const261     inline Color        GetColor( sal_uInt16 nXclIndex ) const
262                             { return Color( GetColorData( nXclIndex ) ); }
263 
264     /** Returns true, if all colors of the palette are equal to default palette colors. */
265     bool                IsDefaultPalette() const;
266     /** Writes the color list (contents of the palette record) to the passed stream. */
267     void                WriteBody( XclExpStream& rStrm );
268     void                SaveXml( XclExpXmlStream& rStrm );
269 
270 private:
271     /** Returns the Excel index of a 0-based color index. */
GetXclIndex(sal_uInt32 nIndex) const272     inline sal_uInt16   GetXclIndex( sal_uInt32 nIndex ) const
273                             { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
274 
275     /** Returns the original inserted color represented by the color ID nColorId. */
276     const Color&        GetOriginalColor( sal_uInt32 nColorId ) const;
277 
278     /** Searches for rColor, returns the ordered insertion index for rColor in rnIndex. */
279     XclListColor*       SearchListEntry( const Color& rColor, sal_uInt32& rnIndex );
280     /** Creates and inserts a new color list entry at the specified list position. */
281     XclListColor*       CreateListEntry( const Color& rColor, sal_uInt32 nIndex );
282 
283     /** Raw and fast reduction of the palette. */
284     void                RawReducePalette( sal_uInt32 nPass );
285     /** Reduction of one color using advanced color merging based on color weighting. */
286     void                ReduceLeastUsedColor();
287 
288     /** Finds the least used color and returns its current list index. */
289     sal_uInt32          GetLeastUsedListColor() const;
290     /** Returns the list index of the color nearest to rColor.
291         @param nIgnore  List index of a color which will be ignored.
292         @return  The list index of the found color. */
293     sal_uInt32          GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const;
294     /** Returns the list index of the color nearest to the color with list index nIndex. */
295     sal_uInt32          GetNearestListColor( sal_uInt32 nIndex ) const;
296 
297     /** Returns in rnIndex the palette index of the color nearest to rColor.
298         @param bDefaultOnly  true = Searches for default colors only (colors never replaced).
299         @return  The distance from passed color to found color. */
300     sal_Int32           GetNearestPaletteColor(
301                             sal_uInt32& rnIndex,
302                             const Color& rColor, bool bDefaultOnly ) const;
303     /** Returns in rnFirst and rnSecond the palette indexes of the two colors nearest to rColor.
304         @return  The minimum distance from passed color to found colors. */
305     sal_Int32           GetNearPaletteColors(
306                             sal_uInt32& rnFirst, sal_uInt32& rnSecond,
307                             const Color& rColor ) const;
308 
309 private:
310     typedef ScfDelList< XclListColor >          XclListColorList;
311     typedef ScfRef< XclListColorList >          XclListColorListRef;
312     typedef ::std::vector< XclColorIdData >     XclColorIdDataVec;
313     typedef ::std::vector< XclPaletteColor >    XclPaletteColorVec;
314 
315     const XclDefaultPalette& mrDefPal;      /// The default palette for the current BIFF version.
316     XclListColorListRef mxColorList;        /// Working color list.
317     XclColorIdDataVec   maColorIdDataVec;   /// Data of all CIDs.
318     XclPaletteColorVec  maPalette;          /// Contains resulting colors to export.
319     sal_uInt32          mnLastIdx;          /// Last insertion index for search opt.
320 };
321 
322 // ----------------------------------------------------------------------------
323 
324 const sal_uInt32 EXC_PAL_INDEXBASE          = 0xFFFF0000;
325 const sal_uInt32 EXC_PAL_MAXRAWSIZE         = 1024;
326 
XclExpPaletteImpl(const XclDefaultPalette & rDefPal)327 XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
328     mrDefPal( rDefPal ),
329     mxColorList( new XclListColorList ),
330     mnLastIdx( 0 )
331 {
332     // initialize maPalette with default colors
333     sal_uInt16 nCount = static_cast< sal_uInt16 >( mrDefPal.GetColorCount() );
334     maPalette.reserve( nCount );
335     for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
336         maPalette.push_back( XclPaletteColor( mrDefPal.GetDefColor( GetXclIndex( nIdx ) ) ) );
337 
338     InsertColor( Color( COL_BLACK ), EXC_COLOR_CELLTEXT );
339 }
340 
InsertColor(const Color & rColor,XclExpColorType eType,sal_uInt16 nAutoDefault)341 sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
342 {
343     if( rColor.GetColor() == COL_AUTO )
344         return GetColorIdFromIndex( nAutoDefault );
345 
346     sal_uInt32 nFoundIdx = 0;
347     XclListColor* pEntry = SearchListEntry( rColor, nFoundIdx );
348     if( !pEntry || (pEntry->GetColor() != rColor) )
349         pEntry = CreateListEntry( rColor, nFoundIdx );
350     pEntry->AddWeighting( lclGetWeighting( eType ) );
351 
352     return pEntry->GetColorId();
353 }
354 
GetColorIdFromIndex(sal_uInt16 nIndex)355 sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
356 {
357     return EXC_PAL_INDEXBASE | nIndex;
358 }
359 
Finalize()360 void XclExpPaletteImpl::Finalize()
361 {
362 // --- build initial color ID data vector (maColorIdDataVec) ---
363 
364     sal_uInt32 nCount = mxColorList->Count();
365     maColorIdDataVec.resize( nCount );
366     for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
367     {
368         XclListColor* pListColor = mxColorList->GetObject( nIdx );
369         maColorIdDataVec[ pListColor->GetColorId() ].Set( pListColor->GetColor(), nIdx );
370     }
371 
372 // --- loop as long as current color count does not fit into palette of current BIFF ---
373 
374     // phase 1: raw reduction (performance reasons, #i36945#)
375     sal_uInt32 nPass = 0;
376     while( mxColorList->Count() > EXC_PAL_MAXRAWSIZE )
377         RawReducePalette( nPass++ );
378 
379     // phase 2: precise reduction using advanced color merging based on color weighting
380     while( mxColorList->Count() > mrDefPal.GetColorCount() )
381         ReduceLeastUsedColor();
382 
383 // --- #104865# use default palette and replace colors with nearest used colors ---
384 
385     nCount = mxColorList->Count();
386     XclRemapVec aRemapVec( nCount );
387     XclNearestVec aNearestVec( nCount );
388 
389     // in each run: search the best fitting color and replace a default color with it
390     for( sal_uInt32 nRun = 0; nRun < nCount; ++nRun )
391     {
392         sal_uInt32 nIndex;
393         // find nearest unused default color for each unprocessed list color
394         for( nIndex = 0; nIndex < nCount; ++nIndex )
395             aNearestVec[ nIndex ].mnDist = aRemapVec[ nIndex ].mbProcessed ? SAL_MAX_INT32 :
396                 GetNearestPaletteColor( aNearestVec[ nIndex ].mnPalIndex, mxColorList->GetObject( nIndex )->GetColor(), true );
397         // find the list color which is nearest to a default color
398         sal_uInt32 nFound = 0;
399         for( nIndex = 1; nIndex < nCount; ++nIndex )
400             if( aNearestVec[ nIndex ].mnDist < aNearestVec[ nFound ].mnDist )
401                 nFound = nIndex;
402         // replace default color with list color
403         sal_uInt32 nNearest = aNearestVec[ nFound ].mnPalIndex;
404         DBG_ASSERT( mxColorList->GetObject( nFound ), "XclExpPaletteImpl::Finalize - missing a color" );
405         DBG_ASSERT( nNearest < maPalette.size(), "XclExpPaletteImpl::Finalize - algorithm error" );
406         maPalette[ nNearest ].SetColor( mxColorList->GetObject( nFound )->GetColor() );
407         aRemapVec[ nFound ].SetIndex( nNearest );
408     }
409 
410     // remap color ID data map (maColorIdDataVec) from list indexes to palette indexes
411     for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
412         aIt->mnIndex = aRemapVec[ aIt->mnIndex ].mnPalIndex;
413 }
414 
GetColorIndex(sal_uInt32 nColorId) const415 sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
416 {
417     sal_uInt16 nRet = 0;
418     if( nColorId >= EXC_PAL_INDEXBASE )
419         nRet = static_cast< sal_uInt16 >( nColorId & ~EXC_PAL_INDEXBASE );
420     else if( nColorId < maColorIdDataVec.size() )
421         nRet = GetXclIndex( maColorIdDataVec[ nColorId ].mnIndex );
422     return nRet;
423 }
424 
GetMixedColors(sal_uInt16 & rnXclForeIx,sal_uInt16 & rnXclBackIx,sal_uInt8 & rnXclPattern,sal_uInt32 nForeColorId,sal_uInt32 nBackColorId) const425 void XclExpPaletteImpl::GetMixedColors(
426         sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
427         sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
428 {
429     rnXclForeIx = GetColorIndex( nForeColorId );
430     rnXclBackIx = GetColorIndex( nBackColorId );
431     if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
432         return;
433 
434     // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
435 
436     sal_uInt32 nIndex1, nIndex2;
437     Color aForeColor( GetOriginalColor( nForeColorId ) );
438     sal_Int32 nFirstDist = GetNearPaletteColors( nIndex1, nIndex2, aForeColor );
439     if( (nIndex1 >= maPalette.size()) || (nIndex2 >= maPalette.size()) )
440         return;
441 
442     Color aColorArr[ 5 ];
443     aColorArr[ 0 ] = maPalette[ nIndex1 ].maColor;
444     aColorArr[ 4 ] = maPalette[ nIndex2 ].maColor;
445     lclSetMixedColor( aColorArr[ 2 ], aColorArr[ 0 ], aColorArr[ 4 ] );
446     lclSetMixedColor( aColorArr[ 1 ], aColorArr[ 0 ], aColorArr[ 2 ] );
447     lclSetMixedColor( aColorArr[ 3 ], aColorArr[ 2 ], aColorArr[ 4 ] );
448 
449     sal_Int32 nMinDist = nFirstDist;
450     sal_uInt32 nMinIndex = 0;
451     for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
452     {
453         sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
454         if( nDist < nMinDist )
455         {
456             nMinDist = nDist;
457             nMinIndex = nCnt;
458         }
459     }
460     rnXclForeIx = GetXclIndex( nIndex1 );
461     rnXclBackIx = GetXclIndex( nIndex2 );
462     if( nMinDist < nFirstDist )
463     {
464         switch( nMinIndex )
465         {
466             case 1: rnXclPattern = EXC_PATT_75_PERC;    break;
467             case 2: rnXclPattern = EXC_PATT_50_PERC;    break;
468             case 3: rnXclPattern = EXC_PATT_25_PERC;    break;
469         }
470     }
471 }
472 
GetColorData(sal_uInt16 nXclIndex) const473 ColorData XclExpPaletteImpl::GetColorData( sal_uInt16 nXclIndex ) const
474 {
475     if( nXclIndex >= EXC_COLOR_USEROFFSET )
476     {
477         sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
478         if( nIdx < maPalette.size() )
479             return maPalette[ nIdx ].maColor.GetColor();
480     }
481     return mrDefPal.GetDefColorData( nXclIndex );
482 }
483 
IsDefaultPalette() const484 bool XclExpPaletteImpl::IsDefaultPalette() const
485 {
486     bool bDefault = true;
487     for( sal_uInt32 nIdx = 0, nSize = static_cast< sal_uInt32 >( maPalette.size() ); bDefault && (nIdx < nSize); ++nIdx )
488         bDefault = maPalette[ nIdx ].maColor == mrDefPal.GetDefColor( GetXclIndex( nIdx ) );
489     return bDefault;
490 }
491 
WriteBody(XclExpStream & rStrm)492 void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
493 {
494     rStrm << static_cast< sal_uInt16 >( maPalette.size() );
495     for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
496         rStrm << aIt->maColor;
497 }
498 
SaveXml(XclExpXmlStream & rStrm)499 void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
500 {
501     if( !maPalette.size() )
502         return;
503 
504     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
505     rStyleSheet->startElement( XML_colors, FSEND );
506     rStyleSheet->startElement( XML_indexedColors, FSEND );
507     for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
508         rStyleSheet->singleElement( XML_rgbColor,
509                 XML_rgb,    XclXmlUtils::ToOString( aIt->maColor ).getStr(),
510                 FSEND );
511     rStyleSheet->endElement( XML_indexedColors );
512     rStyleSheet->endElement( XML_colors );
513 }
514 
GetOriginalColor(sal_uInt32 nColorId) const515 const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
516 {
517     if( nColorId < maColorIdDataVec.size() )
518         return maColorIdDataVec[ nColorId ].maColor;
519     return maPalette[ 0 ].maColor;
520 }
521 
SearchListEntry(const Color & rColor,sal_uInt32 & rnIndex)522 XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
523 {
524     rnIndex = mnLastIdx;
525     XclListColor* pEntry = mxColorList->GetObject( rnIndex );
526 
527     // search optimization for equal-colored objects occurring repeatedly
528     if( pEntry && (pEntry->GetColor() == rColor) )
529         return pEntry;
530 
531     // binary search for color
532     sal_uInt32 nBegIdx = 0;
533     sal_uInt32 nEndIdx = mxColorList->Count();
534     bool bFound = false;
535     while( !bFound && (nBegIdx < nEndIdx) )
536     {
537         rnIndex = (nBegIdx + nEndIdx) / 2;
538         pEntry = mxColorList->GetObject( rnIndex );
539         bFound = pEntry->GetColor() == rColor;
540         if( !bFound )
541         {
542             if( pEntry->GetColor().GetColor() < rColor.GetColor() )
543                 nBegIdx = rnIndex + 1;
544             else
545                 nEndIdx = rnIndex;
546         }
547     }
548     // not found - use end of range as new insertion position
549     if( !bFound )
550         pEntry = mxColorList->GetObject( rnIndex = nEndIdx );
551 
552     mnLastIdx = rnIndex;
553     return pEntry;
554 }
555 
CreateListEntry(const Color & rColor,sal_uInt32 nIndex)556 XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
557 {
558     XclListColor* pEntry = new XclListColor( rColor, mxColorList->Count() );
559     mxColorList->Insert( pEntry, nIndex );
560     return pEntry;
561 }
562 
RawReducePalette(sal_uInt32 nPass)563 void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
564 {
565     /*  Fast palette reduction - in each call of this function one RGB component
566         of each color is reduced to a lower number of distinct values.
567         Pass 0: Blue is reduced to 128 distinct values.
568         Pass 1: Red is reduced to 128 distinct values.
569         Pass 2: Green is reduced to 128 distinct values.
570         Pass 3: Blue is reduced to 64 distinct values.
571         Pass 4: Red is reduced to 64 distinct values.
572         Pass 5: Green is reduced to 64 distinct values.
573         And so on...
574      */
575 
576     XclListColorListRef xOldList = mxColorList;
577     mxColorList.reset( new XclListColorList );
578 
579     // maps old list indexes to new list indexes, used to update maColorIdDataVec
580     ScfUInt32Vec aListIndexMap;
581     aListIndexMap.reserve( xOldList->Count() );
582 
583     // preparations
584     sal_uInt8 nR, nG, nB;
585     sal_uInt8& rnComp = ((nPass % 3 == 0) ? nB : ((nPass % 3 == 1) ? nR : nG));
586     nPass /= 3;
587     DBG_ASSERT( nPass < 7, "XclExpPaletteImpl::RawReducePalette - reduction not terminated" );
588 
589     static const sal_uInt8 spnFactor2[] = { 0x81, 0x82, 0x84, 0x88, 0x92, 0xAA, 0xFF };
590     sal_uInt8 nFactor1 = static_cast< sal_uInt8 >( 0x02 << nPass );
591     sal_uInt8 nFactor2 = spnFactor2[ nPass ];
592     sal_uInt8 nFactor3 = static_cast< sal_uInt8 >( 0x40 >> nPass );
593 
594     // process each color in the old color list
595     for( sal_uInt32 nIdx = 0, nCount = xOldList->Count(); nIdx < nCount; ++nIdx )
596     {
597         // get the old list entry
598         const XclListColor* pOldEntry = xOldList->GetObject( nIdx );
599         nR = pOldEntry->GetColor().GetRed();
600         nG = pOldEntry->GetColor().GetGreen();
601         nB = pOldEntry->GetColor().GetBlue();
602 
603         /*  Calculate the new RGB component (rnComp points to one of nR, nG, nB).
604             Using integer arithmetic with its rounding errors, the results of
605             this calculation are always exactly in the range 0x00 to 0xFF
606             (simply cutting the lower bits would darken the colors slightly). */
607         sal_uInt32 nNewComp = rnComp;
608         nNewComp /= nFactor1;
609         nNewComp *= nFactor2;
610         nNewComp /= nFactor3;
611         rnComp = static_cast< sal_uInt8 >( nNewComp );
612         Color aNewColor( nR, nG, nB );
613 
614         // find or insert the new color
615         sal_uInt32 nFoundIdx = 0;
616         XclListColor* pNewEntry = SearchListEntry( aNewColor, nFoundIdx );
617         if( !pNewEntry || (pNewEntry->GetColor() != aNewColor) )
618             pNewEntry = CreateListEntry( aNewColor, nFoundIdx );
619         pNewEntry->AddWeighting( pOldEntry->GetWeighting() );
620         aListIndexMap.push_back( nFoundIdx );
621     }
622 
623     // update color ID data map (maps color IDs to color list indexes), replace old by new list indexes
624     for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
625         aIt->mnIndex = aListIndexMap[ aIt->mnIndex ];
626 }
627 
ReduceLeastUsedColor()628 void XclExpPaletteImpl::ReduceLeastUsedColor()
629 {
630     // find a list color to remove
631     sal_uInt32 nRemove = GetLeastUsedListColor();
632     // find its nearest neighbor
633     sal_uInt32 nKeep = GetNearestListColor( nRemove );
634 
635     // merge both colors to one color, remove one color from list
636     XclListColor* pKeepEntry = mxColorList->GetObject( nKeep );
637     XclListColor* pRemoveEntry = mxColorList->GetObject( nRemove );
638     if( pKeepEntry && pRemoveEntry )
639     {
640         // merge both colors (if pKeepEntry is a base color, it will not change)
641         pKeepEntry->Merge( *pRemoveEntry );
642         // remove the less used color, adjust nKeep index if kept color follows removed color
643         mxColorList->Delete( nRemove );
644         if( nKeep > nRemove ) --nKeep;
645 
646         // recalculate color ID data map (maps color IDs to color list indexes)
647         for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
648         {
649             if( aIt->mnIndex > nRemove )
650                 --aIt->mnIndex;
651             else if( aIt->mnIndex == nRemove )
652                 aIt->mnIndex = nKeep;
653         }
654     }
655 }
656 
GetLeastUsedListColor() const657 sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
658 {
659     sal_uInt32 nFound = 0;
660     sal_uInt32 nMinW = SAL_MAX_UINT32;
661 
662     for( sal_uInt32 nIdx = 0, nCount = mxColorList->Count(); nIdx < nCount; ++nIdx )
663     {
664         XclListColor* pEntry = mxColorList->GetObject( nIdx );
665         // ignore the base colors
666         if( !pEntry->IsBaseColor() && (pEntry->GetWeighting() < nMinW) )
667         {
668             nFound = nIdx;
669             nMinW = pEntry->GetWeighting();
670         }
671     }
672     return nFound;
673 }
674 
GetNearestListColor(const Color & rColor,sal_uInt32 nIgnore) const675 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
676 {
677     sal_uInt32 nFound = 0;
678     sal_Int32 nMinD = SAL_MAX_INT32;
679 
680     for( sal_uInt32 nIdx = 0, nCount = mxColorList->Count(); nIdx < nCount; ++nIdx )
681     {
682         if( nIdx != nIgnore )
683         {
684             if( XclListColor* pEntry = mxColorList->GetObject( nIdx ) )
685             {
686                 sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
687                 if( nDist < nMinD )
688                 {
689                     nFound = nIdx;
690                     nMinD = nDist;
691                 }
692             }
693         }
694     }
695     return nFound;
696 }
697 
GetNearestListColor(sal_uInt32 nIndex) const698 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
699 {
700     XclListColor* pEntry = mxColorList->GetObject( nIndex );
701     return pEntry ? GetNearestListColor( pEntry->GetColor(), nIndex ) : 0;
702 }
703 
GetNearestPaletteColor(sal_uInt32 & rnIndex,const Color & rColor,bool bDefaultOnly) const704 sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
705         sal_uInt32& rnIndex, const Color& rColor, bool bDefaultOnly ) const
706 {
707     rnIndex = 0;
708     sal_Int32 nDist = SAL_MAX_INT32;
709 
710     for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
711             aIt != aEnd; ++aIt )
712     {
713         if( !bDefaultOnly || !aIt->mbUsed )
714         {
715             sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
716             if( nCurrDist < nDist )
717             {
718                 rnIndex = aIt - maPalette.begin();
719                 nDist = nCurrDist;
720             }
721         }
722     }
723     return nDist;
724 }
725 
GetNearPaletteColors(sal_uInt32 & rnFirst,sal_uInt32 & rnSecond,const Color & rColor) const726 sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
727         sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
728 {
729     rnFirst = rnSecond = 0;
730     sal_Int32 nDist1 = SAL_MAX_INT32;
731     sal_Int32 nDist2 = SAL_MAX_INT32;
732 
733     for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
734             aIt != aEnd; ++aIt )
735     {
736         sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
737         if( nCurrDist < nDist1 )
738         {
739             rnSecond = rnFirst;
740             nDist2 = nDist1;
741             rnFirst = aIt - maPalette.begin();
742             nDist1 = nCurrDist;
743         }
744         else if( nCurrDist < nDist2 )
745         {
746             rnSecond = aIt - maPalette.begin();
747             nDist2 = nCurrDist;
748         }
749     }
750     return nDist1;
751 }
752 
753 // ----------------------------------------------------------------------------
754 
XclExpPalette(const XclExpRoot & rRoot)755 XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
756     XclDefaultPalette( rRoot ),
757     XclExpRecord( EXC_ID_PALETTE )
758 {
759     mxImpl.reset( new XclExpPaletteImpl( *this ) );
760     SetRecSize( GetColorCount() * 4 + 2 );
761 }
762 
~XclExpPalette()763 XclExpPalette::~XclExpPalette()
764 {
765 }
766 
InsertColor(const Color & rColor,XclExpColorType eType,sal_uInt16 nAutoDefault)767 sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
768 {
769     return mxImpl->InsertColor( rColor, eType, nAutoDefault );
770 }
771 
GetColorIdFromIndex(sal_uInt16 nIndex)772 sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
773 {
774     return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
775 }
776 
Finalize()777 void XclExpPalette::Finalize()
778 {
779     mxImpl->Finalize();
780 }
781 
GetColorIndex(sal_uInt32 nColorId) const782 sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
783 {
784     return mxImpl->GetColorIndex( nColorId );
785 }
786 
GetMixedColors(sal_uInt16 & rnXclForeIx,sal_uInt16 & rnXclBackIx,sal_uInt8 & rnXclPattern,sal_uInt32 nForeColorId,sal_uInt32 nBackColorId) const787 void XclExpPalette::GetMixedColors(
788         sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
789         sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
790 {
791     return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
792 }
793 
GetColorData(sal_uInt16 nXclIndex) const794 ColorData XclExpPalette::GetColorData( sal_uInt16 nXclIndex ) const
795 {
796     return mxImpl->GetColorData( nXclIndex );
797 }
798 
Save(XclExpStream & rStrm)799 void XclExpPalette::Save( XclExpStream& rStrm )
800 {
801     if( !mxImpl->IsDefaultPalette() )
802         XclExpRecord::Save( rStrm );
803 }
804 
SaveXml(XclExpXmlStream & rStrm)805 void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
806 {
807     if( !mxImpl->IsDefaultPalette() )
808         mxImpl->SaveXml( rStrm );
809 }
810 
WriteBody(XclExpStream & rStrm)811 void XclExpPalette::WriteBody( XclExpStream& rStrm )
812 {
813     mxImpl->WriteBody( rStrm );
814 }
815 
816 // FONT record - font information =============================================
817 
818 namespace {
819 
820 typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
821 
lclCheckFontItems(const SfxItemSet & rItemSet,const WhichAndScript & rWAS1,const WhichAndScript & rWAS2,const WhichAndScript & rWAS3)822 sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
823         const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
824 {
825     if( ScfTools::CheckItem( rItemSet, rWAS1.first, false ) ) return rWAS1.second;
826     if( ScfTools::CheckItem( rItemSet, rWAS2.first, false ) ) return rWAS2.second;
827     if( ScfTools::CheckItem( rItemSet, rWAS3.first, false ) ) return rWAS3.second;
828     return 0;
829 };
830 
831 } // namespace
832 
GetFirstUsedScript(const XclExpRoot & rRoot,const SfxItemSet & rItemSet)833 /*static*/ sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
834 {
835     namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
836 
837     /*  #i17050# #i107170# We need to determine which font items are set in the
838         item set, and which script type we should prefer according to the
839         current language settings. */
840 
841     static const WhichAndScript WAS_LATIN( ATTR_FONT, ::com::sun::star::i18n::ScriptType::LATIN );
842     static const WhichAndScript WAS_ASIAN( ATTR_CJK_FONT, ::com::sun::star::i18n::ScriptType::ASIAN );
843     static const WhichAndScript WAS_CMPLX( ATTR_CTL_FONT, ::com::sun::star::i18n::ScriptType::COMPLEX );
844 
845     /*  #114008# do not let a font from a parent style override an explicit
846         cell font. */
847 
848     sal_Int16 nDefScript = rRoot.GetDefApiScript();
849     sal_Int16 nScript = 0;
850     const SfxItemSet* pCurrSet = &rItemSet;
851 
852     while( (nScript == 0) && pCurrSet )
853     {
854         switch( nDefScript )
855         {
856             case ApiScriptType::LATIN:
857                 nScript = lclCheckFontItems( *pCurrSet, WAS_LATIN, WAS_CMPLX, WAS_ASIAN );
858             break;
859             case ApiScriptType::ASIAN:
860                 nScript = lclCheckFontItems( *pCurrSet, WAS_ASIAN, WAS_CMPLX, WAS_LATIN );
861             break;
862             case ApiScriptType::COMPLEX:
863                 nScript = lclCheckFontItems( *pCurrSet, WAS_CMPLX, WAS_ASIAN, WAS_LATIN );
864             break;
865             default:
866                 DBG_ERRORFILE( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
867                 nScript = ApiScriptType::LATIN;
868         };
869         pCurrSet = pCurrSet->GetParent();
870     }
871 
872     return nScript;
873 }
874 
GetFontFromItemSet(const XclExpRoot & rRoot,const SfxItemSet & rItemSet,sal_Int16 nScript)875 /*static*/ Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
876 {
877     namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
878 
879     // if WEAK is passed, guess script type from existing items in the item set
880     if( nScript == ApiScriptType::WEAK )
881         nScript = GetFirstUsedScript( rRoot, rItemSet );
882 
883     // convert to core script type constants
884     sal_uInt8 nScScript = SCRIPTTYPE_LATIN;
885     switch( nScript )
886     {
887         case ApiScriptType::LATIN:      nScScript = SCRIPTTYPE_LATIN;   break;
888         case ApiScriptType::ASIAN:      nScScript = SCRIPTTYPE_ASIAN;   break;
889         case ApiScriptType::COMPLEX:    nScScript = SCRIPTTYPE_COMPLEX; break;
890         default:    DBG_ERRORFILE( "XclExpFontHelper::GetFontFromItemSet - unknown script type" );
891     }
892 
893     // fill the font object
894     Font aFont;
895     ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW, 0, 0, 0, nScScript );
896     return aFont;
897 }
898 
CheckItems(const XclExpRoot & rRoot,const SfxItemSet & rItemSet,sal_Int16 nScript,bool bDeep)899 /*static*/ bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
900 {
901     static const sal_uInt16 pnCommonIds[] = {
902         ATTR_FONT_UNDERLINE, ATTR_FONT_CROSSEDOUT, ATTR_FONT_CONTOUR,
903         ATTR_FONT_SHADOWED, ATTR_FONT_COLOR, ATTR_FONT_LANGUAGE, 0 };
904     static const sal_uInt16 pnLatinIds[] = {
905         ATTR_FONT, ATTR_FONT_HEIGHT, ATTR_FONT_WEIGHT, ATTR_FONT_POSTURE, 0 };
906     static const sal_uInt16 pnAsianIds[] = {
907         ATTR_CJK_FONT, ATTR_CJK_FONT_HEIGHT, ATTR_CJK_FONT_WEIGHT, ATTR_CJK_FONT_POSTURE, 0 };
908     static const sal_uInt16 pnComplexIds[] = {
909         ATTR_CTL_FONT, ATTR_CTL_FONT_HEIGHT, ATTR_CTL_FONT_WEIGHT, ATTR_CTL_FONT_POSTURE, 0 };
910 
911     bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
912     if( !bUsed )
913     {
914         namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
915         // if WEAK is passed, guess script type from existing items in the item set
916         if( nScript == ApiScriptType::WEAK )
917             nScript = GetFirstUsedScript( rRoot, rItemSet );
918         // check the correct items
919         switch( nScript )
920         {
921             case ApiScriptType::LATIN:      bUsed = ScfTools::CheckItems( rItemSet, pnLatinIds, bDeep );    break;
922             case ApiScriptType::ASIAN:      bUsed = ScfTools::CheckItems( rItemSet, pnAsianIds, bDeep );    break;
923             case ApiScriptType::COMPLEX:    bUsed = ScfTools::CheckItems( rItemSet, pnComplexIds, bDeep );  break;
924             default:    DBG_ERRORFILE( "XclExpFontHelper::CheckItems - unknown script type" );
925         }
926     }
927     return bUsed;
928 }
929 
930 // ----------------------------------------------------------------------------
931 
932 namespace {
933 
lclCalcHash(const XclFontData & rFontData)934 sal_uInt32 lclCalcHash( const XclFontData& rFontData )
935 {
936     sal_uInt32 nHash = rFontData.maName.Len();
937     nHash += rFontData.maColor.GetColor() * 2;
938     nHash += rFontData.mnWeight * 3;
939     nHash += rFontData.mnCharSet * 5;
940     nHash += rFontData.mnFamily * 7;
941     nHash += rFontData.mnHeight * 11;
942     nHash += rFontData.mnUnderline * 13;
943     nHash += rFontData.mnEscapem * 17;
944     if( rFontData.mbItalic ) nHash += 19;
945     if( rFontData.mbStrikeout ) nHash += 23;
946     if( rFontData.mbOutline ) nHash += 29;
947     if( rFontData.mbShadow ) nHash += 31;
948     return nHash;
949 }
950 
951 } // namespace
952 
953 // ----------------------------------------------------------------------------
954 
XclExpFont(const XclExpRoot & rRoot,const XclFontData & rFontData,XclExpColorType eColorType)955 XclExpFont::XclExpFont( const XclExpRoot& rRoot,
956         const XclFontData& rFontData, XclExpColorType eColorType ) :
957     XclExpRecord( EXC_ID2_FONT, 14 ),
958     XclExpRoot( rRoot ),
959     maData( rFontData )
960 {
961     // insert font color into palette
962     mnColorId = rRoot.GetPalette().InsertColor( rFontData.maColor, eColorType, EXC_COLOR_FONTAUTO );
963     // hash value for faster comparison
964     mnHash = lclCalcHash( maData );
965     // record size
966     sal_Size nStrLen = maData.maName.Len();
967     SetRecSize( ((GetBiff() == EXC_BIFF8) ? (nStrLen * 2 + 1) : nStrLen) + 15 );
968 }
969 
Equals(const XclFontData & rFontData,sal_uInt32 nHash) const970 bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
971 {
972     return (mnHash == nHash) && (maData == rFontData);
973 }
974 
SaveXml(XclExpXmlStream & rStrm)975 void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
976 {
977     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
978     rStyleSheet->startElement( XML_font, FSEND );
979     rStrm.WriteFontData( maData, XML_name );
980     // OOXTODO: XML_scheme; //scheme/@val values: "major", "minor", "none"
981     rStyleSheet->endElement( XML_font );
982 }
983 
984 // private --------------------------------------------------------------------
985 
WriteBody(XclExpStream & rStrm)986 void XclExpFont::WriteBody( XclExpStream& rStrm )
987 {
988     sal_uInt16 nAttr = EXC_FONTATTR_NONE;
989     ::set_flag( nAttr, EXC_FONTATTR_ITALIC, maData.mbItalic );
990     ::set_flag( nAttr, EXC_FONTATTR_STRIKEOUT, maData.mbStrikeout );
991     ::set_flag( nAttr, EXC_FONTATTR_OUTLINE, maData.mbOutline );
992     ::set_flag( nAttr, EXC_FONTATTR_SHADOW, maData.mbShadow );
993 
994     DBG_ASSERT( maData.maName.Len() < 256, "XclExpFont::WriteBody - font name too long" );
995     XclExpString aFontName;
996     if( GetBiff() <= EXC_BIFF5 )
997         aFontName.AssignByte( maData.maName, GetTextEncoding(), EXC_STR_8BITLENGTH );
998     else
999         aFontName.Assign( maData.maName, EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH );
1000 
1001     rStrm   << maData.mnHeight
1002             << nAttr
1003             << GetPalette().GetColorIndex( mnColorId )
1004             << maData.mnWeight
1005             << maData.mnEscapem
1006             << maData.mnUnderline
1007             << maData.mnFamily
1008             << maData.mnCharSet
1009             << sal_uInt8( 0 )
1010             << aFontName;
1011 }
1012 
1013 // ----------------------------------------------------------------------------
1014 
XclExpBlindFont(const XclExpRoot & rRoot)1015 XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
1016     XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
1017 {
1018 }
1019 
Equals(const XclFontData &,sal_uInt32) const1020 bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
1021 {
1022     return false;
1023 }
1024 
Save(XclExpStream &)1025 void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
1026 {
1027     // do nothing
1028 }
1029 
1030 // ============================================================================
1031 
XclExpFontBuffer(const XclExpRoot & rRoot)1032 XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
1033     XclExpRoot( rRoot ),
1034     mnXclMaxSize( 0 )
1035 {
1036     switch( GetBiff() )
1037     {
1038         case EXC_BIFF4: mnXclMaxSize = EXC_FONT_MAXCOUNT4;  break;
1039         case EXC_BIFF5: mnXclMaxSize = EXC_FONT_MAXCOUNT5;  break;
1040         case EXC_BIFF8: mnXclMaxSize = EXC_FONT_MAXCOUNT8;  break;
1041         default:        DBG_ERROR_BIFF();
1042     }
1043     InitDefaultFonts();
1044 }
1045 
GetFont(sal_uInt16 nXclFont) const1046 const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
1047 {
1048     return maFontList.GetRecord( nXclFont ).get();
1049 }
1050 
GetAppFontData() const1051 const XclFontData& XclExpFontBuffer::GetAppFontData() const
1052 {
1053     return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
1054 }
1055 
Insert(const XclFontData & rFontData,XclExpColorType eColorType,bool bAppFont)1056 sal_uInt16 XclExpFontBuffer::Insert(
1057         const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
1058 {
1059     if( bAppFont )
1060     {
1061         XclExpFontRef xFont( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1062         maFontList.ReplaceRecord( xFont, EXC_FONT_APP );
1063         // #108487# set width of '0' character for column width export
1064         SetCharWidth( xFont->GetFontData() );
1065         return EXC_FONT_APP;
1066     }
1067 
1068     size_t nPos = Find( rFontData );
1069     if( nPos == EXC_FONTLIST_NOTFOUND )
1070     {
1071         // not found in buffer - create new font
1072         size_t nSize = maFontList.GetSize();
1073         if( nSize < mnXclMaxSize )
1074         {
1075             // possible to insert
1076             maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1077             nPos = nSize;       // old size is last position now
1078         }
1079         else
1080         {
1081             // buffer is full - ignore new font, use default font
1082             nPos = EXC_FONT_APP;
1083         }
1084     }
1085     return static_cast< sal_uInt16 >( nPos );
1086 }
1087 
Insert(const Font & rFont,XclExpColorType eColorType,bool bAppFont)1088 sal_uInt16 XclExpFontBuffer::Insert(
1089         const Font& rFont, XclExpColorType eColorType, bool bAppFont )
1090 {
1091     return Insert( XclFontData( rFont ), eColorType, bAppFont );
1092 }
1093 
Insert(const SvxFont & rFont,XclExpColorType eColorType,bool bAppFont)1094 sal_uInt16 XclExpFontBuffer::Insert(
1095         const SvxFont& rFont, XclExpColorType eColorType, bool bAppFont )
1096 {
1097     return Insert( XclFontData( rFont ), eColorType, bAppFont );
1098 }
1099 
Insert(const SfxItemSet & rItemSet,sal_Int16 nScript,XclExpColorType eColorType,bool bAppFont)1100 sal_uInt16 XclExpFontBuffer::Insert( const SfxItemSet& rItemSet,
1101         sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1102 {
1103     // #i17050# #114008# #115495# script type now provided by caller
1104     Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rItemSet, nScript );
1105     return Insert( aFont, eColorType, bAppFont );
1106 }
1107 
Insert(const ScPatternAttr & rPattern,sal_Int16 nScript,XclExpColorType eColorType,bool bAppFont)1108 sal_uInt16 XclExpFontBuffer::Insert( const ScPatternAttr& rPattern,
1109         sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1110 {
1111     return Insert( rPattern.GetItemSet(), nScript, eColorType, bAppFont );
1112 }
1113 
Save(XclExpStream & rStrm)1114 void XclExpFontBuffer::Save( XclExpStream& rStrm )
1115 {
1116     maFontList.Save( rStrm );
1117 }
1118 
SaveXml(XclExpXmlStream & rStrm)1119 void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
1120 {
1121     if( maFontList.IsEmpty() )
1122         return;
1123 
1124     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1125     rStyleSheet->startElement( XML_fonts,
1126             XML_count,  OString::valueOf( (sal_Int32) maFontList.GetSize() ).getStr(),
1127             FSEND );
1128 
1129     maFontList.SaveXml( rStrm );
1130 
1131     rStyleSheet->endElement( XML_fonts );
1132 }
1133 
1134 // private --------------------------------------------------------------------
1135 
InitDefaultFonts()1136 void XclExpFontBuffer::InitDefaultFonts()
1137 {
1138     XclFontData aFontData;
1139     aFontData.maName.AssignAscii( "Arial" );
1140     aFontData.SetScFamily( FAMILY_DONTKNOW );
1141     aFontData.SetFontEncoding( ScfTools::GetSystemTextEncoding() );
1142     aFontData.SetScHeight( 200 );   // 200 twips = 10 pt
1143     aFontData.SetScWeight( WEIGHT_NORMAL );
1144 
1145     switch( GetBiff() )
1146     {
1147         case EXC_BIFF5:
1148         {
1149             maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1150             aFontData.SetScWeight( WEIGHT_BOLD );
1151             maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1152             aFontData.SetScWeight( WEIGHT_NORMAL );
1153             aFontData.SetScPosture( ITALIC_NORMAL );
1154             maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1155             aFontData.SetScWeight( WEIGHT_BOLD );
1156             maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1157             // the blind font with index 4
1158             maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1159             // already add the first user defined font (Excel does it too)
1160             aFontData.SetScWeight( WEIGHT_NORMAL );
1161             aFontData.SetScPosture( ITALIC_NONE );
1162             maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1163         }
1164         break;
1165         case EXC_BIFF8:
1166         {
1167             XclExpFontRef xFont( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1168             maFontList.AppendRecord( xFont );
1169             maFontList.AppendRecord( xFont );
1170             maFontList.AppendRecord( xFont );
1171             maFontList.AppendRecord( xFont );
1172             if( GetOutput() == EXC_OUTPUT_BINARY )
1173                 // the blind font with index 4
1174                 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1175         }
1176         break;
1177         default:
1178             DBG_ERROR_BIFF();
1179     }
1180 }
1181 
Find(const XclFontData & rFontData)1182 size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
1183 {
1184     sal_uInt32 nHash = lclCalcHash( rFontData );
1185     for( size_t nPos = 0, nSize = maFontList.GetSize(); nPos < nSize; ++nPos )
1186         if( maFontList.GetRecord( nPos )->Equals( rFontData, nHash ) )
1187             return nPos;
1188     return EXC_FONTLIST_NOTFOUND;
1189 }
1190 
1191 // FORMAT record - number formats =============================================
1192 
1193 /** Predicate for search algorithm. */
1194 struct XclExpNumFmtPred
1195 {
1196     sal_uLong               mnScNumFmt;
XclExpNumFmtPredXclExpNumFmtPred1197     inline explicit     XclExpNumFmtPred( sal_uLong nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
operator ()XclExpNumFmtPred1198     inline bool         operator()( const XclExpNumFmt& rFormat ) const
1199                             { return rFormat.mnScNumFmt == mnScNumFmt; }
1200 };
1201 
1202 // ----------------------------------------------------------------------------
1203 
XclExpNumFmtBuffer(const XclExpRoot & rRoot)1204 XclExpNumFmtBuffer::XclExpNumFmtBuffer( const XclExpRoot& rRoot ) :
1205     XclExpRoot( rRoot ),
1206     /*  Compiler needs a hint, this doesn't work: new NfKeywordTable;
1207         cannot convert from 'class String *' to 'class String (*)[54]'
1208         The effective result here is class String (*)[54*1] */
1209     mxFormatter( new SvNumberFormatter( rRoot.GetDoc().GetServiceManager(), LANGUAGE_ENGLISH_US ) ),
1210     mpKeywordTable( new NfKeywordTable[ 1 ] ),
1211     mnStdFmt( GetFormatter().GetStandardFormat( ScGlobal::eLnge ) )
1212 {
1213     switch( GetBiff() )
1214     {
1215         case EXC_BIFF5: mnXclOffset = EXC_FORMAT_OFFSET5;   break;
1216         case EXC_BIFF8: mnXclOffset = EXC_FORMAT_OFFSET8;   break;
1217         default:        DBG_ERROR_BIFF();
1218     }
1219 
1220     mxFormatter->FillKeywordTable( *mpKeywordTable, LANGUAGE_ENGLISH_US );
1221     // remap codes unknown to Excel
1222     (*mpKeywordTable)[ NF_KEY_NN ] = String( RTL_CONSTASCII_USTRINGPARAM( "DDD" ) );
1223     (*mpKeywordTable)[ NF_KEY_NNN ] = String( RTL_CONSTASCII_USTRINGPARAM( "DDDD" ) );
1224     // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
1225     (*mpKeywordTable)[ NF_KEY_NNNN ] = String( RTL_CONSTASCII_USTRINGPARAM( "DDDD" ) );
1226     // Export the Thai T NatNum modifier.
1227     (*mpKeywordTable)[ NF_KEY_THAI_T ] = String( RTL_CONSTASCII_USTRINGPARAM( "T" ) );
1228 }
1229 
~XclExpNumFmtBuffer()1230 XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
1231 {
1232     delete[] mpKeywordTable;
1233 }
1234 
Insert(sal_uLong nScNumFmt)1235 sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uLong nScNumFmt )
1236 {
1237     XclExpNumFmtVec::const_iterator aIt =
1238         ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
1239     if( aIt != maFormatMap.end() )
1240         return aIt->mnXclNumFmt;
1241 
1242     size_t nSize = maFormatMap.size();
1243     if( nSize < static_cast< size_t >( 0xFFFF - mnXclOffset ) )
1244     {
1245         sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
1246         maFormatMap.push_back( XclExpNumFmt( nScNumFmt, nXclNumFmt ) );
1247         return nXclNumFmt;
1248     }
1249 
1250     return 0;
1251 }
1252 
Save(XclExpStream & rStrm)1253 void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
1254 {
1255     for( XclExpNumFmtVec::const_iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
1256         WriteFormatRecord( rStrm, *aIt );
1257 }
1258 
SaveXml(XclExpXmlStream & rStrm)1259 void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
1260 {
1261     if( !maFormatMap.size() )
1262         return;
1263 
1264     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1265     rStyleSheet->startElement( XML_numFmts,
1266             XML_count,  OString::valueOf( (sal_Int32) maFormatMap.size() ).getStr(),
1267             FSEND );
1268     for( XclExpNumFmtVec::const_iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
1269     {
1270         rStyleSheet->singleElement( XML_numFmt,
1271                 XML_numFmtId,   OString::valueOf( sal_Int32(aIt->mnXclNumFmt) ).getStr(),
1272                 XML_formatCode, XclXmlUtils::ToOString( GetFormatCode( *aIt ) ).getStr(),
1273                 FSEND );
1274     }
1275     rStyleSheet->endElement( XML_numFmts );
1276 }
1277 
WriteFormatRecord(XclExpStream & rStrm,sal_uInt16 nXclNumFmt,const String & rFormatStr)1278 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const String& rFormatStr )
1279 {
1280     XclExpString aExpStr;
1281     if( GetBiff() <= EXC_BIFF5 )
1282         aExpStr.AssignByte( rFormatStr, GetTextEncoding(), EXC_STR_8BITLENGTH );
1283     else
1284         aExpStr.Assign( rFormatStr );
1285 
1286     rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
1287     rStrm << nXclNumFmt << aExpStr;
1288     rStrm.EndRecord();
1289 }
1290 
WriteFormatRecord(XclExpStream & rStrm,const XclExpNumFmt & rFormat)1291 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
1292 {
1293     WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat ) );
1294 }
1295 
GetFormatCode(const XclExpNumFmt & rFormat)1296 String XclExpNumFmtBuffer::GetFormatCode( const XclExpNumFmt& rFormat )
1297 {
1298     String aFormatStr;
1299 
1300     if( const SvNumberformat* pEntry = GetFormatter().GetEntry( rFormat.mnScNumFmt ) )
1301     {
1302         if( pEntry->GetType() == NUMBERFORMAT_LOGICAL )
1303         {
1304             // build Boolean number format
1305             Color* pColor = 0;
1306             String aTemp;
1307             const_cast< SvNumberformat* >( pEntry )->GetOutputString( 1.0, aTemp, &pColor );
1308             aFormatStr.Append( '"' ).Append( aTemp ).AppendAscii( "\";\"" ).Append( aTemp ).AppendAscii( "\";\"" );
1309             const_cast< SvNumberformat* >( pEntry )->GetOutputString( 0.0, aTemp, &pColor );
1310             aFormatStr.Append( aTemp ).Append( '"' );
1311         }
1312         else
1313         {
1314             LanguageType eLang = pEntry->GetLanguage();
1315             if( eLang != LANGUAGE_ENGLISH_US )
1316             {
1317                 xub_StrLen nCheckPos;
1318                 short nType = NUMBERFORMAT_DEFINED;
1319                 sal_uInt32 nKey;
1320                 String aTemp( pEntry->GetFormatstring() );
1321                 mxFormatter->PutandConvertEntry( aTemp, nCheckPos, nType, nKey, eLang, LANGUAGE_ENGLISH_US );
1322                 DBG_ASSERT( nCheckPos == 0, "XclExpNumFmtBuffer::WriteFormatRecord - format code not convertible" );
1323                 pEntry = mxFormatter->GetEntry( nKey );
1324             }
1325 
1326             aFormatStr = pEntry->GetMappedFormatstring( *mpKeywordTable, *mxFormatter->GetLocaleData() );
1327             if( aFormatStr.EqualsAscii( "Standard" ) )
1328                 aFormatStr.AssignAscii( "General" );
1329         }
1330     }
1331     else
1332     {
1333         DBG_ERRORFILE( "XclExpNumFmtBuffer::WriteFormatRecord - format not found" );
1334         aFormatStr.AssignAscii( "General" );
1335     }
1336 
1337     return aFormatStr;
1338 }
1339 
1340 // XF, STYLE record - Cell formatting =========================================
1341 
FillFromItemSet(const SfxItemSet & rItemSet,bool bStyle)1342 bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
1343 {
1344     const ScProtectionAttr& rProtItem = GETITEM( rItemSet, ScProtectionAttr, ATTR_PROTECTION );
1345     mbLocked = rProtItem.GetProtection();
1346     mbHidden = rProtItem.GetHideFormula() || rProtItem.GetHideCell();
1347     return ScfTools::CheckItem( rItemSet, ATTR_PROTECTION, bStyle );
1348 }
1349 
1350 #if 0
1351 void XclExpCellProt::FillToXF2( sal_uInt8& rnNumFmt ) const
1352 {
1353     ::set_flag( rnNumFmt, EXC_XF2_LOCKED, mbLocked );
1354     ::set_flag( rnNumFmt, EXC_XF2_HIDDEN, mbHidden );
1355 }
1356 #endif
1357 
FillToXF3(sal_uInt16 & rnProt) const1358 void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
1359 {
1360     ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
1361     ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
1362 }
1363 
SaveXml(XclExpXmlStream & rStrm) const1364 void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
1365 {
1366     rStrm.GetCurrentStream()->singleElement( XML_protection,
1367             XML_locked,     XclXmlUtils::ToPsz( mbLocked ),
1368             XML_hidden,     XclXmlUtils::ToPsz( mbHidden ),
1369             FSEND );
1370 }
1371 
1372 // ----------------------------------------------------------------------------
1373 
FillFromItemSet(const SfxItemSet & rItemSet,bool bForceLineBreak,XclBiff eBiff,bool bStyle)1374 bool XclExpCellAlign::FillFromItemSet(
1375         const SfxItemSet& rItemSet, bool bForceLineBreak, XclBiff eBiff, bool bStyle )
1376 {
1377     bool bUsed = false;
1378 
1379     switch( eBiff )
1380     {
1381         // ALL 'case's - run through!
1382 
1383         case EXC_BIFF8: // attributes new in BIFF8
1384         {
1385             // text indent
1386             long nTmpIndent = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_INDENT, sal_Int32 );
1387             (nTmpIndent += 100) /= 200; // 1 Excel unit == 10 pt == 200 twips
1388             mnIndent = limit_cast< sal_uInt8 >( nTmpIndent, 0, 15 );
1389             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_INDENT, bStyle );
1390 
1391             // shrink to fit
1392             mbShrink = GETITEMVALUE( rItemSet, SfxBoolItem, ATTR_SHRINKTOFIT, sal_Bool );
1393             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
1394 
1395             // CTL text direction
1396             SetScFrameDir( GETITEMVALUE( rItemSet, SvxFrameDirectionItem, ATTR_WRITINGDIR, SvxFrameDirection ) );
1397             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
1398         }
1399 
1400         case EXC_BIFF5: // attributes new in BIFF5
1401         case EXC_BIFF4: // attributes new in BIFF4
1402         {
1403             // vertical alignment
1404             SetScVerAlign( GETITEMVALUE( rItemSet, SvxVerJustifyItem, ATTR_VER_JUSTIFY, SvxCellVerJustify ) );
1405             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
1406 
1407             // stacked/rotation
1408             bool bStacked = GETITEMVALUE( rItemSet, SfxBoolItem, ATTR_STACKED, sal_Bool );
1409             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
1410             if( bStacked )
1411             {
1412                 mnRotation = EXC_ROT_STACKED;
1413             }
1414             else
1415             {
1416                 // rotation
1417                 sal_Int32 nScRot = GETITEMVALUE( rItemSet, SfxInt32Item, ATTR_ROTATE_VALUE, sal_Int32 );
1418                 mnRotation = XclTools::GetXclRotation( nScRot );
1419                 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_ROTATE_VALUE, bStyle );
1420             }
1421             mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
1422         }
1423 
1424         case EXC_BIFF3: // attributes new in BIFF3
1425         {
1426             // text wrap
1427             mbLineBreak = bForceLineBreak || GETITEMBOOL( rItemSet, ATTR_LINEBREAK );
1428             bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
1429         }
1430 
1431         case EXC_BIFF2: // attributes new in BIFF2
1432         {
1433             // horizontal alignment
1434             SetScHorAlign( GETITEMVALUE( rItemSet, SvxHorJustifyItem, ATTR_HOR_JUSTIFY, SvxCellHorJustify ) );
1435             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
1436         }
1437 
1438         break;
1439         default:    DBG_ERROR_BIFF();
1440     }
1441 
1442     return bUsed;
1443 }
1444 
1445 #if 0
1446 void XclExpCellAlign::FillToXF2( sal_uInt8& rnFlags ) const
1447 {
1448     ::insert_value( rnFlags, mnHorAlign, 0, 3 );
1449 }
1450 
1451 void XclExpCellAlign::FillToXF3( sal_uInt16& rnAlign ) const
1452 {
1453     ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1454     ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1455 }
1456 
1457 void XclExpCellAlign::FillToXF4( sal_uInt16& rnAlign ) const
1458 {
1459     FillToXF3( rnAlign );
1460     ::insert_value( rnAlign, mnVerAlign, 4, 2 );
1461     ::insert_value( rnAlign, mnOrient, 6, 2 );
1462 }
1463 #endif
1464 
FillToXF5(sal_uInt16 & rnAlign) const1465 void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
1466 {
1467     ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1468     ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1469     ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1470     ::insert_value( rnAlign, mnOrient, 8, 2 );
1471 }
1472 
FillToXF8(sal_uInt16 & rnAlign,sal_uInt16 & rnMiscAttrib) const1473 void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
1474 {
1475     ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1476     ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1477     ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1478     ::insert_value( rnAlign, mnRotation, 8, 8 );
1479     ::insert_value( rnMiscAttrib, mnIndent, 0, 4 );
1480     ::set_flag( rnMiscAttrib, EXC_XF8_SHRINK, mbShrink );
1481     ::insert_value( rnMiscAttrib, mnTextDir, 6, 2 );
1482 }
1483 
ToHorizontalAlignment(sal_uInt8 nHorAlign)1484 static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
1485 {
1486     switch( nHorAlign )
1487     {
1488         case EXC_XF_HOR_GENERAL:    return "general";
1489         case EXC_XF_HOR_LEFT:       return "left";
1490         case EXC_XF_HOR_CENTER:     return "center";
1491         case EXC_XF_HOR_RIGHT:      return "right";
1492         case EXC_XF_HOR_FILL:       return "fill";
1493         case EXC_XF_HOR_JUSTIFY:    return "justify";
1494         case EXC_XF_HOR_CENTER_AS:  return "centerContinuous";
1495         case EXC_XF_HOR_DISTRIB:    return "distributed";
1496     }
1497     return "*unknown*";
1498 }
1499 
ToVerticalAlignment(sal_uInt8 nVerAlign)1500 static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
1501 {
1502     switch( nVerAlign )
1503     {
1504         case EXC_XF_VER_TOP:        return "top";
1505         case EXC_XF_VER_CENTER:     return "center";
1506         case EXC_XF_VER_BOTTOM:     return "bottom";
1507         case EXC_XF_VER_JUSTIFY:    return "justify";
1508         case EXC_XF_VER_DISTRIB:    return "distributed";
1509     }
1510     return "*unknown*";
1511 }
1512 
SaveXml(XclExpXmlStream & rStrm) const1513 void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
1514 {
1515     rStrm.GetCurrentStream()->singleElement( XML_alignment,
1516             XML_horizontal,         ToHorizontalAlignment( mnHorAlign ),
1517             XML_vertical,           ToVerticalAlignment( mnVerAlign ),
1518             XML_textRotation,       OString::valueOf( (sal_Int32) mnRotation ).getStr(),
1519             XML_wrapText,           XclXmlUtils::ToPsz( mbLineBreak ),
1520             XML_indent,             OString::valueOf( (sal_Int32) mnIndent ).getStr(),
1521             // OOXTODO: XML_relativeIndent,     mnIndent?
1522             // OOXTODO: XML_justifyLastLine,
1523             XML_shrinkToFit,        XclXmlUtils::ToPsz( mbShrink ),
1524             // OOXTODO: XML_readingOrder,
1525             FSEND );
1526 }
1527 
1528 // ----------------------------------------------------------------------------
1529 
1530 namespace {
1531 
lclGetBorderLine(sal_uInt8 & rnXclLine,sal_uInt32 & rnColorId,const SvxBorderLine * pLine,XclExpPalette & rPalette,XclBiff eBiff)1532 void lclGetBorderLine(
1533         sal_uInt8& rnXclLine, sal_uInt32& rnColorId,
1534         const SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
1535 {
1536     rnXclLine = EXC_LINE_NONE;
1537     if( pLine )
1538     {
1539         sal_uInt16 nOuterWidth = pLine->GetOutWidth();
1540         sal_uInt16 nDistance = pLine->GetDistance();
1541         if( nDistance > 0 )
1542             rnXclLine = EXC_LINE_DOUBLE;
1543         else if( nOuterWidth > DEF_LINE_WIDTH_2 )
1544             rnXclLine = EXC_LINE_THICK;
1545         else if( nOuterWidth > DEF_LINE_WIDTH_1 )
1546             rnXclLine = EXC_LINE_MEDIUM;
1547         else if( nOuterWidth > DEF_LINE_WIDTH_0 )
1548             rnXclLine = EXC_LINE_THIN;
1549         else if( nOuterWidth > 0 )
1550             rnXclLine = EXC_LINE_HAIR;
1551         else
1552             rnXclLine = EXC_LINE_NONE;
1553     }
1554     if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
1555         rnXclLine = EXC_LINE_THIN;
1556 
1557     rnColorId = (pLine && (rnXclLine != EXC_LINE_NONE)) ?
1558         rPalette.InsertColor( pLine->GetColor(), EXC_COLOR_CELLBORDER ) :
1559         XclExpPalette::GetColorIdFromIndex( 0 );
1560 }
1561 
1562 } // namespace
1563 
1564 // ----------------------------------------------------------------------------
1565 
XclExpCellBorder()1566 XclExpCellBorder::XclExpCellBorder() :
1567     mnLeftColorId(   XclExpPalette::GetColorIdFromIndex( mnLeftColor ) ),
1568     mnRightColorId(  XclExpPalette::GetColorIdFromIndex( mnRightColor ) ),
1569     mnTopColorId(    XclExpPalette::GetColorIdFromIndex( mnTopColor ) ),
1570     mnBottomColorId( XclExpPalette::GetColorIdFromIndex( mnBottomColor ) ),
1571     mnDiagColorId(   XclExpPalette::GetColorIdFromIndex( mnDiagColor ) )
1572 {
1573 }
1574 
FillFromItemSet(const SfxItemSet & rItemSet,XclExpPalette & rPalette,XclBiff eBiff,bool bStyle)1575 bool XclExpCellBorder::FillFromItemSet(
1576         const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
1577 {
1578     bool bUsed = false;
1579 
1580     switch( eBiff )
1581     {
1582         // ALL 'case's - run through!
1583 
1584         case EXC_BIFF8: // attributes new in BIFF8
1585         {
1586             const SvxLineItem& rTLBRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_TLBR );
1587             sal_uInt8 nTLBRLine;
1588             sal_uInt32 nTLBRColorId;
1589             lclGetBorderLine( nTLBRLine, nTLBRColorId, rTLBRItem.GetLine(), rPalette, eBiff );
1590             mbDiagTLtoBR = (nTLBRLine != EXC_LINE_NONE);
1591 
1592             const SvxLineItem& rBLTRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_BLTR );
1593             sal_uInt8 nBLTRLine;
1594             sal_uInt32 nBLTRColorId;
1595             lclGetBorderLine( nBLTRLine, nBLTRColorId, rBLTRItem.GetLine(), rPalette, eBiff );
1596             mbDiagBLtoTR = (nBLTRLine != EXC_LINE_NONE);
1597 
1598             if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
1599             {
1600                 mnDiagLine = nTLBRLine;
1601                 mnDiagColorId = nTLBRColorId;
1602             }
1603             else
1604             {
1605                 mnDiagLine = nBLTRLine;
1606                 mnDiagColorId = nBLTRColorId;
1607             }
1608 
1609             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
1610                      ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
1611         }
1612 
1613         case EXC_BIFF5:
1614         case EXC_BIFF4:
1615         case EXC_BIFF3:
1616         case EXC_BIFF2:
1617         {
1618             const SvxBoxItem& rBoxItem = GETITEM( rItemSet, SvxBoxItem, ATTR_BORDER );
1619             lclGetBorderLine( mnLeftLine,   mnLeftColorId,   rBoxItem.GetLeft(),   rPalette, eBiff );
1620             lclGetBorderLine( mnRightLine,  mnRightColorId,  rBoxItem.GetRight(),  rPalette, eBiff );
1621             lclGetBorderLine( mnTopLine,    mnTopColorId,    rBoxItem.GetTop(),    rPalette, eBiff );
1622             lclGetBorderLine( mnBottomLine, mnBottomColorId, rBoxItem.GetBottom(), rPalette, eBiff );
1623             bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER, bStyle );
1624         }
1625 
1626         break;
1627         default:    DBG_ERROR_BIFF();
1628     }
1629 
1630     return bUsed;
1631 }
1632 
SetFinalColors(const XclExpPalette & rPalette)1633 void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
1634 {
1635     mnLeftColor   = rPalette.GetColorIndex( mnLeftColorId );
1636     mnRightColor  = rPalette.GetColorIndex( mnRightColorId );
1637     mnTopColor    = rPalette.GetColorIndex( mnTopColorId );
1638     mnBottomColor = rPalette.GetColorIndex( mnBottomColorId );
1639     mnDiagColor   = rPalette.GetColorIndex( mnDiagColorId );
1640 }
1641 
1642 #if 0
1643 void XclExpCellBorder::FillToXF2( sal_uInt8& rnFlags ) const
1644 {
1645     ::set_flag( rnFlags, EXC_XF2_LEFTLINE,   mnLeftLine   != EXC_LINE_NONE );
1646     ::set_flag( rnFlags, EXC_XF2_RIGHTLINE,  mnRightLine  != EXC_LINE_NONE );
1647     ::set_flag( rnFlags, EXC_XF2_TOPLINE,    mnTopLine    != EXC_LINE_NONE );
1648     ::set_flag( rnFlags, EXC_XF2_BOTTOMLINE, mnBottomLine != EXC_LINE_NONE );
1649 }
1650 
1651 void XclExpCellBorder::FillToXF3( sal_uInt32& rnBorder ) const
1652 {
1653     ::insert_value( rnBorder, mnTopLine,      0, 3 );
1654     ::insert_value( rnBorder, mnLeftLine,     8, 3 );
1655     ::insert_value( rnBorder, mnBottomLine,  16, 3 );
1656     ::insert_value( rnBorder, mnRightLine,   24, 3 );
1657     ::insert_value( rnBorder, mnTopColor,     3, 5 );
1658     ::insert_value( rnBorder, mnLeftColor,   11, 5 );
1659     ::insert_value( rnBorder, mnBottomColor, 19, 5 );
1660     ::insert_value( rnBorder, mnRightColor,  27, 5 );
1661 }
1662 #endif
1663 
FillToXF5(sal_uInt32 & rnBorder,sal_uInt32 & rnArea) const1664 void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
1665 {
1666     ::insert_value( rnBorder, mnTopLine,      0, 3 );
1667     ::insert_value( rnBorder, mnLeftLine,     3, 3 );
1668     ::insert_value( rnArea,   mnBottomLine,  22, 3 );
1669     ::insert_value( rnBorder, mnRightLine,    6, 3 );
1670     ::insert_value( rnBorder, mnTopColor,     9, 7 );
1671     ::insert_value( rnBorder, mnLeftColor,   16, 7 );
1672     ::insert_value( rnArea,   mnBottomColor, 25, 7 );
1673     ::insert_value( rnBorder, mnRightColor,  23, 7 );
1674 }
1675 
FillToXF8(sal_uInt32 & rnBorder1,sal_uInt32 & rnBorder2) const1676 void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
1677 {
1678     ::insert_value( rnBorder1, mnLeftLine,     0, 4 );
1679     ::insert_value( rnBorder1, mnRightLine,    4, 4 );
1680     ::insert_value( rnBorder1, mnTopLine,      8, 4 );
1681     ::insert_value( rnBorder1, mnBottomLine,  12, 4 );
1682     ::insert_value( rnBorder1, mnLeftColor,   16, 7 );
1683     ::insert_value( rnBorder1, mnRightColor,  23, 7 );
1684     ::insert_value( rnBorder2, mnTopColor,     0, 7 );
1685     ::insert_value( rnBorder2, mnBottomColor,  7, 7 );
1686     ::insert_value( rnBorder2, mnDiagColor,   14, 7 );
1687     ::insert_value( rnBorder2, mnDiagLine,    21, 4 );
1688     ::set_flag( rnBorder1, EXC_XF_DIAGONAL_TL_TO_BR, mbDiagTLtoBR );
1689     ::set_flag( rnBorder1, EXC_XF_DIAGONAL_BL_TO_TR, mbDiagBLtoTR );
1690 }
1691 
FillToCF8(sal_uInt16 & rnLine,sal_uInt32 & rnColor) const1692 void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
1693 {
1694     ::insert_value( rnLine,  mnLeftLine,     0, 4 );
1695     ::insert_value( rnLine,  mnRightLine,    4, 4 );
1696     ::insert_value( rnLine,  mnTopLine,      8, 4 );
1697     ::insert_value( rnLine,  mnBottomLine,  12, 4 );
1698     ::insert_value( rnColor, mnLeftColor,    0, 7 );
1699     ::insert_value( rnColor, mnRightColor,   7, 7 );
1700     ::insert_value( rnColor, mnTopColor,    16, 7 );
1701     ::insert_value( rnColor, mnBottomColor, 23, 7 );
1702 }
1703 
ToLineStyle(sal_uInt8 nLineStyle)1704 static const char* ToLineStyle( sal_uInt8 nLineStyle )
1705 {
1706     switch( nLineStyle )
1707     {
1708         case EXC_LINE_NONE:     return "none";
1709         case EXC_LINE_THIN:     return "thin";
1710         case EXC_LINE_MEDIUM:   return "medium";
1711         case EXC_LINE_THICK:    return "thick";
1712         case EXC_LINE_DOUBLE:   return "double";
1713         case EXC_LINE_HAIR:     return "hair";
1714     }
1715     return "*unknown*";
1716 }
1717 
lcl_WriteBorder(XclExpXmlStream & rStrm,sal_Int32 nElement,sal_uInt8 nLineStyle,const Color & rColor)1718 static void lcl_WriteBorder( XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor )
1719 {
1720     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1721     if( nLineStyle == EXC_LINE_NONE )
1722         rStyleSheet->singleElement( nElement, FSEND );
1723     else if( rColor == Color( 0, 0, 0, 0 ) )
1724         rStyleSheet->singleElement( nElement,
1725                 XML_style,  ToLineStyle( nLineStyle ),
1726                 FSEND );
1727     else
1728     {
1729         rStyleSheet->startElement( nElement,
1730                 XML_style,  ToLineStyle( nLineStyle ),
1731                 FSEND );
1732         rStyleSheet->singleElement( XML_color,
1733                 XML_rgb,    XclXmlUtils::ToOString( rColor ).getStr(),
1734                 FSEND );
1735         rStyleSheet->endElement( nElement );
1736     }
1737 }
1738 
SaveXml(XclExpXmlStream & rStrm) const1739 void XclExpCellBorder::SaveXml( XclExpXmlStream& rStrm ) const
1740 {
1741     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1742 
1743     XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1744 
1745     rStyleSheet->startElement( XML_border,
1746             XML_diagonalUp,     XclXmlUtils::ToPsz( mbDiagBLtoTR ),
1747             XML_diagonalDown,   XclXmlUtils::ToPsz( mbDiagTLtoBR ),
1748             // OOXTODO: XML_outline,
1749             FSEND );
1750     lcl_WriteBorder( rStrm, XML_left,       mnLeftLine,     rPalette.GetColor( mnLeftColor ) );
1751     lcl_WriteBorder( rStrm, XML_right,      mnRightLine,    rPalette.GetColor( mnRightColor ) );
1752     lcl_WriteBorder( rStrm, XML_top,        mnTopLine,      rPalette.GetColor( mnTopColor ) );
1753     lcl_WriteBorder( rStrm, XML_bottom,     mnBottomLine,   rPalette.GetColor( mnBottomColor ) );
1754     lcl_WriteBorder( rStrm, XML_diagonal,   mnDiagLine,     rPalette.GetColor( mnDiagColor ) );
1755     // OOXTODO: XML_vertical, XML_horizontal
1756     rStyleSheet->endElement( XML_border );
1757 }
1758 
1759 // ----------------------------------------------------------------------------
1760 
XclExpCellArea()1761 XclExpCellArea::XclExpCellArea() :
1762     mnForeColorId( XclExpPalette::GetColorIdFromIndex( mnForeColor ) ),
1763     mnBackColorId( XclExpPalette::GetColorIdFromIndex( mnBackColor ) )
1764 {
1765 }
1766 
FillFromItemSet(const SfxItemSet & rItemSet,XclExpPalette & rPalette,bool bStyle)1767 bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
1768 {
1769     const SvxBrushItem& rBrushItem = GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND );
1770     if( rBrushItem.GetColor().GetTransparency() )
1771     {
1772         mnPattern = EXC_PATT_NONE;
1773         mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1774         mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
1775     }
1776     else
1777     {
1778         mnPattern = EXC_PATT_SOLID;
1779         mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
1780         mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1781     }
1782     return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
1783 }
1784 
SetFinalColors(const XclExpPalette & rPalette)1785 void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
1786 {
1787     rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
1788 }
1789 
1790 #if 0
1791 void XclExpCellArea::FillToXF2( sal_uInt8& rnFlags ) const
1792 {
1793     ::set_flag( rnFlags, EXC_XF2_BACKGROUND, mnPattern != EXC_PATT_NONE );
1794 }
1795 
1796 void XclExpCellArea::FillToXF3( sal_uInt16& rnArea ) const
1797 {
1798     ::insert_value( rnArea, mnPattern,    0, 6 );
1799     ::insert_value( rnArea, mnForeColor,  6, 5 );
1800     ::insert_value( rnArea, mnBackColor, 11, 5 );
1801 }
1802 #endif
1803 
FillToXF5(sal_uInt32 & rnArea) const1804 void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
1805 {
1806     ::insert_value( rnArea, mnPattern,   16, 6 );
1807     ::insert_value( rnArea, mnForeColor,  0, 7 );
1808     ::insert_value( rnArea, mnBackColor,  7, 7 );
1809 }
1810 
FillToXF8(sal_uInt32 & rnBorder2,sal_uInt16 & rnArea) const1811 void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
1812 {
1813     ::insert_value( rnBorder2, mnPattern,   26, 6 );
1814     ::insert_value( rnArea,    mnForeColor,  0, 7 );
1815     ::insert_value( rnArea,    mnBackColor,  7, 7 );
1816 }
1817 
FillToCF8(sal_uInt16 & rnPattern,sal_uInt16 & rnColor) const1818 void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
1819 {
1820     XclCellArea aTmp( *this );
1821     if( !aTmp.IsTransparent() && (aTmp.mnBackColor == EXC_COLOR_WINDOWTEXT) )
1822         aTmp.mnBackColor = 0;
1823     if( aTmp.mnPattern == EXC_PATT_SOLID )
1824         ::std::swap( aTmp.mnForeColor, aTmp.mnBackColor );
1825     ::insert_value( rnColor,   aTmp.mnForeColor,  0, 7 );
1826     ::insert_value( rnColor,   aTmp.mnBackColor,  7, 7 );
1827     ::insert_value( rnPattern, aTmp.mnPattern,   10, 6 );
1828 }
1829 
ToPatternType(sal_uInt8 nPattern)1830 static const char* ToPatternType( sal_uInt8 nPattern )
1831 {
1832     switch( nPattern )
1833     {
1834         case EXC_PATT_NONE:         return "none";
1835         case EXC_PATT_SOLID:        return "solid";
1836         case EXC_PATT_50_PERC:      return "mediumGray";
1837         case EXC_PATT_75_PERC:      return "darkGray";
1838         case EXC_PATT_25_PERC:      return "lightGray";
1839         case EXC_PATT_12_5_PERC:    return "gray125";
1840         case EXC_PATT_6_25_PERC:    return "gray0625";
1841     }
1842     return "*unknown*";
1843 }
1844 
SaveXml(XclExpXmlStream & rStrm) const1845 void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
1846 {
1847     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1848     rStyleSheet->startElement( XML_fill,
1849             FSEND );
1850 
1851     // OOXTODO: XML_gradientFill
1852 
1853     XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1854 
1855     if( mnPattern == EXC_PATT_NONE || ( mnForeColor == 0 && mnBackColor == 0 ) )
1856         rStyleSheet->singleElement( XML_patternFill,
1857                 XML_patternType,    ToPatternType( mnPattern ),
1858                 FSEND );
1859     else
1860     {
1861         rStyleSheet->startElement( XML_patternFill,
1862                 XML_patternType,    ToPatternType( mnPattern ),
1863                 FSEND );
1864         rStyleSheet->singleElement( XML_fgColor,
1865                 XML_rgb,    XclXmlUtils::ToOString( rPalette.GetColor( mnForeColor ) ).getStr(),
1866                 FSEND );
1867         rStyleSheet->singleElement( XML_bgColor,
1868                 XML_rgb,    XclXmlUtils::ToOString( rPalette.GetColor( mnBackColor ) ).getStr(),
1869                 FSEND );
1870         rStyleSheet->endElement( XML_patternFill );
1871     }
1872 
1873     rStyleSheet->endElement( XML_fill );
1874 }
1875 
1876 // ----------------------------------------------------------------------------
1877 
XclExpXFId()1878 XclExpXFId::XclExpXFId() :
1879     mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
1880     mnXFIndex( EXC_XF_DEFAULTCELL )
1881 {
1882 }
1883 
XclExpXFId(sal_uInt32 nXFId)1884 XclExpXFId::XclExpXFId( sal_uInt32 nXFId ) :
1885     mnXFId( nXFId ),
1886     mnXFIndex( EXC_XF_DEFAULTCELL )
1887 {
1888 }
1889 
ConvertXFIndex(const XclExpRoot & rRoot)1890 void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
1891 {
1892     mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
1893 }
1894 
1895 // ----------------------------------------------------------------------------
1896 
XclExpXF(const XclExpRoot & rRoot,const ScPatternAttr & rPattern,sal_Int16 nScript,sal_uLong nForceScNumFmt,sal_uInt16 nForceXclFont,bool bForceLineBreak)1897 XclExpXF::XclExpXF(
1898         const XclExpRoot& rRoot, const ScPatternAttr& rPattern, sal_Int16 nScript,
1899         sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
1900 :   XclXFBase(true),
1901     XclExpRecord(),
1902     XclExpRoot(rRoot),
1903     mpItemSet(0),
1904     maProtection(),
1905     maAlignment(),
1906     maBorder(),
1907     maArea(),
1908     mnParentXFId(),
1909     mnScNumFmt(),
1910     mnXclFont(),
1911     mnXclNumFmt(),
1912     mnBorderId(),
1913     mnFillId(),
1914     mnIndexInXFList(0)
1915 {
1916     mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
1917     Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
1918 }
1919 
XclExpXF(const XclExpRoot & rRoot,const SfxStyleSheetBase & rStyleSheet)1920 XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet )
1921 :   XclXFBase(false),
1922     XclExpRecord(),
1923     XclExpRoot(rRoot),
1924     mpItemSet(0),
1925     maProtection(),
1926     maAlignment(),
1927     maBorder(),
1928     maArea(),
1929     mnParentXFId(XclExpXFBuffer::GetXFIdFromIndex(EXC_XF_STYLEPARENT)),
1930     mnScNumFmt(),
1931     mnXclFont(),
1932     mnXclNumFmt(),
1933     mnBorderId(),
1934     mnFillId(),
1935     mnIndexInXFList(0)
1936 {
1937     bool bDefStyle = (rStyleSheet.GetName() == ScGlobal::GetRscString( STR_STYLENAME_STANDARD ));
1938     sal_Int16 nScript = bDefStyle ? GetDefApiScript() : ::com::sun::star::i18n::ScriptType::WEAK;
1939     Init( const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet(), nScript,
1940         NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false, bDefStyle );
1941 }
1942 
XclExpXF(const XclExpRoot & rRoot,bool bCellXF)1943 XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF )
1944 :   XclXFBase(bCellXF),
1945     XclExpRecord(),
1946     XclExpRoot(rRoot),
1947     mpItemSet(0),
1948     maProtection(),
1949     maAlignment(),
1950     maBorder(),
1951     maArea(),
1952     mnParentXFId(XclExpXFBuffer::GetXFIdFromIndex(EXC_XF_STYLEPARENT)),
1953     mnScNumFmt(),
1954     mnXclFont(),
1955     mnXclNumFmt(),
1956     mnBorderId(),
1957     mnFillId(),
1958     mnIndexInXFList(0)
1959 {
1960     InitDefault();
1961 }
1962 
Equals(const ScPatternAttr & rPattern,sal_uLong nForceScNumFmt,sal_uInt16 nForceXclFont,bool bForceLineBreak) const1963 bool XclExpXF::Equals( const ScPatternAttr& rPattern,
1964         sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
1965 {
1966     return IsCellXF() && (mpItemSet == &rPattern.GetItemSet()) &&
1967         (!bForceLineBreak || maAlignment.mbLineBreak) &&
1968         ((nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) || (mnScNumFmt == nForceScNumFmt)) &&
1969         ((nForceXclFont == EXC_FONT_NOTFOUND) || (mnXclFont == nForceXclFont));
1970 }
1971 
Equals(const SfxStyleSheetBase & rStyleSheet) const1972 bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
1973 {
1974     return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
1975 }
1976 
SetFinalColors()1977 void XclExpXF::SetFinalColors()
1978 {
1979     maBorder.SetFinalColors( GetPalette() );
1980     maArea.SetFinalColors( GetPalette() );
1981 }
1982 
Equals(const XclExpXF & rCmpXF) const1983 bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
1984 {
1985     return XclXFBase::Equals( rCmpXF ) &&
1986         (maProtection == rCmpXF.maProtection) && (maAlignment  == rCmpXF.maAlignment) &&
1987         (maBorder     == rCmpXF.maBorder)     && (maArea       == rCmpXF.maArea)      &&
1988         (mnXclFont    == rCmpXF.mnXclFont)    && (mnXclNumFmt  == rCmpXF.mnXclNumFmt) &&
1989         (mnParentXFId == rCmpXF.mnParentXFId);
1990 }
1991 
InitDefault()1992 void XclExpXF::InitDefault()
1993 {
1994     SetRecHeader( EXC_ID5_XF, (GetBiff() == EXC_BIFF8) ? 20 : 16 );
1995     mpItemSet = 0;
1996     mnScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
1997     mnXclFont = mnXclNumFmt = 0;
1998 }
1999 
Init(const SfxItemSet & rItemSet,sal_Int16 nScript,sal_uLong nForceScNumFmt,sal_uInt16 nForceXclFont,bool bForceLineBreak,bool bDefStyle)2000 void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
2001         sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
2002 {
2003     InitDefault();
2004     mpItemSet = &rItemSet;
2005 
2006     // cell protection
2007     mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
2008 
2009     // font
2010     if( nForceXclFont == EXC_FONT_NOTFOUND )
2011     {
2012         mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
2013         mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
2014     }
2015     else
2016     {
2017         mnXclFont = nForceXclFont;
2018         mbFontUsed = true;
2019     }
2020 
2021     // number format
2022     mnScNumFmt = (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) ?
2023         GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) : nForceScNumFmt;
2024     mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
2025     mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
2026 
2027     // alignment
2028     mbAlignUsed = maAlignment.FillFromItemSet( rItemSet, bForceLineBreak, GetBiff(), IsStyleXF() );
2029 
2030     // cell border
2031     mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
2032 
2033     // background area
2034     mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
2035 
2036     // set all b***Used flags to true in "Default"/"Normal" style
2037     if( bDefStyle )
2038         SetAllUsedFlags( true );
2039 }
2040 
GetUsedFlags() const2041 sal_uInt8 XclExpXF::GetUsedFlags() const
2042 {
2043     sal_uInt8 nUsedFlags = 0;
2044     /*  In cell XFs a set bit means a used attribute, in style XFs a cleared bit.
2045         "mbCellXF == mb***Used" evaluates to correct value in cell and style XFs. */
2046     ::set_flag( nUsedFlags, EXC_XF_DIFF_PROT,   mbCellXF == mbProtUsed );
2047     ::set_flag( nUsedFlags, EXC_XF_DIFF_FONT,   mbCellXF == mbFontUsed );
2048     ::set_flag( nUsedFlags, EXC_XF_DIFF_VALFMT, mbCellXF == mbFmtUsed );
2049     ::set_flag( nUsedFlags, EXC_XF_DIFF_ALIGN,  mbCellXF == mbAlignUsed );
2050     ::set_flag( nUsedFlags, EXC_XF_DIFF_BORDER, mbCellXF == mbBorderUsed );
2051     ::set_flag( nUsedFlags, EXC_XF_DIFF_AREA,   mbCellXF == mbAreaUsed );
2052     return nUsedFlags;
2053 }
2054 
WriteBody5(XclExpStream & rStrm)2055 void XclExpXF::WriteBody5( XclExpStream& rStrm )
2056 {
2057     sal_uInt16 nTypeProt = 0, nAlign = 0;
2058     sal_uInt32 nArea = 0, nBorder = 0;
2059 
2060     ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2061     ::insert_value( nTypeProt, mnParent, 4, 12 );
2062     ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
2063 
2064     maProtection.FillToXF3( nTypeProt );
2065     maAlignment.FillToXF5( nAlign );
2066     maBorder.FillToXF5( nBorder, nArea );
2067     maArea.FillToXF5( nArea );
2068 
2069     rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
2070 }
2071 
WriteBody8(XclExpStream & rStrm)2072 void XclExpXF::WriteBody8( XclExpStream& rStrm )
2073 {
2074     sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
2075     sal_uInt32 nBorder1 = 0, nBorder2 = 0;
2076 
2077     ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2078     ::insert_value( nTypeProt, mnParent, 4, 12 );
2079     ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
2080 
2081     maProtection.FillToXF3( nTypeProt );
2082     maAlignment.FillToXF8( nAlign, nMiscAttrib );
2083     maBorder.FillToXF8( nBorder1, nBorder2 );
2084     maArea.FillToXF8( nBorder2, nArea );
2085 
2086     rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
2087 }
2088 
WriteBody(XclExpStream & rStrm)2089 void XclExpXF::WriteBody( XclExpStream& rStrm )
2090 {
2091     XclExpXFId aParentId( mnParentXFId );
2092     aParentId.ConvertXFIndex( GetRoot() );
2093     mnParent = aParentId.mnXFIndex;
2094     switch( GetBiff() )
2095     {
2096         case EXC_BIFF5: WriteBody5( rStrm );    break;
2097         case EXC_BIFF8: WriteBody8( rStrm );    break;
2098         default:        DBG_ERROR_BIFF();
2099     }
2100 }
2101 
SetXmlIds(sal_uInt32 nBorderId,sal_uInt32 nFillId)2102 void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
2103 {
2104     mnBorderId = nBorderId;
2105     mnFillId   = nFillId;
2106 }
2107 
SaveXml(XclExpXmlStream & rStrm)2108 void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
2109 {
2110     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2111 
2112     sal_Int32 nXfId = 0;
2113     if( IsCellXF() )
2114     {
2115         sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
2116         nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
2117     }
2118 
2119     rStyleSheet->startElement( XML_xf,
2120             XML_numFmtId,           OString::valueOf( (sal_Int32) mnXclNumFmt ).getStr(),
2121             XML_fontId,             OString::valueOf( (sal_Int32) mnXclFont ).getStr(),
2122             XML_fillId,             OString::valueOf( (sal_Int32) mnFillId ).getStr(),
2123             XML_borderId,           OString::valueOf( (sal_Int32) mnBorderId ).getStr(),
2124             XML_xfId,               IsStyleXF() ? NULL : OString::valueOf( nXfId ).getStr(),
2125             // OOXTODO: XML_quotePrefix,
2126             // OOXTODO: XML_pivotButton,
2127             // OOXTODO: XML_applyNumberFormat,  ;
2128             XML_applyFont,          XclXmlUtils::ToPsz( mbFontUsed ),
2129             // OOXTODO: XML_applyFill,
2130             XML_applyBorder,        XclXmlUtils::ToPsz( mbBorderUsed ),
2131             XML_applyAlignment,     XclXmlUtils::ToPsz( mbAlignUsed ),
2132             XML_applyProtection,    XclXmlUtils::ToPsz( mbProtUsed ),
2133             FSEND );
2134     if( mbAlignUsed )
2135         maAlignment.SaveXml( rStrm );
2136     if( mbProtUsed )
2137         maProtection.SaveXml( rStrm );
2138     // OOXTODO: XML_extLst
2139     rStyleSheet->endElement( XML_xf );
2140 }
2141 
2142 // ----------------------------------------------------------------------------
2143 
XclExpDefaultXF(const XclExpRoot & rRoot,bool bCellXF)2144 XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
2145     XclExpXF( rRoot, bCellXF )
2146 {
2147 }
2148 
2149 //UNUSED2008-05  void XclExpDefaultXF::SetParent( sal_uInt32 nParentXFId )
2150 //UNUSED2008-05  {
2151 //UNUSED2008-05      DBG_ASSERT( IsCellXF(), "XclExpDefaultXF::SetParent - not allowed in style XFs" );
2152 //UNUSED2008-05      if( IsCellXF() )
2153 //UNUSED2008-05          mnParentXFId = nParentXFId;
2154 //UNUSED2008-05  }
2155 //UNUSED2008-05
2156 //UNUSED2008-05  void XclExpDefaultXF::SetUsedFlags(
2157 //UNUSED2008-05          bool bProtUsed, bool bFontUsed, bool bFmtUsed,
2158 //UNUSED2008-05          bool bAlignUsed, bool bBorderUsed, bool bAreaUsed )
2159 //UNUSED2008-05  {
2160 //UNUSED2008-05      mbProtUsed    = bProtUsed;
2161 //UNUSED2008-05      mbFontUsed    = bFontUsed;
2162 //UNUSED2008-05      mbFmtUsed     = bFmtUsed;
2163 //UNUSED2008-05      mbAlignUsed   = bAlignUsed;
2164 //UNUSED2008-05      mbBorderUsed  = bBorderUsed;
2165 //UNUSED2008-05      mbAreaUsed    = bAreaUsed;
2166 //UNUSED2008-05  }
2167 //UNUSED2008-05
2168 //UNUSED2008-05  void XclExpDefaultXF::SetProtection( const XclExpCellProt& rProtection )
2169 //UNUSED2008-05  {
2170 //UNUSED2008-05      maProtection = rProtection;
2171 //UNUSED2008-05      mbProtUsed = true;
2172 //UNUSED2008-05  }
2173 //UNUSED2008-05
2174 //UNUSED2008-05  void XclExpDefaultXF::SetAlignment( const XclExpCellAlign& rAlignment )
2175 //UNUSED2008-05  {
2176 //UNUSED2008-05      maAlignment = rAlignment;
2177 //UNUSED2008-05      mbAlignUsed = true;
2178 //UNUSED2008-05  }
2179 //UNUSED2008-05
2180 //UNUSED2008-05  void XclExpDefaultXF::SetBorder( const XclExpCellBorder& rBorder )
2181 //UNUSED2008-05  {
2182 //UNUSED2008-05      maBorder = rBorder;
2183 //UNUSED2008-05      mbBorderUsed = true;
2184 //UNUSED2008-05  }
2185 //UNUSED2008-05
2186 //UNUSED2008-05  void XclExpDefaultXF::SetArea( const XclExpCellArea& rArea )
2187 //UNUSED2008-05  {
2188 //UNUSED2008-05      maArea = rArea;
2189 //UNUSED2008-05      mbAreaUsed = true;
2190 //UNUSED2008-05  }
2191 
SetFont(sal_uInt16 nXclFont)2192 void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
2193 {
2194     mnXclFont = nXclFont;
2195     mbFontUsed = true;
2196 }
2197 
SetNumFmt(sal_uInt16 nXclNumFmt)2198 void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
2199 {
2200     mnXclNumFmt = nXclNumFmt;
2201     mbFmtUsed = true;
2202 }
2203 
2204 // ----------------------------------------------------------------------------
2205 
XclExpStyle(sal_uInt32 nXFId,const String & rStyleName)2206 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, const String& rStyleName ) :
2207     XclExpRecord( EXC_ID_STYLE, 4 ),
2208     maName( rStyleName ),
2209     maXFId( nXFId ),
2210     mnStyleId( EXC_STYLE_USERDEF ),
2211     mnLevel( EXC_STYLE_NOLEVEL )
2212 {
2213     DBG_ASSERT( maName.Len(), "XclExpStyle::XclExpStyle - empty style name" );
2214 #ifdef DBG_UTIL
2215     sal_uInt8 nStyleId, nLevel; // do not use members for debug tests
2216     DBG_ASSERT( !XclTools::GetBuiltInStyleId( nStyleId, nLevel, maName ),
2217         "XclExpStyle::XclExpStyle - this is a built-in style" );
2218 #endif
2219 }
2220 
XclExpStyle(sal_uInt32 nXFId,sal_uInt8 nStyleId,sal_uInt8 nLevel)2221 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, sal_uInt8 nStyleId, sal_uInt8 nLevel ) :
2222     XclExpRecord( EXC_ID_STYLE, 4 ),
2223     maXFId( nXFId ),
2224     mnStyleId( nStyleId ),
2225     mnLevel( nLevel )
2226 {
2227 }
2228 
WriteBody(XclExpStream & rStrm)2229 void XclExpStyle::WriteBody( XclExpStream& rStrm )
2230 {
2231     maXFId.ConvertXFIndex( rStrm.GetRoot() );
2232     ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
2233     rStrm << maXFId.mnXFIndex;
2234 
2235     if( IsBuiltIn() )
2236     {
2237         rStrm << mnStyleId << mnLevel;
2238     }
2239     else
2240     {
2241         XclExpString aNameEx;
2242         if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
2243             aNameEx.Assign( maName );
2244         else
2245             aNameEx.AssignByte( maName, rStrm.GetRoot().GetTextEncoding(), EXC_STR_8BITLENGTH );
2246         rStrm << aNameEx;
2247     }
2248 }
2249 
lcl_StyleNameFromId(sal_Int32 nStyleId)2250 static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
2251 {
2252     switch( nStyleId )
2253     {
2254         case 0:     return "Normal";
2255         case 3:     return "Comma";
2256         case 4:     return "Currency";
2257         case 5:     return "Percent";
2258         case 6:     return "Comma [0]";
2259         case 7:     return "Currency [0]";
2260     }
2261     return "*unknown*";
2262 }
2263 
SaveXml(XclExpXmlStream & rStrm)2264 void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
2265 {
2266     OString sName;
2267     if( IsBuiltIn() )
2268     {
2269         sName = OString( lcl_StyleNameFromId( mnStyleId ) );
2270     }
2271     else
2272         sName = XclXmlUtils::ToOString( maName );
2273     sal_Int32 nXFId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( maXFId.mnXFId );
2274     rStrm.GetCurrentStream()->singleElement( XML_cellStyle,
2275             XML_name,           sName.getStr(),
2276             XML_xfId,           OString::valueOf( nXFId ).getStr(),
2277             XML_builtinId,      OString::valueOf( (sal_Int32) mnStyleId ).getStr(),
2278             // OOXTODO: XML_iLevel,
2279             // OOXTODO: XML_hidden,
2280             XML_customBuiltin,  XclXmlUtils::ToPsz( ! IsBuiltIn() ),
2281             FSEND );
2282     // OOXTODO: XML_extLst
2283 }
2284 
2285 // ----------------------------------------------------------------------------
2286 
2287 namespace {
2288 
2289 const sal_uInt32 EXC_XFLIST_INDEXBASE   = 0xFFFE0000;
2290 /** Maximum count of XF records to store in the XF list (performance). */
2291 const sal_uInt32 EXC_XFLIST_HARDLIMIT   = 256 * 1024;
2292 
lclIsBuiltInStyle(const String & rStyleName)2293 bool lclIsBuiltInStyle( const String& rStyleName )
2294 {
2295     return
2296         XclTools::IsBuiltInStyleName( rStyleName ) ||
2297         XclTools::IsCondFormatStyleName( rStyleName );
2298 }
2299 
2300 } // namespace
2301 
2302 // ----------------------------------------------------------------------------
2303 
XclExpBuiltInInfo()2304 XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
2305     mnStyleId( EXC_STYLE_USERDEF ),
2306     mnLevel( EXC_STYLE_NOLEVEL ),
2307     mbPredefined( true ),
2308     mbHasStyleRec( false )
2309 {
2310 }
2311 
2312 // ----------------------------------------------------------------------------
2313 
2314 /** Predicate for search algorithm. */
2315 struct XclExpBorderPred
2316 {
2317     const XclExpCellBorder&
2318                         mrBorder;
XclExpBorderPredXclExpBorderPred2319     inline explicit     XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
2320     bool                operator()( const XclExpCellBorder& rBorder ) const;
2321 };
2322 
operator ()(const XclExpCellBorder & rBorder) const2323 bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
2324 {
2325     return
2326         mrBorder.mnLeftColor     == rBorder.mnLeftColor &&
2327         mrBorder.mnRightColor    == rBorder.mnRightColor &&
2328         mrBorder.mnTopColor      == rBorder.mnTopColor &&
2329         mrBorder.mnBottomColor   == rBorder.mnBottomColor &&
2330         mrBorder.mnDiagColor     == rBorder.mnDiagColor &&
2331         mrBorder.mnLeftLine      == rBorder.mnLeftLine &&
2332         mrBorder.mnRightLine     == rBorder.mnRightLine &&
2333         mrBorder.mnTopLine       == rBorder.mnTopLine &&
2334         mrBorder.mnBottomLine    == rBorder.mnBottomLine &&
2335         mrBorder.mnDiagLine      == rBorder.mnDiagLine &&
2336         mrBorder.mbDiagTLtoBR    == rBorder.mbDiagTLtoBR &&
2337         mrBorder.mbDiagBLtoTR    == rBorder.mbDiagBLtoTR &&
2338         mrBorder.mnLeftColorId   == rBorder.mnLeftColorId &&
2339         mrBorder.mnRightColorId  == rBorder.mnRightColorId &&
2340         mrBorder.mnTopColorId    == rBorder.mnTopColorId &&
2341         mrBorder.mnBottomColorId == rBorder.mnBottomColorId &&
2342         mrBorder.mnDiagColorId   == rBorder.mnDiagColorId;
2343 }
2344 
2345 struct XclExpFillPred
2346 {
2347     const XclExpCellArea&
2348                         mrFill;
XclExpFillPredXclExpFillPred2349     inline explicit     XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
2350     bool                operator()( const XclExpCellArea& rFill ) const;
2351 };
2352 
operator ()(const XclExpCellArea & rFill) const2353 bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
2354 {
2355     return
2356         mrFill.mnForeColor      == rFill.mnForeColor &&
2357         mrFill.mnBackColor      == rFill.mnBackColor &&
2358         mrFill.mnPattern        == rFill.mnPattern &&
2359         mrFill.mnForeColorId    == rFill.mnForeColorId &&
2360         mrFill.mnBackColorId    == rFill.mnBackColorId;
2361 }
2362 
2363 static bool XclExpXFBuffer_mbUseMultimapBuffer = true;
2364 
XclExpXFBuffer(const XclExpRoot & rRoot)2365 XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot )
2366 :   XclExpRecordBase(),
2367     XclExpRoot(rRoot),
2368     maXFList(),
2369     maStyleList(),
2370     maBuiltInMap(),
2371     maXFIndexVec(),
2372     maStyleIndexes(),
2373     maCellIndexes(),
2374     maSortedXFList(),
2375     maBorders(),
2376     maFills(),
2377     maXclExpXFMap()
2378 {
2379 }
2380 
Initialize()2381 void XclExpXFBuffer::Initialize()
2382 {
2383     InsertDefaultRecords();
2384     InsertUserStyles();
2385 }
2386 
Insert(const ScPatternAttr * pPattern,sal_Int16 nScript)2387 sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
2388 {
2389     return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
2390 }
2391 
InsertWithFont(const ScPatternAttr * pPattern,sal_Int16 nScript,sal_uInt16 nForceXclFont,bool bForceLineBreak)2392 sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
2393         sal_uInt16 nForceXclFont, bool bForceLineBreak )
2394 {
2395     return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
2396 }
2397 
InsertWithNumFmt(const ScPatternAttr * pPattern,sal_Int16 nScript,sal_uLong nForceScNumFmt,bool bForceLineBreak)2398 sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uLong nForceScNumFmt, bool bForceLineBreak )
2399 {
2400     return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
2401 }
2402 
InsertStyle(const SfxStyleSheetBase * pStyleSheet)2403 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
2404 {
2405     return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2406 }
2407 
GetXFIdFromIndex(sal_uInt16 nXFIndex)2408 sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
2409 {
2410     return EXC_XFLIST_INDEXBASE | nXFIndex;
2411 }
2412 
GetDefCellXFId()2413 sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
2414 {
2415     return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
2416 }
2417 
GetXFById(sal_uInt32 nXFId) const2418 const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
2419 {
2420     return maXFList.GetRecord( nXFId ).get();
2421 }
2422 
Finalize()2423 void XclExpXFBuffer::Finalize()
2424 {
2425     for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2426         maXFList.GetRecord( nPos )->SetFinalColors();
2427 
2428     sal_uInt32 nTotalCount = static_cast< sal_uInt32 >( maXFList.GetSize() );
2429     sal_uInt32 nId;
2430     maXFIndexVec.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2431     maStyleIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2432     maCellIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2433 
2434     XclExpBuiltInMap::const_iterator aBuiltInEnd = maBuiltInMap.end();
2435     /*  nMaxBuiltInXFId used to decide faster whether an XF record is
2436         user-defined. If the current XF ID is greater than this value,
2437         maBuiltInMap doesn't need to be searched. */
2438     sal_uInt32 nMaxBuiltInXFId = maBuiltInMap.empty() ? 0 : maBuiltInMap.rbegin()->first;
2439 
2440     // *** map all built-in XF records (cell and style) *** -------------------
2441 
2442     // do not change XF order -> std::map<> iterates elements in ascending order
2443     for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(); aIt != aBuiltInEnd; ++aIt )
2444         AppendXFIndex( aIt->first );
2445 
2446     // *** insert all user-defined style XF records, without reduce *** -------
2447 
2448     sal_uInt32 nStyleXFCount = 0;       // counts up to EXC_XF_MAXSTYLECOUNT limit
2449 
2450     for( nId = 0; nId < nTotalCount; ++nId )
2451     {
2452         XclExpXFRef xXF = maXFList.GetRecord( nId );
2453         if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2454         {
2455             if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
2456             {
2457                 // maximum count of styles not reached
2458                 AppendXFIndex( nId );
2459                 ++nStyleXFCount;
2460             }
2461             else
2462             {
2463                 /*  Maximum count of styles reached - do not append more
2464                     pointers to XFs; use default style XF instead; do not break
2465                     the loop to initialize all maXFIndexVec elements. */
2466                 maXFIndexVec[ nId ] = EXC_XF_DEFAULTSTYLE;
2467             }
2468         }
2469     }
2470 
2471     // *** insert all cell XF records *** -------------------------------------
2472 
2473     // start position to search for equal inserted XF records
2474     size_t nSearchStart = maSortedXFList.GetSize();
2475 
2476     // break the loop if XF limit reached - maXFIndexVec is already initialized with default index
2477     XclExpXFRef xDefCellXF = maXFList.GetRecord( EXC_XF_DEFAULTCELL );
2478     for( nId = 0; (nId < nTotalCount) && (maSortedXFList.GetSize() < EXC_XF_MAXCOUNT); ++nId )
2479     {
2480         XclExpXFRef xXF = maXFList.GetRecord( nId );
2481         if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2482         {
2483             // try to find an XF record equal to *xXF, which is already inserted
2484             sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
2485 
2486             // first try if it is equal to the default cell XF
2487             if( xDefCellXF->Equals( *xXF ) )
2488             {
2489                 nFoundIndex = EXC_XF_DEFAULTCELL;
2490             }
2491             else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
2492                         (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
2493             {
2494                 if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
2495                     nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
2496             }
2497 
2498             if( nFoundIndex != EXC_XF_NOTFOUND )
2499                 // equal XF already in the list, use its resulting XF index
2500                 maXFIndexVec[ nId ] = nFoundIndex;
2501             else
2502                 AppendXFIndex( nId );
2503         }
2504     }
2505 
2506     sal_uInt16 nXmlStyleIndex   = 0;
2507     sal_uInt16 nXmlCellIndex    = 0;
2508 
2509     size_t nXFCount = maSortedXFList.GetSize();
2510     for( size_t i = 0; i < nXFCount; ++i )
2511     {
2512         XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2513         if( xXF->IsStyleXF() )
2514             maStyleIndexes[ i ] = nXmlStyleIndex++;
2515         else
2516             maCellIndexes[ i ] = nXmlCellIndex++;
2517     }
2518 }
2519 
GetXFIndex(sal_uInt32 nXFId) const2520 sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
2521 {
2522     sal_uInt16 nXFIndex = EXC_XF_DEFAULTSTYLE;
2523     if( nXFId >= EXC_XFLIST_INDEXBASE )
2524         nXFIndex = static_cast< sal_uInt16 >( nXFId & ~EXC_XFLIST_INDEXBASE );
2525     else if( nXFId < maXFIndexVec.size() )
2526         nXFIndex = maXFIndexVec[ nXFId ];
2527     return nXFIndex;
2528 }
2529 
GetXmlStyleIndex(sal_uInt32 nXFIndex) const2530 sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
2531 {
2532     DBG_ASSERT( nXFIndex < maStyleIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2533     if( nXFIndex > maStyleIndexes.size() )
2534         return 0;   // should be caught/debugged via above assert; return "valid" index.
2535     return maStyleIndexes[ nXFIndex ];
2536 }
2537 
GetXmlCellIndex(sal_uInt32 nXFIndex) const2538 sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
2539 {
2540     DBG_ASSERT( nXFIndex < maCellIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2541     if( nXFIndex > maCellIndexes.size() )
2542         return 0;   // should be caught/debugged via above assert; return "valid" index.
2543     return maCellIndexes[ nXFIndex ];
2544 }
2545 
Save(XclExpStream & rStrm)2546 void XclExpXFBuffer::Save( XclExpStream& rStrm )
2547 {
2548     // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2549     maSortedXFList.Save( rStrm );
2550     // save all STYLE records
2551     maStyleList.Save( rStrm );
2552 }
2553 
lcl_GetCellCounts(const XclExpRecordList<XclExpXF> & rXFList,sal_Int32 & rCells,sal_Int32 & rStyles)2554 static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
2555 {
2556     rCells  = 0;
2557     rStyles = 0;
2558     size_t nXFCount = rXFList.GetSize();
2559     for( size_t i = 0; i < nXFCount; ++i )
2560     {
2561         XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
2562         if( xXF->IsCellXF() )
2563             ++rCells;
2564         else if( xXF->IsStyleXF() )
2565             ++rStyles;
2566     }
2567 }
2568 
SaveXml(XclExpXmlStream & rStrm)2569 void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
2570 {
2571     sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2572 
2573     rStyleSheet->startElement( XML_fills,
2574             XML_count,  OString::valueOf( (sal_Int32) maFills.size() ).getStr(),
2575             FSEND );
2576     for( XclExpFillList::iterator aIt = maFills.begin(), aEnd = maFills.end();
2577             aIt != aEnd; ++aIt )
2578     {
2579         aIt->SaveXml( rStrm );
2580     }
2581     rStyleSheet->endElement( XML_fills );
2582 
2583     rStyleSheet->startElement( XML_borders,
2584             XML_count,  OString::valueOf( (sal_Int32) maBorders.size() ).getStr(),
2585             FSEND );
2586     for( XclExpBorderList::iterator aIt = maBorders.begin(), aEnd = maBorders.end();
2587             aIt != aEnd; ++aIt )
2588     {
2589         aIt->SaveXml( rStrm );
2590     }
2591     rStyleSheet->endElement( XML_borders );
2592 
2593     // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2594     sal_Int32 nCells, nStyles;
2595     lcl_GetCellCounts( maSortedXFList, nCells, nStyles );
2596 
2597     if( nStyles > 0 )
2598     {
2599         rStyleSheet->startElement( XML_cellStyleXfs,
2600                 XML_count,  OString::valueOf( nStyles ).getStr(),
2601                 FSEND );
2602         size_t nXFCount = maSortedXFList.GetSize();
2603         for( size_t i = 0; i < nXFCount; ++i )
2604         {
2605             XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2606             if( ! xXF->IsStyleXF() )
2607                 continue;
2608             SaveXFXml( rStrm, *xXF );
2609         }
2610         rStyleSheet->endElement( XML_cellStyleXfs );
2611     }
2612 
2613     if( nCells > 0 )
2614     {
2615         rStyleSheet->startElement( XML_cellXfs,
2616                 XML_count,  OString::valueOf( nCells ).getStr(),
2617                 FSEND );
2618         size_t nXFCount = maSortedXFList.GetSize();
2619         for( size_t i = 0; i < nXFCount; ++i )
2620         {
2621             XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2622             if( ! xXF->IsCellXF() )
2623                 continue;
2624             SaveXFXml( rStrm, *xXF );
2625         }
2626         rStyleSheet->endElement( XML_cellXfs );
2627     }
2628 
2629     // save all STYLE records
2630     rStyleSheet->startElement( XML_cellStyles,
2631             XML_count,  OString::valueOf( (sal_Int32) maStyleList.GetSize() ).getStr(),
2632             FSEND );
2633     maStyleList.SaveXml( rStrm );
2634     rStyleSheet->endElement( XML_cellStyles );
2635 }
2636 
SaveXFXml(XclExpXmlStream & rStrm,XclExpXF & rXF)2637 void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
2638 {
2639     XclExpBorderList::iterator aBorderPos =
2640         std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) );
2641     DBG_ASSERT( aBorderPos != maBorders.end(), "XclExpXFBuffer::SaveXml - Invalid @borderId!" );
2642     XclExpFillList::iterator aFillPos =
2643         std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) );
2644     DBG_ASSERT( aFillPos != maFills.end(), "XclExpXFBuffer::SaveXml - Invalid @fillId!" );
2645 
2646     sal_Int32 nBorderId = 0, nFillId = 0;
2647     if( aBorderPos != maBorders.end() )
2648         nBorderId = std::distance( maBorders.begin(), aBorderPos );
2649     if( aFillPos != maFills.end() )
2650         nFillId = std::distance( maFills.begin(), aFillPos );
2651 
2652     rXF.SetXmlIds( nBorderId, nFillId );
2653     rXF.SaveXml( rStrm );
2654 }
2655 
impAddMissingValuesFromXFListToXclExpXFMap()2656 void XclExpXFBuffer::impAddMissingValuesFromXFListToXclExpXFMap()
2657 {
2658     for(size_t nPos(maXclExpXFMap.size()); nPos < maXFList.GetSize(); ++nPos)
2659     {
2660         XclExpXF* pValue = maXFList.GetRecord(nPos).get();
2661 
2662         if(pValue)
2663         {
2664             const SfxItemSet* pKey = maXFList.GetRecord(nPos)->getItemSet();
2665 
2666             maXclExpXFMap.insert(std::pair< const SfxItemSet*, XclExpXF* >(pKey, pValue));
2667             pValue->setIndexInXFList(nPos);
2668         }
2669         else
2670         {
2671             OSL_ENSURE(false, "maXFList has empty entries (!)");
2672         }
2673     }
2674 }
2675 
FindXF(const ScPatternAttr & rPattern,sal_uLong nForceScNumFmt,sal_uInt16 nForceXclFont,bool bForceLineBreak) const2676 sal_uInt32 XclExpXFBuffer::FindXF(const ScPatternAttr& rPattern, sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak) const
2677 {
2678     // define return value
2679     sal_uInt32 nXFId(EXC_XFID_NOTFOUND);
2680 
2681     if(XclExpXFBuffer_mbUseMultimapBuffer)
2682     {
2683         // add values from maXFList which are not yet in maXclExpXFMap
2684         const_cast< XclExpXFBuffer* >(this)->impAddMissingValuesFromXFListToXclExpXFMap();
2685 
2686         // get the full range for the pattern set
2687         typedef std::multimap< const SfxItemSet*, XclExpXF* >::const_iterator CIT;
2688         typedef std::pair< CIT, CIT > Range;
2689         const SfxItemSet* pPatternSet = &(rPattern.GetItemSet());
2690         const Range range(maXclExpXFMap.equal_range(pPatternSet));
2691 
2692         // iterate over evtl. multiple candidates using the pattern set
2693         for(CIT ite(range.first); ite != range.second; ++ite)
2694         {
2695             XclExpXF* pIte = ite->second;
2696 
2697             if(pIte->Equals(rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak))
2698             {
2699                 nXFId = pIte->getIndexInXFList();
2700                 break;
2701             }
2702         }
2703     }
2704     else
2705     {
2706         // old, unbuffered implementation
2707         for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2708             if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2709                 return static_cast< sal_uInt32 >( nPos );
2710     }
2711 
2712     return nXFId;
2713 }
2714 
FindXF(const SfxStyleSheetBase & rStyleSheet) const2715 sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
2716 {
2717     if(XclExpXFBuffer_mbUseMultimapBuffer)
2718     {
2719         // add values from maXFList which are not yet in maXclExpXFMap
2720         const_cast< XclExpXFBuffer* >(this)->impAddMissingValuesFromXFListToXclExpXFMap();
2721 
2722         // find entry with given ItemSet (by StyleSheet)
2723         const SfxItemSet& rItemSet = const_cast< SfxStyleSheetBase& >(rStyleSheet).GetItemSet();
2724         typedef std::multimap< const SfxItemSet*, XclExpXF* >::const_iterator CIT;
2725         const CIT aFound(maXclExpXFMap.find(&rItemSet));
2726 
2727         if(aFound != maXclExpXFMap.end())
2728         {
2729             return aFound->second->getIndexInXFList();
2730         }
2731     }
2732     else
2733     {
2734         // old, unbuffered implementation
2735         for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2736             if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
2737                 return static_cast< sal_uInt32 >( nPos );
2738     }
2739 
2740     return EXC_XFID_NOTFOUND;
2741 }
2742 
FindBuiltInXF(sal_uInt8 nStyleId,sal_uInt8 nLevel) const2743 sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
2744 {
2745     for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(), aEnd = maBuiltInMap.end(); aIt != aEnd; ++aIt )
2746         if( (aIt->second.mnStyleId == nStyleId) && (aIt->second.mnLevel == nLevel) )
2747             return aIt->first;
2748     return EXC_XFID_NOTFOUND;
2749 }
2750 
InsertCellXF(const ScPatternAttr * pPattern,sal_Int16 nScript,sal_uLong nForceScNumFmt,sal_uInt16 nForceXclFont,bool bForceLineBreak)2751 sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
2752         sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
2753 {
2754     const ScPatternAttr* pDefPattern = GetDoc().GetDefPattern();
2755     if( !pPattern )
2756         pPattern = pDefPattern;
2757 
2758     // special handling for default cell formatting
2759     if( (pPattern == pDefPattern) && !bForceLineBreak &&
2760         (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
2761         (nForceXclFont == EXC_FONT_NOTFOUND) )
2762     {
2763         // Is it the first try to insert the default cell format?
2764         bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
2765         if( rbPredefined )
2766         {
2767             // replace default cell pattern
2768             XclExpXFRef xNewXF( new XclExpXF( GetRoot(), *pPattern, nScript ) );
2769             maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
2770 
2771             // need to clear the multimap buffer to force reinsertin of the new element
2772             if(XclExpXFBuffer_mbUseMultimapBuffer)
2773             {
2774                     maXclExpXFMap.clear();
2775             }
2776 
2777             rbPredefined = false;
2778         }
2779         return GetDefCellXFId();
2780     }
2781 
2782     sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2783     if( nXFId == EXC_XFID_NOTFOUND )
2784     {
2785         // not found - insert new cell XF
2786         if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
2787         {
2788             maXFList.AppendNewRecord( new XclExpXF(
2789                 GetRoot(), *pPattern, nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak ) );
2790             // do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
2791             nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
2792         }
2793         else
2794         {
2795             // list full - fall back to default cell XF
2796             nXFId = GetDefCellXFId();
2797         }
2798     }
2799     return nXFId;
2800 }
2801 
InsertStyleXF(const SfxStyleSheetBase & rStyleSheet)2802 sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
2803 {
2804     // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
2805 
2806     sal_uInt8 nStyleId, nLevel;
2807     if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
2808     {
2809         // try to find the built-in XF record (if already created in InsertDefaultRecords())
2810         sal_uInt32 nXFId = FindBuiltInXF( nStyleId, nLevel );
2811         if( nXFId == EXC_XFID_NOTFOUND )
2812         {
2813             // built-in style XF not yet created - do it now
2814             XclExpXFRef xXF( new XclExpXF( GetRoot(), rStyleSheet ) );
2815             nXFId = AppendBuiltInXFWithStyle( xXF, nStyleId, nLevel );
2816             // this new XF record is not predefined
2817             maBuiltInMap[ nXFId ].mbPredefined = false;
2818         }
2819         else
2820         {
2821             DBG_ASSERT( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::InsertStyleXF - built-in XF not found" );
2822             // XF record still predefined? -> Replace with real XF
2823             bool& rbPredefined = maBuiltInMap[ nXFId ].mbPredefined;
2824             if( rbPredefined )
2825             {
2826                 // replace predefined built-in style (ReplaceRecord() deletes old record)
2827                 maXFList.ReplaceRecord( XclExpXFRef( new XclExpXF( GetRoot(), rStyleSheet ) ), nXFId );
2828 
2829                 // need to clear the multimap buffer to force reinsertin of the new element
2830                 if(XclExpXFBuffer_mbUseMultimapBuffer)
2831                 {
2832                     maXclExpXFMap.clear();
2833                 }
2834 
2835                 rbPredefined = false;
2836             }
2837         }
2838 
2839         // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
2840         bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
2841         if( !rbHasStyleRec )
2842         {
2843             maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2844             rbHasStyleRec = true;
2845         }
2846 
2847         return nXFId;
2848     }
2849 
2850     // *** try to find the XF record of a user-defined style ***
2851 
2852     sal_uInt32 nXFId = FindXF( rStyleSheet );
2853     if( nXFId == EXC_XFID_NOTFOUND )
2854     {
2855         // not found - insert new style XF and STYLE
2856         nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2857         if( nXFId < EXC_XFLIST_HARDLIMIT )
2858         {
2859             maXFList.AppendNewRecord( new XclExpXF( GetRoot(), rStyleSheet ) );
2860             // create the STYLE record
2861             if( rStyleSheet.GetName().Len() )
2862                 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
2863         }
2864         else
2865             // list full - fall back to default style XF
2866             nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2867     }
2868     return nXFId;
2869 }
2870 
InsertUserStyles()2871 void XclExpXFBuffer::InsertUserStyles()
2872 {
2873     SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
2874     for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
2875         if( pStyleSheet->IsUserDefined() && !lclIsBuiltInStyle( pStyleSheet->GetName() ) )
2876             InsertStyleXF( *pStyleSheet );
2877 }
2878 
AppendBuiltInXF(XclExpXFRef xXF,sal_uInt8 nStyleId,sal_uInt8 nLevel)2879 sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2880 {
2881     sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2882     maXFList.AppendRecord( xXF );
2883     XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
2884     rInfo.mnStyleId = nStyleId;
2885     rInfo.mnLevel = nLevel;
2886     rInfo.mbPredefined = true;
2887     return nXFId;
2888 }
2889 
AppendBuiltInXFWithStyle(XclExpXFRef xXF,sal_uInt8 nStyleId,sal_uInt8 nLevel)2890 sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2891 {
2892     sal_uInt32 nXFId = AppendBuiltInXF( xXF, nStyleId, nLevel );
2893     maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2894     maBuiltInMap[ nXFId ].mbHasStyleRec = true;  // mark existing STYLE record
2895     return nXFId;
2896 }
2897 
lcl_GetPatternFill_None()2898 static XclExpCellArea lcl_GetPatternFill_None()
2899 {
2900     XclExpCellArea aFill;
2901     aFill.mnPattern = EXC_PATT_NONE;
2902     return aFill;
2903 }
2904 
lcl_GetPatternFill_Gray125()2905 static XclExpCellArea lcl_GetPatternFill_Gray125()
2906 {
2907     XclExpCellArea aFill;
2908     aFill.mnPattern     = EXC_PATT_12_5_PERC;
2909     aFill.mnForeColor   = 0;
2910     aFill.mnBackColor   = 0;
2911     return aFill;
2912 }
2913 
InsertDefaultRecords()2914 void XclExpXFBuffer::InsertDefaultRecords()
2915 {
2916     maFills.push_back( lcl_GetPatternFill_None() );
2917     maFills.push_back( lcl_GetPatternFill_Gray125() );
2918 
2919     // index 0: default style
2920     if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) )
2921     {
2922         XclExpXFRef xDefStyle( new XclExpXF( GetRoot(), *pDefStyleSheet ) );
2923         sal_uInt32 nXFId = AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2924         // mark this XF as not predefined, prevents overwriting
2925         maBuiltInMap[ nXFId ].mbPredefined = false;
2926     }
2927     else
2928     {
2929         DBG_ERRORFILE( "XclExpXFBuffer::InsertDefaultRecords - default style not found" );
2930         XclExpXFRef xDefStyle( new XclExpDefaultXF( GetRoot(), false ) );
2931         xDefStyle->SetAllUsedFlags( true );
2932         AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2933     }
2934 
2935     // index 1-14: RowLevel and ColLevel styles (without STYLE records)
2936     XclExpDefaultXF aLevelStyle( GetRoot(), false );
2937     // RowLevel_1, ColLevel_1
2938     aLevelStyle.SetFont( 1 );
2939     AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 0 );
2940     AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 0 );
2941     // RowLevel_2, ColLevel_2
2942     aLevelStyle.SetFont( 2 );
2943     AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 1 );
2944     AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 1 );
2945     // RowLevel_3, ColLevel_3 ... RowLevel_7, ColLevel_7
2946     aLevelStyle.SetFont( 0 );
2947     for( sal_uInt8 nLevel = 2; nLevel < EXC_STYLE_LEVELCOUNT; ++nLevel )
2948     {
2949         AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, nLevel );
2950         AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, nLevel );
2951     }
2952 
2953     // index 15: default hard cell format, placeholder to be able to add more built-in styles
2954     maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
2955     maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
2956 
2957     // index 16-20: other built-in styles
2958     XclExpDefaultXF aFormatStyle( GetRoot(), false );
2959     aFormatStyle.SetFont( 1 );
2960     aFormatStyle.SetNumFmt( 43 );
2961     AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA );
2962     aFormatStyle.SetNumFmt( 41 );
2963     AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA_0 );
2964     aFormatStyle.SetNumFmt( 44 );
2965     AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY );
2966     aFormatStyle.SetNumFmt( 42 );
2967     AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY_0 );
2968     aFormatStyle.SetNumFmt( 9 );
2969     AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_PERCENT );
2970 
2971     // other built-in style XF records (i.e. Hyperlink styles) are created on demand
2972 
2973     /*  Insert the real default hard cell format -> 0 is document default pattern.
2974         Do it here (and not already above) to really have all built-in styles. */
2975     Insert( 0, GetDefApiScript() );
2976 }
2977 
AppendXFIndex(sal_uInt32 nXFId)2978 void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
2979 {
2980     DBG_ASSERT( nXFId < maXFIndexVec.size(), "XclExpXFBuffer::AppendXFIndex - XF ID out of range" );
2981     maXFIndexVec[ nXFId ] = static_cast< sal_uInt16 >( maSortedXFList.GetSize() );
2982     XclExpXFRef xXF = maXFList.GetRecord( nXFId );
2983     AddBorderAndFill( *xXF );
2984     maSortedXFList.AppendRecord( xXF );
2985     DBG_ASSERT( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::AppendXFIndex - XF not found" );
2986 }
2987 
AddBorderAndFill(const XclExpXF & rXF)2988 void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
2989 {
2990     if( std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) == maBorders.end() )
2991     {
2992         maBorders.push_back( rXF.GetBorderData() );
2993     }
2994 
2995     if( std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) == maFills.end() )
2996     {
2997         maFills.push_back( rXF.GetAreaData() );
2998     }
2999 }
3000 
3001 // ============================================================================
3002 
XclExpXmlStyleSheet(const XclExpRoot & rRoot)3003 XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
3004     : XclExpRoot( rRoot )
3005 {
3006 }
3007 
SaveXml(XclExpXmlStream & rStrm)3008 void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
3009 {
3010     sax_fastparser::FSHelperPtr aStyleSheet = rStrm.CreateOutputStream(
3011             OUString::createFromAscii( "xl/styles.xml" ),
3012             OUString::createFromAscii( "styles.xml" ),
3013             rStrm.GetCurrentStream()->getOutputStream(),
3014             "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3015             "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" );
3016     rStrm.PushStream( aStyleSheet );
3017 
3018     aStyleSheet->startElement( XML_styleSheet,
3019             XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
3020             FSEND );
3021 
3022     CreateRecord( EXC_ID_FORMATLIST )->SaveXml( rStrm );
3023     CreateRecord( EXC_ID_FONTLIST )->SaveXml( rStrm );
3024     CreateRecord( EXC_ID_XFLIST )->SaveXml( rStrm );
3025     CreateRecord( EXC_ID_PALETTE )->SaveXml( rStrm );
3026 
3027     aStyleSheet->endElement( XML_styleSheet );
3028 
3029     rStrm.PopStream();
3030 }
3031 
3032 // ============================================================================
3033 
3034