Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / excel / xestyle.cxx
blob7b6a3b5a5665cf575c16a9cd6cba0b71548f0345
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <xestyle.hxx>
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>
50 #include <oox/export/utils.hxx>
51 #include <oox/token/tokens.hxx>
52 #include <oox/token/namespaces.hxx>
53 #include <oox/token/relationship.hxx>
55 using namespace ::com::sun::star;
56 using namespace oox;
58 // PALETTE record - color information =========================================
60 namespace {
62 sal_uInt32 lclGetWeighting( XclExpColorType eType )
64 switch( eType )
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" );
77 return 1;
80 sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
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;
91 sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
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 )
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);
103 sal_uInt32 nWSum = nWeight1 + nWeight2;
104 return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
107 void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
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 ) );
114 } // namespace
116 // additional classes for color reduction -------------------------------------
118 namespace {
120 /** Represents an entry in a color list.
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.
126 class XclListColor
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).
134 public:
135 explicit XclListColor( const Color& rColor, sal_uInt32 nColorId );
137 /** Returns the RGB color value of the color. */
138 const Color& GetColor() const { return maColor; }
139 /** Returns the unique ID of the color. */
140 sal_uInt32 GetColorId() const { return mnColorId; }
141 /** Returns the current weighting of the color. */
142 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. */
144 bool IsBaseColor() const { return mbBaseColor; }
146 /** Adds the passed weighting to this color. */
147 void AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
148 /** Merges this color with rColor, regarding weighting settings. */
149 void Merge( const XclListColor& rColor );
152 XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
153 maColor( rColor ),
154 mnColorId( nColorId ),
155 mnWeight( 0 )
157 mbBaseColor =
158 ((rColor.GetRed() == 0x00) || (rColor.GetRed() == 0xFF)) &&
159 ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
160 ((rColor.GetBlue() == 0x00) || (rColor.GetBlue() == 0xFF));
163 void XclListColor::Merge( const XclListColor& rColor )
165 sal_uInt32 nWeight2 = rColor.GetWeighting();
166 // do not change RGB value of base colors
167 if( !mbBaseColor )
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 ) );
173 AddWeighting( nWeight2 );
176 /** Data for each inserted original color, represented by a color ID. */
177 struct XclColorIdData
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. */
182 void Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
185 /** A color that will be written to the Excel file. */
186 struct XclPaletteColor
188 Color maColor; /// Resulting color to export.
189 bool mbUsed; /// true = Entry is used in the document.
191 explicit XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
192 void SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
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
199 sal_uInt32 mnPalIndex; /// Index to palette.
200 bool mbProcessed; /// true = List color already processed.
202 explicit XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
203 void SetIndex( sal_uInt32 nPalIndex )
204 { mnPalIndex = nPalIndex; mbProcessed = true; }
207 /** Stores the nearest palette color index of a list color. */
208 struct XclNearest
210 sal_uInt32 mnPalIndex; /// Index to nearest palette color.
211 sal_Int32 mnDist; /// Distance to palette color.
213 explicit XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
216 } // namespace
218 class XclExpPaletteImpl
220 public:
221 explicit XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
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 );
230 /** Reduces the color list to the maximum count of the current BIFF version. */
231 void Finalize();
233 /** Returns the Excel palette index of the color with passed color ID. */
234 sal_uInt16 GetColorIndex( sal_uInt32 nColorId ) const;
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;
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;
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 );
254 private:
255 /** Returns the Excel index of a 0-based color index. */
256 static sal_uInt16 GetXclIndex( sal_uInt32 nIndex )
257 { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
259 /** Returns the original inserted color represented by the color ID nColorId. */
260 const Color& GetOriginalColor( sal_uInt32 nColorId ) const;
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 );
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();
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;
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;
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;
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.
306 const sal_uInt32 EXC_PAL_INDEXBASE = 0xFFFF0000;
307 const sal_uInt32 EXC_PAL_MAXRAWSIZE = 1024;
309 XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
310 mrDefPal( rDefPal ),
311 mxColorList( new XclListColorList ),
312 mnLastIdx( 0 )
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 ) ) );
320 InsertColor( COL_BLACK, EXC_COLOR_CELLTEXT );
323 sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
325 if( rColor == COL_AUTO )
326 return GetColorIdFromIndex( nAutoDefault );
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 ) );
334 return pEntry->GetColorId();
337 sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
339 return EXC_PAL_INDEXBASE | nIndex;
342 void XclExpPaletteImpl::Finalize()
344 // --- build initial color ID data vector (maColorIdDataVec) ---
346 sal_uInt32 nCount = mxColorList->size();
347 maColorIdDataVec.resize( nCount );
348 for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
350 const XclListColor& listColor = *mxColorList->at( nIdx );
351 maColorIdDataVec[ listColor.GetColorId() ].Set( listColor.GetColor(), nIdx );
354 // --- loop as long as current color count does not fit into palette of current BIFF ---
356 // phase 1: raw reduction (performance reasons, #i36945#)
357 sal_uInt32 nPass = 0;
358 while( mxColorList->size() > EXC_PAL_MAXRAWSIZE )
359 RawReducePalette( nPass++ );
361 // phase 2: precise reduction using advanced color merging based on color weighting
362 while( mxColorList->size() > mrDefPal.GetColorCount() )
363 ReduceLeastUsedColor();
365 // --- use default palette and replace colors with nearest used colors ---
367 nCount = mxColorList->size();
368 std::vector< XclRemap > aRemapVec( nCount );
369 std::vector< XclNearest > aNearestVec( nCount );
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 )
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 );
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;
396 sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
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;
406 void XclExpPaletteImpl::GetMixedColors(
407 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
408 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
410 rnXclForeIx = GetColorIndex( nForeColorId );
411 rnXclBackIx = GetColorIndex( nBackColorId );
412 if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
413 return;
415 // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
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;
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 ] );
430 sal_Int32 nMinDist = nFirstDist;
431 sal_uInt32 nMinIndex = 0;
432 for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
434 sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
435 if( nDist < nMinDist )
437 nMinDist = nDist;
438 nMinIndex = nCnt;
441 rnXclForeIx = GetXclIndex( nIndex1 );
442 rnXclBackIx = GetXclIndex( nIndex2 );
443 if( nMinDist < nFirstDist )
445 switch( nMinIndex )
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;
454 Color XclExpPaletteImpl::GetColor( sal_uInt16 nXclIndex ) const
456 if( nXclIndex >= EXC_COLOR_USEROFFSET )
458 sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
459 if( nIdx < maPalette.size() )
460 return maPalette[ nIdx ].maColor;
462 return mrDefPal.GetDefColor( nXclIndex );
465 bool XclExpPaletteImpl::IsDefaultPalette() const
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;
473 void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
475 rStrm << static_cast< sal_uInt16 >( maPalette.size() );
476 for( const auto& rColor : maPalette )
477 rStrm << rColor.maColor;
480 void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
482 if( maPalette.empty() )
483 return;
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 );
494 const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
496 if( nColorId < maColorIdDataVec.size() )
497 return maColorIdDataVec[ nColorId ].maColor;
498 return maPalette[ 0 ].maColor;
501 XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
503 rnIndex = 0;
505 if (mxColorList->empty())
506 return nullptr;
508 XclListColor* pEntry = nullptr;
510 // search optimization for equal-colored objects occurring repeatedly
511 if (mnLastIdx < mxColorList->size())
513 pEntry = (*mxColorList)[mnLastIdx].get();
514 if( pEntry->GetColor() == rColor )
516 rnIndex = mnLastIdx;
517 return pEntry;
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) )
527 rnIndex = (nBegIdx + nEndIdx) / 2;
528 pEntry = (*mxColorList)[rnIndex].get();
529 bFound = pEntry->GetColor() == rColor;
530 if( !bFound )
532 if( pEntry->GetColor() < rColor )
533 nBegIdx = rnIndex + 1;
534 else
535 nEndIdx = rnIndex;
539 // not found - use end of range as new insertion position
540 if( !bFound )
541 rnIndex = nEndIdx;
543 mnLastIdx = rnIndex;
544 return pEntry;
547 XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
549 XclListColor* pEntry = new XclListColor( rColor, mxColorList->size() );
550 mxColorList->insert(mxColorList->begin() + nIndex, std::unique_ptr<XclListColor>(pEntry));
551 return pEntry;
554 void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
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...
567 XclListColorListRef xOldList = mxColorList;
568 mxColorList.reset( new XclListColorList );
570 // maps old list indexes to new list indexes, used to update maColorIdDataVec
571 ScfUInt32Vec aListIndexMap;
572 aListIndexMap.reserve( xOldList->size() );
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" );
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 );
585 // process each color in the old color list
586 for(const std::unique_ptr<XclListColor> & pOldColor : *xOldList)
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();
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 );
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 );
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 ];
619 void XclExpPaletteImpl::ReduceLeastUsedColor()
621 // find a list color to remove
622 sal_uInt32 nRemove = GetLeastUsedListColor();
623 // find its nearest neighbor
624 sal_uInt32 nKeep = GetNearestListColor( nRemove );
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 )
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;
639 // recalculate color ID data map (maps color IDs to color list indexes)
640 for( auto& rColorIdData : maColorIdDataVec )
642 if( rColorIdData.mnIndex > nRemove )
643 --rColorIdData.mnIndex;
644 else if( rColorIdData.mnIndex == nRemove )
645 rColorIdData.mnIndex = nKeep;
650 sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
652 sal_uInt32 nFound = 0;
653 sal_uInt32 nMinW = SAL_MAX_UINT32;
655 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
657 XclListColor& rEntry = *mxColorList->at( nIdx );
658 // ignore the base colors
659 if( !rEntry.IsBaseColor() && (rEntry.GetWeighting() < nMinW) )
661 nFound = nIdx;
662 nMinW = rEntry.GetWeighting();
665 return nFound;
668 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
670 sal_uInt32 nFound = 0;
671 sal_Int32 nMinD = SAL_MAX_INT32;
673 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
675 if( nIdx != nIgnore )
677 if( XclListColor* pEntry = mxColorList->at(nIdx).get() )
679 sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
680 if( nDist < nMinD )
682 nFound = nIdx;
683 nMinD = nDist;
688 return nFound;
691 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
693 if (nIndex >= mxColorList->size())
694 return 0;
695 XclListColor* pEntry = mxColorList->at(nIndex).get();
696 return GetNearestListColor( pEntry->GetColor(), nIndex );
699 sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
700 sal_uInt32& rnIndex, const Color& rColor ) const
702 rnIndex = 0;
703 sal_Int32 nDist = SAL_MAX_INT32;
705 sal_uInt32 nPaletteIndex = 0;
706 for( const auto& rPaletteColor : maPalette )
708 if( !rPaletteColor.mbUsed )
710 sal_Int32 nCurrDist = lclGetColorDistance( rColor, rPaletteColor.maColor );
711 if( nCurrDist < nDist )
713 rnIndex = nPaletteIndex;
714 nDist = nCurrDist;
717 ++nPaletteIndex;
719 return nDist;
722 sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
723 sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
725 rnFirst = rnSecond = 0;
726 sal_Int32 nDist1 = SAL_MAX_INT32;
727 sal_Int32 nDist2 = SAL_MAX_INT32;
729 sal_uInt32 nPaletteIndex = 0;
730 for( const auto& rPaletteColor : maPalette )
732 sal_Int32 nCurrDist = lclGetColorDistance( rColor, rPaletteColor.maColor );
733 if( nCurrDist < nDist1 )
735 rnSecond = rnFirst;
736 nDist2 = nDist1;
737 rnFirst = nPaletteIndex;
738 nDist1 = nCurrDist;
740 else if( nCurrDist < nDist2 )
742 rnSecond = nPaletteIndex;
743 nDist2 = nCurrDist;
745 ++nPaletteIndex;
747 return nDist1;
750 XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
751 XclDefaultPalette( rRoot ),
752 XclExpRecord( EXC_ID_PALETTE )
754 mxImpl.reset( new XclExpPaletteImpl( *this ) );
755 SetRecSize( GetColorCount() * 4 + 2 );
758 XclExpPalette::~XclExpPalette()
762 sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
764 return mxImpl->InsertColor( rColor, eType, nAutoDefault );
767 sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
769 return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
772 void XclExpPalette::Finalize()
774 mxImpl->Finalize();
777 sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
779 return mxImpl->GetColorIndex( nColorId );
782 void XclExpPalette::GetMixedColors(
783 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
784 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
786 return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
789 Color XclExpPalette::GetColor( sal_uInt16 nXclIndex ) const
791 return mxImpl->GetColor( nXclIndex );
794 void XclExpPalette::Save( XclExpStream& rStrm )
796 if( !mxImpl->IsDefaultPalette() )
797 XclExpRecord::Save( rStrm );
800 void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
802 if( !mxImpl->IsDefaultPalette() )
803 mxImpl->SaveXml( rStrm );
806 void XclExpPalette::WriteBody( XclExpStream& rStrm )
808 mxImpl->WriteBody( rStrm );
811 // FONT record - font information =============================================
813 namespace {
815 typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
817 sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
818 const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
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;
826 } // namespace
828 sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
830 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
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. */
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 );
840 /* do not let a font from a parent style override an explicit
841 cell font. */
843 sal_Int16 nDefScript = rRoot.GetDefApiScript();
844 sal_Int16 nScript = 0;
845 const SfxItemSet* pCurrSet = &rItemSet;
847 while( (nScript == 0) && pCurrSet )
849 switch( nDefScript )
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;
864 pCurrSet = pCurrSet->GetParent();
867 if (nScript == 0)
868 nScript = nDefScript;
870 if (nScript == 0)
872 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
873 nScript = ApiScriptType::LATIN;
876 return nScript;
879 vcl::Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
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 );
885 // convert to core script type constants
886 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
888 // fill the font object
889 vcl::Font aFont;
890 ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW, nullptr, nullptr, nullptr, nScScript );
891 return aFont;
894 ScDxfFont XclExpFontHelper::GetDxfFontFromItemSet(const XclExpRoot& rRoot, const SfxItemSet& rItemSet)
896 sal_Int16 nScript = GetFirstUsedScript(rRoot, rItemSet);
898 // convert to core script type constants
899 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
900 return ScPatternAttr::GetDxfFont(rItemSet, nScScript);
903 bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
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 };
915 bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
916 if( !bUsed )
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 )
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" );
931 return bUsed;
934 namespace {
936 sal_uInt32 lclCalcHash( const XclFontData& rFontData )
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;
953 } // namespace
955 XclExpFont::XclExpFont( const XclExpRoot& rRoot,
956 const XclFontData& rFontData, XclExpColorType eColorType ) :
957 XclExpRecord( EXC_ID2_FONT, 14 ),
958 XclExpRoot( rRoot ),
959 maData( rFontData )
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 );
970 bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
972 return (mnHash == nHash) && (maData == rFontData);
975 void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
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 );
984 // private --------------------------------------------------------------------
986 void XclExpFont::WriteBody( XclExpStream& rStrm )
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 );
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 );
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;
1015 XclExpDxfFont::XclExpDxfFont(const XclExpRoot& rRoot,
1016 const SfxItemSet& rItemSet):
1017 XclExpRoot(rRoot)
1019 maDxfData = XclExpFontHelper::GetDxfFontFromItemSet(rRoot, rItemSet);
1022 namespace {
1024 const char* getUnderlineOOXValue(FontLineStyle eUnderline)
1026 switch (eUnderline)
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";
1039 const char* getFontFamilyOOXValue(FontFamily eValue)
1041 switch (eValue)
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";
1064 void XclExpDxfFont::SaveXml(XclExpXmlStream& rStrm)
1066 if (maDxfData.isEmpty())
1067 return;
1069 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1070 rStyleSheet->startElement(XML_font);
1072 if (maDxfData.pFontAttr)
1074 OUString aFontName = (*maDxfData.pFontAttr)->GetFamilyName();
1076 aFontName = XclTools::GetXclFontName(aFontName);
1077 if (!aFontName.isEmpty())
1079 rStyleSheet->singleElement(XML_name, XML_val, aFontName.toUtf8());
1082 rtl_TextEncoding eTextEnc = (*maDxfData.pFontAttr)->GetCharSet();
1083 sal_uInt8 nExcelCharSet = rtl_getBestWindowsCharsetFromTextEncoding(eTextEnc);
1084 if (nExcelCharSet)
1086 rStyleSheet->singleElement(XML_charset, XML_val, OString::number(nExcelCharSet));
1089 FontFamily eFamily = (*maDxfData.pFontAttr)->GetFamily();
1090 const char* pVal = getFontFamilyOOXValue(eFamily);
1091 if (pVal)
1093 rStyleSheet->singleElement(XML_family, XML_val, pVal);
1097 if (maDxfData.eWeight)
1099 rStyleSheet->singleElement(XML_b,
1100 XML_val, ToPsz10(maDxfData.eWeight.get() != WEIGHT_NORMAL));
1103 if (maDxfData.eItalic)
1105 bool bItalic = (maDxfData.eItalic.get() == ITALIC_OBLIQUE) || (maDxfData.eItalic.get() == ITALIC_NORMAL);
1106 rStyleSheet->singleElement(XML_i, XML_val, ToPsz10(bItalic));
1109 if (maDxfData.eStrike)
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);
1116 rStyleSheet->singleElement(XML_strike, XML_val, ToPsz10(bStrikeout));
1119 if (maDxfData.bOutline)
1121 rStyleSheet->singleElement(XML_outline, XML_val, ToPsz10(maDxfData.bOutline.get()));
1124 if (maDxfData.bShadow)
1126 rStyleSheet->singleElement(XML_shadow, XML_val, ToPsz10(maDxfData.bShadow.get()));
1129 if (maDxfData.aColor)
1131 rStyleSheet->singleElement(XML_color,
1132 XML_rgb, XclXmlUtils::ToOString(maDxfData.aColor.get()));
1135 if (maDxfData.nFontHeight)
1137 rStyleSheet->singleElement(XML_sz,
1138 XML_val, OString::number(*maDxfData.nFontHeight/20));
1141 if (maDxfData.eUnder)
1143 const char* pVal = getUnderlineOOXValue(maDxfData.eUnder.get());
1144 rStyleSheet->singleElement(XML_u, XML_val, pVal);
1147 rStyleSheet->endElement(XML_font);
1150 XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
1151 XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
1155 bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
1157 return false;
1160 void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
1162 // do nothing
1165 XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
1166 XclExpRoot( rRoot ),
1167 mnXclMaxSize( 0 )
1169 switch( GetBiff() )
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();
1176 InitDefaultFonts();
1179 const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
1181 return maFontList.GetRecord( nXclFont ).get();
1184 const XclFontData& XclExpFontBuffer::GetAppFontData() const
1186 return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
1189 sal_uInt16 XclExpFontBuffer::Insert(
1190 const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
1192 if( bAppFont )
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;
1201 size_t nPos = Find( rFontData );
1202 if( nPos == EXC_FONTLIST_NOTFOUND )
1204 // not found in buffer - create new font
1205 size_t nSize = maFontList.GetSize();
1206 if( nSize < mnXclMaxSize )
1208 // possible to insert
1209 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1210 nPos = nSize; // old size is last position now
1212 else
1214 // buffer is full - ignore new font, use default font
1215 nPos = EXC_FONT_APP;
1218 return static_cast< sal_uInt16 >( nPos );
1221 sal_uInt16 XclExpFontBuffer::Insert(
1222 const SvxFont& rFont, XclExpColorType eColorType )
1224 return Insert( XclFontData( rFont ), eColorType );
1227 sal_uInt16 XclExpFontBuffer::Insert( const SfxItemSet& rItemSet,
1228 sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1230 // #i17050# script type now provided by caller
1231 vcl::Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rItemSet, nScript );
1232 return Insert( XclFontData( aFont ), eColorType, bAppFont );
1235 void XclExpFontBuffer::Save( XclExpStream& rStrm )
1237 maFontList.Save( rStrm );
1240 void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
1242 if( maFontList.IsEmpty() )
1243 return;
1245 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1246 rStyleSheet->startElement(XML_fonts, XML_count, OString::number(maFontList.GetSize()));
1248 maFontList.SaveXml( rStrm );
1250 rStyleSheet->endElement( XML_fonts );
1253 // private --------------------------------------------------------------------
1255 void XclExpFontBuffer::InitDefaultFonts()
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 );
1264 switch( GetBiff() )
1266 case EXC_BIFF5:
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 ) );
1283 break;
1284 case EXC_BIFF8:
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() ) );
1295 break;
1296 default:
1297 DBG_ERROR_BIFF();
1301 size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
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;
1310 // FORMAT record - number formats =============================================
1312 /** Predicate for search algorithm. */
1313 struct XclExpNumFmtPred
1315 sal_uInt32 const mnScNumFmt;
1316 explicit XclExpNumFmtPred( sal_uInt32 nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
1317 bool operator()( const XclExpNumFmt& rFormat ) const
1318 { return rFormat.mnScNumFmt == mnScNumFmt; }
1321 void XclExpNumFmt::SaveXml( XclExpXmlStream& rStrm )
1323 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1324 rStyleSheet->singleElement( XML_numFmt,
1325 XML_numFmtId, OString::number(mnXclNumFmt),
1326 XML_formatCode, maNumFmtString.toUtf8() );
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 ) )
1335 switch( GetBiff() )
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();
1342 mxFormatter->FillKeywordTableForExcel( *mpKeywordTable );
1345 XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
1349 sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uInt32 nScNumFmt )
1351 XclExpNumFmtVec::const_iterator aIt =
1352 ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
1353 if( aIt != maFormatMap.end() )
1354 return aIt->mnXclNumFmt;
1356 size_t nSize = maFormatMap.size();
1357 if( nSize < static_cast< size_t >( 0xFFFF - mnXclOffset ) )
1359 sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
1360 maFormatMap.emplace_back( nScNumFmt, nXclNumFmt, GetFormatCode( nScNumFmt ) );
1361 return nXclNumFmt;
1364 return 0;
1367 void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
1369 for( const auto& rEntry : maFormatMap )
1370 WriteFormatRecord( rStrm, rEntry );
1373 void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
1375 if( maFormatMap.empty() )
1376 return;
1378 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1379 rStyleSheet->startElement(XML_numFmts, XML_count, OString::number(maFormatMap.size()));
1380 for( auto& rEntry : maFormatMap )
1382 rEntry.SaveXml( rStrm );
1384 rStyleSheet->endElement( XML_numFmts );
1387 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const OUString& rFormatStr )
1389 XclExpString aExpStr;
1390 if( GetBiff() <= EXC_BIFF5 )
1391 aExpStr.AssignByte( rFormatStr, GetTextEncoding(), XclStrFlags::EightBitLength );
1392 else
1393 aExpStr.Assign( rFormatStr );
1395 rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
1396 rStrm << nXclNumFmt << aExpStr;
1397 rStrm.EndRecord();
1400 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
1402 WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat.mnScNumFmt ) );
1405 namespace {
1407 OUString GetNumberFormatCode(const XclRoot& rRoot, const sal_uInt32 nScNumFmt, SvNumberFormatter* pFormatter, const NfKeywordTable* pKeywordTable)
1409 return rRoot.GetFormatter().GetFormatStringForExcel( nScNumFmt, *pKeywordTable, *pFormatter);
1414 OUString XclExpNumFmtBuffer::GetFormatCode( sal_uInt32 nScNumFmt )
1416 return GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() );
1419 // XF, STYLE record - Cell formatting =========================================
1421 bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
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 );
1429 void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
1431 ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
1432 ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
1435 void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
1437 rStrm.GetCurrentStream()->singleElement( XML_protection,
1438 XML_locked, ToPsz( mbLocked ),
1439 XML_hidden, ToPsz( mbHidden ) );
1442 bool XclExpCellAlign::FillFromItemSet(
1443 const SfxItemSet& rItemSet, bool bForceLineBreak, XclBiff eBiff, bool bStyle )
1445 bool bUsed = false;
1446 SvxCellHorJustify eHorAlign = rItemSet.Get( ATTR_HOR_JUSTIFY ).GetValue();
1447 SvxCellVerJustify eVerAlign = rItemSet.Get( ATTR_VER_JUSTIFY ).GetValue();
1449 switch( eBiff )
1451 case EXC_BIFF8: // attributes new in BIFF8
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 );
1459 // shrink to fit
1460 mbShrink = rItemSet.Get( ATTR_SHRINKTOFIT ).GetValue();
1461 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
1463 // CTL text direction
1464 SetScFrameDir( rItemSet.Get( ATTR_WRITINGDIR ).GetValue() );
1465 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
1467 [[fallthrough]];
1470 case EXC_BIFF5: // attributes new in BIFF5
1471 case EXC_BIFF4: // attributes new in BIFF4
1473 // vertical alignment
1474 SetScVerAlign( eVerAlign );
1475 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
1477 // stacked/rotation
1478 bool bStacked = rItemSet.Get( ATTR_STACKED ).GetValue();
1479 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
1480 if( bStacked )
1482 mnRotation = EXC_ROT_STACKED;
1484 else
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 );
1491 mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
1493 [[fallthrough]];
1496 case EXC_BIFF3: // attributes new in BIFF3
1498 // text wrap
1499 mbLineBreak = bForceLineBreak || rItemSet.Get( ATTR_LINEBREAK ).GetValue();
1500 bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
1502 [[fallthrough]];
1505 case EXC_BIFF2: // attributes new in BIFF2
1507 // horizontal alignment
1508 SetScHorAlign( eHorAlign );
1509 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
1512 break;
1513 default: DBG_ERROR_BIFF();
1516 if (eBiff == EXC_BIFF8)
1518 // Adjust for distributed alignments.
1519 if (eHorAlign == SvxCellHorJustify::Block)
1521 SvxCellJustifyMethod eHorJustMethod =
1522 rItemSet.GetItem<SvxJustifyMethodItem>(ATTR_HOR_JUSTIFY_METHOD)->GetValue();
1523 if (eHorJustMethod == SvxCellJustifyMethod::Distribute)
1524 mnHorAlign = EXC_XF_HOR_DISTRIB;
1527 if (eVerAlign == SvxCellVerJustify::Block)
1529 SvxCellJustifyMethod eVerJustMethod =
1530 rItemSet.GetItem<SvxJustifyMethodItem>(ATTR_VER_JUSTIFY_METHOD)->GetValue();
1531 if (eVerJustMethod == SvxCellJustifyMethod::Distribute)
1532 mnVerAlign = EXC_XF_VER_DISTRIB;
1536 return bUsed;
1539 void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
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 );
1547 void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
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 );
1558 static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
1560 switch( nHorAlign )
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";
1571 return "*unknown*";
1574 static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
1576 switch( nVerAlign )
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";
1584 return "*unknown*";
1587 void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
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() );
1601 namespace {
1603 void lclGetBorderLine(
1604 sal_uInt8& rnXclLine, sal_uInt32& rnColorId,
1605 const ::editeng::SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
1607 // Document: sc/qa/unit/data/README.cellborders
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] =
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
1625 rnXclLine = EXC_LINE_NONE;
1626 if( pLine )
1628 sal_uInt16 nOuterWidth = pLine->GetOutWidth();
1629 ExcelWidthIndex nOuterWidthIndx;
1630 CalcLineIndex nStyleIndex;
1632 switch (pLine->GetBorderLineStyle())
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;
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;
1676 rnXclLine = Map_LineLO_toMS[nStyleIndex][nOuterWidthIndx];
1679 if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
1680 rnXclLine = EXC_LINE_THIN;
1682 rnColorId = (pLine && (rnXclLine != EXC_LINE_NONE)) ?
1683 rPalette.InsertColor( pLine->GetColor(), EXC_COLOR_CELLBORDER ) :
1684 XclExpPalette::GetColorIdFromIndex( 0 );
1687 } // namespace
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 ) )
1698 bool XclExpCellBorder::FillFromItemSet(
1699 const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
1701 bool bUsed = false;
1703 switch( eBiff )
1705 case EXC_BIFF8: // attributes new in BIFF8
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);
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);
1719 if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
1721 mnDiagLine = nTLBRLine;
1722 mnDiagColorId = nTLBRColorId;
1724 else
1726 mnDiagLine = nBLTRLine;
1727 mnDiagColorId = nBLTRColorId;
1730 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
1731 ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
1733 [[fallthrough]];
1736 case EXC_BIFF5:
1737 case EXC_BIFF4:
1738 case EXC_BIFF3:
1739 case EXC_BIFF2:
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 );
1749 break;
1750 default: DBG_ERROR_BIFF();
1753 return bUsed;
1756 void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
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 );
1765 void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
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 );
1777 void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
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 );
1793 void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
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 );
1805 static const char* ToLineStyle( sal_uInt8 nLineStyle )
1807 switch( nLineStyle )
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";
1824 return "*unknown*";
1827 static void lcl_WriteBorder( XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor )
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
1836 rStyleSheet->startElement(nElement, XML_style, ToLineStyle(nLineStyle));
1837 rStyleSheet->singleElement(XML_color, XML_rgb, XclXmlUtils::ToOString(rColor));
1838 rStyleSheet->endElement( nElement );
1842 void XclExpCellBorder::SaveXml( XclExpXmlStream& rStrm ) const
1844 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1846 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1848 rStyleSheet->startElement( XML_border,
1849 XML_diagonalUp, ToPsz( mbDiagBLtoTR ),
1850 XML_diagonalDown, ToPsz( mbDiagTLtoBR )
1851 // OOXTODO: XML_outline
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 );
1862 XclExpCellArea::XclExpCellArea() :
1863 mnForeColorId( XclExpPalette::GetColorIdFromIndex( mnForeColor ) ),
1864 mnBackColorId( XclExpPalette::GetColorIdFromIndex( mnBackColor ) )
1868 bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
1870 const SvxBrushItem& rBrushItem = rItemSet.Get( ATTR_BACKGROUND );
1871 if( rBrushItem.GetColor().GetTransparency() )
1873 mnPattern = EXC_PATT_NONE;
1874 mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1875 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
1877 else
1879 mnPattern = EXC_PATT_SOLID;
1880 mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
1881 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1883 return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
1886 void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
1888 rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
1891 void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
1893 ::insert_value( rnArea, mnPattern, 16, 6 );
1894 ::insert_value( rnArea, mnForeColor, 0, 7 );
1895 ::insert_value( rnArea, mnBackColor, 7, 7 );
1898 void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
1900 ::insert_value( rnBorder2, mnPattern, 26, 6 );
1901 ::insert_value( rnArea, mnForeColor, 0, 7 );
1902 ::insert_value( rnArea, mnBackColor, 7, 7 );
1905 void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
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 );
1917 static const char* ToPatternType( sal_uInt8 nPattern )
1919 switch( nPattern )
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";
1929 return "*unknown*";
1932 void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
1934 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1935 rStyleSheet->startElement(XML_fill);
1937 // OOXTODO: XML_gradientFill
1939 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1941 if( mnPattern == EXC_PATT_NONE || ( mnForeColor == 0 && mnBackColor == 0 ) )
1942 rStyleSheet->singleElement(XML_patternFill, XML_patternType, ToPatternType(mnPattern));
1943 else
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 );
1953 rStyleSheet->endElement( XML_fill );
1956 bool XclExpColor::FillFromItemSet( const SfxItemSet& rItemSet )
1958 if( !ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true ) )
1959 return false;
1961 const SvxBrushItem& rBrushItem = rItemSet.Get( ATTR_BACKGROUND );
1962 maColor = rBrushItem.GetColor();
1964 return true;
1967 void XclExpColor::SaveXml( XclExpXmlStream& rStrm ) const
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));
1974 rStyleSheet->endElement( XML_patternFill );
1975 rStyleSheet->endElement( XML_fill );
1978 XclExpXFId::XclExpXFId() :
1979 mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
1980 mnXFIndex( EXC_XF_DEFAULTCELL )
1984 XclExpXFId::XclExpXFId( sal_uInt32 nXFId ) :
1985 mnXFId( nXFId ),
1986 mnXFIndex( EXC_XF_DEFAULTCELL )
1990 void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
1992 mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
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 )
2001 mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
2002 Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
2005 XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet ) :
2006 XclXFBase( false ),
2007 XclExpRoot( rRoot ),
2008 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
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 );
2016 XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF ) :
2017 XclXFBase( bCellXF ),
2018 XclExpRoot( rRoot ),
2019 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2021 InitDefault();
2024 bool XclExpXF::Equals( const ScPatternAttr& rPattern,
2025 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
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));
2033 bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
2035 return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
2038 void XclExpXF::SetFinalColors()
2040 maBorder.SetFinalColors( GetPalette() );
2041 maArea.SetFinalColors( GetPalette() );
2044 bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
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);
2053 void XclExpXF::InitDefault()
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);
2062 void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
2063 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
2065 InitDefault();
2066 mpItemSet = &rItemSet;
2068 // cell protection
2069 mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
2071 // font
2072 if( nForceXclFont == EXC_FONT_NOTFOUND )
2074 mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
2075 mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
2077 else
2079 mnXclFont = nForceXclFont;
2080 mbFontUsed = true;
2083 // number format
2084 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
2085 mnXclNumFmt = nForceScNumFmt;
2086 else
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);
2096 mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
2097 mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
2099 // alignment
2100 mbAlignUsed = maAlignment.FillFromItemSet( rItemSet, bForceLineBreak, GetBiff(), IsStyleXF() );
2102 // cell border
2103 mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
2105 // background area
2106 mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
2108 // set all b***Used flags to true in "Default"/"Normal" style
2109 if( bDefStyle )
2110 SetAllUsedFlags( true );
2113 sal_uInt8 XclExpXF::GetUsedFlags() const
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;
2127 void XclExpXF::WriteBody5( XclExpStream& rStrm )
2129 sal_uInt16 nTypeProt = 0, nAlign = 0;
2130 sal_uInt32 nArea = 0, nBorder = 0;
2132 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2133 ::insert_value( nTypeProt, mnParent, 4, 12 );
2134 ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
2136 maProtection.FillToXF3( nTypeProt );
2137 maAlignment.FillToXF5( nAlign );
2138 maBorder.FillToXF5( nBorder, nArea );
2139 maArea.FillToXF5( nArea );
2141 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
2144 void XclExpXF::WriteBody8( XclExpStream& rStrm )
2146 sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
2147 sal_uInt32 nBorder1 = 0, nBorder2 = 0;
2149 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2150 ::insert_value( nTypeProt, mnParent, 4, 12 );
2151 ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
2153 maProtection.FillToXF3( nTypeProt );
2154 maAlignment.FillToXF8( nAlign, nMiscAttrib );
2155 maBorder.FillToXF8( nBorder1, nBorder2 );
2156 maArea.FillToXF8( nBorder2, nArea );
2158 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
2161 void XclExpXF::WriteBody( XclExpStream& rStrm )
2163 XclExpXFId aParentId( mnParentXFId );
2164 aParentId.ConvertXFIndex( GetRoot() );
2165 mnParent = aParentId.mnXFIndex;
2166 switch( GetBiff() )
2168 case EXC_BIFF5: WriteBody5( rStrm ); break;
2169 case EXC_BIFF8: WriteBody8( rStrm ); break;
2170 default: DBG_ERROR_BIFF();
2174 void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
2176 mnBorderId = nBorderId;
2177 mnFillId = nFillId;
2180 void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
2182 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2184 sal_Int32 nXfId = 0;
2185 const XclExpXF* pStyleXF = nullptr;
2186 if( IsCellXF() )
2188 sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
2189 nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
2190 pStyleXF = rStrm.GetRoot().GetXFBuffer().GetXFById( mnParentXFId );
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 );
2216 // OOXTODO: XML_extLst
2217 rStyleSheet->endElement( XML_xf );
2220 XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
2221 XclExpXF( rRoot, bCellXF )
2225 void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
2227 mnXclFont = nXclFont;
2228 mbFontUsed = true;
2231 void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
2233 mnXclNumFmt = nXclNumFmt;
2234 mbFmtUsed = true;
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 )
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
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 )
2260 void XclExpStyle::WriteBody( XclExpStream& rStrm )
2262 maXFId.ConvertXFIndex( rStrm.GetRoot() );
2263 ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
2264 rStrm << maXFId.mnXFIndex;
2266 if( IsBuiltIn() )
2268 rStrm << mnStyleId << mnLevel;
2270 else
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;
2281 static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
2283 switch( nStyleId )
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]";
2292 return "*unknown*";
2295 void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
2297 constexpr sal_Int32 CELL_STYLE_MAX_BUILTIN_ID = 54;
2298 OString sName;
2299 OString sBuiltinId;
2300 const char* pBuiltinId = nullptr;
2301 if( IsBuiltIn() )
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();
2307 else
2308 sName = maName.toUtf8();
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() )
2323 // OOXTODO: XML_extLst
2326 namespace {
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;
2332 bool lclIsBuiltInStyle( const OUString& rStyleName )
2334 return
2335 XclTools::IsBuiltInStyleName( rStyleName ) ||
2336 XclTools::IsCondFormatStyleName( rStyleName );
2339 } // namespace
2341 XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
2342 mnStyleId( EXC_STYLE_USERDEF ),
2343 mnLevel( EXC_STYLE_NOLEVEL ),
2344 mbPredefined( true ),
2345 mbHasStyleRec( false )
2349 /** Predicate for search algorithm. */
2350 struct XclExpBorderPred
2352 const XclExpCellBorder&
2353 mrBorder;
2354 explicit XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
2355 bool operator()( const XclExpCellBorder& rBorder ) const;
2358 bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
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;
2380 struct XclExpFillPred
2382 const XclExpCellArea&
2383 mrFill;
2384 explicit XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
2385 bool operator()( const XclExpCellArea& rFill ) const;
2388 bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
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;
2398 XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot ) :
2399 XclExpRoot( rRoot )
2403 void XclExpXFBuffer::Initialize()
2405 InsertDefaultRecords();
2406 InsertUserStyles();
2409 sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
2411 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
2414 sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
2415 sal_uInt16 nForceXclFont, bool bForceLineBreak )
2417 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
2420 sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForceScNumFmt, bool bForceLineBreak )
2422 return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
2425 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
2427 return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2430 sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
2432 return EXC_XFLIST_INDEXBASE | nXFIndex;
2435 sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
2437 return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
2440 const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
2442 return maXFList.GetRecord( nXFId ).get();
2445 void XclExpXFBuffer::Finalize()
2447 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2448 maXFList.GetRecord( nPos )->SetFinalColors();
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 );
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;
2462 // *** map all built-in XF records (cell and style) *** -------------------
2464 // do not change XF order -> std::map<> iterates elements in ascending order
2465 for( const auto& rEntry : maBuiltInMap )
2466 AppendXFIndex( rEntry.first );
2468 // *** insert all user-defined style XF records, without reduce *** -------
2470 sal_uInt32 nStyleXFCount = 0; // counts up to EXC_XF_MAXSTYLECOUNT limit
2472 for( nId = 0; nId < nTotalCount; ++nId )
2474 XclExpXFRef xXF = maXFList.GetRecord( nId );
2475 if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2477 if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
2479 // maximum count of styles not reached
2480 AppendXFIndex( nId );
2481 ++nStyleXFCount;
2483 else
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;
2493 // *** insert all cell XF records *** -------------------------------------
2495 // start position to search for equal inserted XF records
2496 size_t nSearchStart = maSortedXFList.GetSize();
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 )
2502 XclExpXFRef xXF = maXFList.GetRecord( nId );
2503 if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2505 // try to find an XF record equal to *xXF, which is already inserted
2506 sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
2508 // first try if it is equal to the default cell XF
2509 if( xDefCellXF->Equals( *xXF ) )
2511 nFoundIndex = EXC_XF_DEFAULTCELL;
2513 else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
2514 (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
2516 if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
2517 nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
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 );
2528 sal_uInt16 nXmlStyleIndex = 0;
2529 sal_uInt16 nXmlCellIndex = 0;
2531 size_t nXFCount = maSortedXFList.GetSize();
2532 for( size_t i = 0; i < nXFCount; ++i )
2534 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2535 if( xXF->IsStyleXF() )
2536 maStyleIndexes[ i ] = nXmlStyleIndex++;
2537 else
2538 maCellIndexes[ i ] = nXmlCellIndex++;
2542 sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
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;
2552 sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
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 ];
2560 sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
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 ];
2568 void XclExpXFBuffer::Save( XclExpStream& rStrm )
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 );
2576 static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
2578 rCells = 0;
2579 rStyles = 0;
2580 size_t nXFCount = rXFList.GetSize();
2581 for( size_t i = 0; i < nXFCount; ++i )
2583 XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
2584 if( xXF->IsCellXF() )
2585 ++rCells;
2586 else if( xXF->IsStyleXF() )
2587 ++rStyles;
2591 void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
2593 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2595 rStyleSheet->startElement(XML_fills, XML_count, OString::number(maFills.size()));
2596 for( const auto& rFill : maFills )
2598 rFill.SaveXml( rStrm );
2600 rStyleSheet->endElement( XML_fills );
2602 rStyleSheet->startElement(XML_borders, XML_count, OString::number(maBorders.size()));
2603 for( const auto& rBorder : maBorders )
2605 rBorder.SaveXml( rStrm );
2607 rStyleSheet->endElement( XML_borders );
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 );
2613 if( nStyles > 0 )
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 )
2619 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2620 if( ! xXF->IsStyleXF() )
2621 continue;
2622 SaveXFXml( rStrm, *xXF );
2624 rStyleSheet->endElement( XML_cellStyleXfs );
2627 if( nCells > 0 )
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 )
2633 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2634 if( ! xXF->IsCellXF() )
2635 continue;
2636 SaveXFXml( rStrm, *xXF );
2638 rStyleSheet->endElement( XML_cellXfs );
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 );
2647 void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
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!" );
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 );
2662 rXF.SetXmlIds( nBorderId, nFillId );
2663 rXF.SaveXml( rStrm );
2666 sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
2667 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2669 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND && nForceXclFont == EXC_FONT_NOTFOUND)
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())
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;
2683 else if (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND || nForceXclFont == EXC_FONT_NOTFOUND)
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())
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;
2697 else
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;
2707 return EXC_XFID_NOTFOUND;
2710 sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
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;
2724 sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
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);
2730 if (aIt != maBuiltInMap.end())
2731 return aIt->first;
2732 return EXC_XFID_NOTFOUND;
2735 XclExpXFBuffer::FindKey XclExpXFBuffer::ToFindKey(XclExpXF const & rRec)
2737 return { rRec.IsCellXF(), rRec.GetItemSet(), rRec.GetScNumFmt(), rRec.GetXclFont() };
2740 sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
2741 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
2743 const ScPatternAttr* pDefPattern = GetDoc().GetDefPattern();
2744 if( !pPattern )
2745 pPattern = pDefPattern;
2747 // special handling for default cell formatting
2748 if( (pPattern == pDefPattern) && !bForceLineBreak &&
2749 (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
2750 (nForceXclFont == EXC_FONT_NOTFOUND) )
2752 // Is it the first try to insert the default cell format?
2753 bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
2754 if( rbPredefined )
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;
2767 return GetDefCellXFId();
2770 sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2771 if( nXFId == EXC_XFID_NOTFOUND )
2773 // not found - insert new cell XF
2774 if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
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);
2783 else
2785 // list full - fall back to default cell XF
2786 nXFId = GetDefCellXFId();
2789 return nXFId;
2792 sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
2794 // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
2796 sal_uInt8 nStyleId, nLevel;
2797 if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
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 )
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;
2809 else
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 )
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;
2829 // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
2830 bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
2831 if( !rbHasStyleRec )
2833 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2834 rbHasStyleRec = true;
2837 return nXFId;
2840 // *** try to find the XF record of a user-defined style ***
2842 sal_uInt32 nXFId = FindXF( rStyleSheet );
2843 if( nXFId == EXC_XFID_NOTFOUND )
2845 // not found - insert new style XF and STYLE
2846 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2847 if( nXFId < EXC_XFLIST_HARDLIMIT )
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);
2856 else
2857 // list full - fall back to default style XF
2858 nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2860 return nXFId;
2863 void XclExpXFBuffer::InsertUserStyles()
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 );
2871 sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef const & xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
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;
2883 sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef const & xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
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;
2891 static XclExpCellArea lcl_GetPatternFill_None()
2893 XclExpCellArea aFill;
2894 aFill.mnPattern = EXC_PATT_NONE;
2895 return aFill;
2898 static XclExpCellArea lcl_GetPatternFill_Gray125()
2900 XclExpCellArea aFill;
2901 aFill.mnPattern = EXC_PATT_12_5_PERC;
2902 aFill.mnForeColor = 0;
2903 aFill.mnBackColor = 0;
2904 return aFill;
2907 void XclExpXFBuffer::InsertDefaultRecords()
2909 maFills.push_back( lcl_GetPatternFill_None() );
2910 maFills.push_back( lcl_GetPatternFill_Gray125() );
2912 // index 0: default style
2913 if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScResId( STR_STYLENAME_STANDARD ), SfxStyleFamily::Para ) )
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;
2920 else
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 );
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 )
2942 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, nLevel );
2943 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, nLevel );
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;
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 );
2965 // other built-in style XF records (i.e. Hyperlink styles) are created on demand
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() );
2972 void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
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" );
2982 void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
2984 if( std::none_of( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) )
2986 maBorders.push_back( rXF.GetBorderData() );
2989 if( std::none_of( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) )
2991 maFills.push_back( rXF.GetAreaData() );
2995 XclExpDxfs::XclExpDxfs( const XclExpRoot& rRoot )
2996 : XclExpRoot( rRoot ),
2997 mpKeywordTable( new NfKeywordTable )
2999 // Special number formatter for conversion.
3000 SvNumberFormatterPtr xFormatter(new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ));
3001 xFormatter->FillKeywordTableForExcel( *mpKeywordTable );
3003 SCTAB nTables = rRoot.GetDoc().GetTableCount();
3004 sal_Int32 nIndex = 0;
3005 for(SCTAB nTab = 0; nTab < nTables; ++nTab)
3007 ScConditionalFormatList* pList = rRoot.GetDoc().GetCondFormList(nTab);
3008 if (pList)
3010 for (const auto& rxItem : *pList)
3012 size_t nEntryCount = rxItem->size();
3013 for (size_t nFormatEntry = 0; nFormatEntry < nEntryCount; ++nFormatEntry)
3015 const ScFormatEntry* pFormatEntry = rxItem->GetEntry(nFormatEntry);
3016 if (!pFormatEntry || (pFormatEntry->GetType() != ScFormatEntry::Type::Condition &&
3017 pFormatEntry->GetType() != ScFormatEntry::Type::Date))
3018 continue;
3020 OUString aStyleName;
3021 if(pFormatEntry->GetType() == ScFormatEntry::Type::Condition)
3023 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
3024 aStyleName= pEntry->GetStyle();
3026 else
3028 const ScCondDateFormatEntry* pEntry = static_cast<const ScCondDateFormatEntry*>(pFormatEntry);
3029 aStyleName = pEntry->GetStyleName();
3032 if (maStyleNameToDxfId.emplace(aStyleName, nIndex).second)
3034 SfxStyleSheetBase* pStyle = rRoot.GetDoc().GetStyleSheetPool()->Find(aStyleName);
3035 if(!pStyle)
3036 continue;
3038 SfxItemSet& rSet = pStyle->GetItemSet();
3040 std::unique_ptr<XclExpCellBorder> pBorder(new XclExpCellBorder);
3041 if (!pBorder->FillFromItemSet( rSet, GetPalette(), GetBiff()) )
3043 pBorder.reset();
3046 std::unique_ptr<XclExpCellAlign> pAlign(new XclExpCellAlign);
3047 if (!pAlign->FillFromItemSet( rSet, false, GetBiff()))
3049 pAlign.reset();
3052 std::unique_ptr<XclExpCellProt> pCellProt(new XclExpCellProt);
3053 if (!pCellProt->FillFromItemSet( rSet ))
3055 pCellProt.reset();
3058 std::unique_ptr<XclExpColor> pColor(new XclExpColor);
3059 if(!pColor->FillFromItemSet( rSet ))
3061 pColor.reset();
3064 std::unique_ptr<XclExpDxfFont> pFont(new XclExpDxfFont(rRoot, rSet));
3066 std::unique_ptr<XclExpNumFmt> pNumFormat;
3067 const SfxPoolItem *pPoolItem = nullptr;
3068 if( rSet.GetItemState( ATTR_VALUE_FORMAT, true, &pPoolItem ) == SfxItemState::SET )
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() )));
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;
3086 sal_Int32 XclExpDxfs::GetDxfId( const OUString& rStyleName )
3088 std::map<OUString, sal_Int32>::iterator itr = maStyleNameToDxfId.find(rStyleName);
3089 if(itr!= maStyleNameToDxfId.end())
3090 return itr->second;
3091 return -1;
3094 void XclExpDxfs::SaveXml( XclExpXmlStream& rStrm )
3096 if(maDxf.empty())
3097 return;
3099 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3100 rStyleSheet->startElement(XML_dxfs, XML_count, OString::number(maDxf.size()));
3102 for ( auto& rxDxf : maDxf )
3104 rxDxf->SaveXml( rStrm );
3107 rStyleSheet->endElement( XML_dxfs );
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))
3123 XclExpDxf::~XclExpDxf()
3127 void XclExpDxf::SaveXml( XclExpXmlStream& rStrm )
3129 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3130 rStyleSheet->startElement(XML_dxf);
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 );
3147 void XclExpDxf::SaveXmlExt( XclExpXmlStream& rStrm )
3149 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3150 rStyleSheet->startElementNS( XML_x14, XML_dxf );
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 );;
3168 XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
3169 : XclExpRoot( rRoot )
3173 void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
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 );
3183 aStyleSheet->startElement( XML_styleSheet,
3184 XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8() );
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 );
3192 aStyleSheet->endElement( XML_styleSheet );
3194 rStrm.PopStream();
3197 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */