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