use insert function instead of for loop
[LibreOffice.git] / sc / source / filter / excel / xestyle.cxx
blob01bc9bfe8d81634d75650756321648be493f00bd
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 <utility>
22 #include <xestyle.hxx>
24 #include <algorithm>
25 #include <iterator>
26 #include <com/sun/star/i18n/ScriptType.hpp>
27 #include <comphelper/processfactory.hxx>
28 #include <rtl/tencinfo.h>
29 #include <vcl/font.hxx>
30 #include <svl/languageoptions.hxx>
31 #include <scitems.hxx>
32 #include <editeng/borderline.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/lineitem.hxx>
35 #include <editeng/brushitem.hxx>
36 #include <editeng/frmdiritem.hxx>
37 #include <editeng/fontitem.hxx>
38 #include <editeng/justifyitem.hxx>
39 #include <editeng/langitem.hxx>
40 #include <document.hxx>
41 #include <stlpool.hxx>
42 #include <stlsheet.hxx>
43 #include <patattr.hxx>
44 #include <attrib.hxx>
45 #include <globstr.hrc>
46 #include <scresid.hxx>
47 #include <xestring.hxx>
48 #include <xltools.hxx>
49 #include <conditio.hxx>
50 #include <dbdata.hxx>
51 #include <filterentries.hxx>
52 #include <export/ExportTools.hxx>
53 #include <dpobject.hxx>
54 #include <dpsave.hxx>
55 #include <pivot/PivotTableFormats.hxx>
57 #include <o3tl/safeint.hxx>
58 #include <oox/export/utils.hxx>
59 #include <oox/token/tokens.hxx>
60 #include <oox/token/namespaces.hxx>
61 #include <oox/token/relationship.hxx>
62 #include <svl/numformat.hxx>
64 using namespace ::com::sun::star;
65 using namespace oox;
67 // PALETTE record - color information =========================================
69 namespace {
71 sal_uInt32 lclGetWeighting( XclExpColorType eType )
73 switch( eType )
75 case EXC_COLOR_CHARTLINE: return 1;
76 case EXC_COLOR_CELLBORDER:
77 case EXC_COLOR_CHARTAREA: return 2;
78 case EXC_COLOR_CELLTEXT:
79 case EXC_COLOR_CHARTTEXT:
80 case EXC_COLOR_CTRLTEXT: return 10;
81 case EXC_COLOR_TABBG:
82 case EXC_COLOR_CELLAREA: return 20;
83 case EXC_COLOR_GRID: return 50;
84 default: OSL_FAIL( "lclGetWeighting - unknown color type" );
86 return 1;
89 sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
91 sal_Int32 nDist = rColor1.GetRed() - rColor2.GetRed();
92 nDist *= nDist * 77;
93 sal_Int32 nDummy = rColor1.GetGreen() - rColor2.GetGreen();
94 nDist += nDummy * nDummy * 151;
95 nDummy = rColor1.GetBlue() - rColor2.GetBlue();
96 nDist += nDummy * nDummy * 28;
97 return nDist;
100 sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
102 sal_uInt8 nComp1Dist = ::std::min< sal_uInt8 >( nComp1, 0xFF - nComp1 );
103 sal_uInt8 nComp2Dist = ::std::min< sal_uInt8 >( nComp2, 0xFF - nComp2 );
104 if( nComp1Dist != nComp2Dist )
106 /* #i36945# One of the passed RGB components is nearer at the limits (0x00 or 0xFF).
107 Increase its weighting to prevent fading of the colors during reduction. */
108 const sal_uInt8& rnCompNearer = (nComp1Dist < nComp2Dist) ? nComp1 : nComp2;
109 sal_uInt32& rnWeight = (nComp1Dist < nComp2Dist) ? nWeight1 : nWeight2;
110 rnWeight *= ((rnCompNearer - 0x80L) * (rnCompNearer - 0x7FL) / 0x1000L + 1);
112 sal_uInt32 nWSum = nWeight1 + nWeight2;
113 return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
116 void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
118 rDest.SetRed( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetRed() ) + rSrc2.GetRed()) / 2 ) );
119 rDest.SetGreen( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetGreen() ) + rSrc2.GetGreen()) / 2 ) );
120 rDest.SetBlue( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetBlue() ) + rSrc2.GetBlue()) / 2 ) );
123 } // namespace
125 // additional classes for color reduction -------------------------------------
127 namespace {
129 /** Represents an entry in a color list.
131 The color stores a weighting value, which increases the more the color is
132 used in the document. Heavy-weighted colors will change less than others on
133 color reduction.
135 class XclListColor
137 private:
138 Color maColor; /// The color value of this palette entry.
139 sal_uInt32 mnColorId; /// Unique color ID for color reduction.
140 sal_uInt32 mnWeight; /// Weighting for color reduction.
141 bool mbBaseColor; /// true = Handle as base color, (don't remove/merge).
143 public:
144 explicit XclListColor( const Color& rColor, sal_uInt32 nColorId );
146 /** Returns the RGB color value of the color. */
147 const Color& GetColor() const { return maColor; }
148 /** Returns the unique ID of the color. */
149 sal_uInt32 GetColorId() const { return mnColorId; }
150 /** Returns the current weighting of the color. */
151 sal_uInt32 GetWeighting() const { return mnWeight; }
152 /** Returns true, if this color is a base color, i.e. it will not be removed or merged. */
153 bool IsBaseColor() const { return mbBaseColor; }
155 /** Adds the passed weighting to this color. */
156 void AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
157 /** Merges this color with rColor, regarding weighting settings. */
158 void Merge( const XclListColor& rColor );
161 XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
162 maColor( rColor ),
163 mnColorId( nColorId ),
164 mnWeight( 0 )
166 mbBaseColor =
167 ((rColor.GetRed() == 0x00) || (rColor.GetRed() == 0xFF)) &&
168 ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
169 ((rColor.GetBlue() == 0x00) || (rColor.GetBlue() == 0xFF));
172 void XclListColor::Merge( const XclListColor& rColor )
174 sal_uInt32 nWeight2 = rColor.GetWeighting();
175 // do not change RGB value of base colors
176 if( !mbBaseColor )
178 maColor.SetRed( lclGetMergedColorComp( maColor.GetRed(), mnWeight, rColor.maColor.GetRed(), nWeight2 ) );
179 maColor.SetGreen( lclGetMergedColorComp( maColor.GetGreen(), mnWeight, rColor.maColor.GetGreen(), nWeight2 ) );
180 maColor.SetBlue( lclGetMergedColorComp( maColor.GetBlue(), mnWeight, rColor.maColor.GetBlue(), nWeight2 ) );
182 AddWeighting( nWeight2 );
185 /** Data for each inserted original color, represented by a color ID. */
186 struct XclColorIdData
188 Color maColor; /// The original inserted color.
189 sal_uInt32 mnIndex; /// Maps current color ID to color list or export color vector.
190 /** Sets the contents of this struct. */
191 void Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
194 /** A color that will be written to the Excel file. */
195 struct XclPaletteColor
197 Color maColor; /// Resulting color to export.
198 bool mbUsed; /// true = Entry is used in the document.
200 explicit XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
201 void SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
204 /** Maps a color list index to a palette index.
205 @descr Used to remap the color ID data vector from list indexes to palette indexes. */
206 struct XclRemap
208 sal_uInt32 mnPalIndex; /// Index to palette.
209 bool mbProcessed; /// true = List color already processed.
211 explicit XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
212 void SetIndex( sal_uInt32 nPalIndex )
213 { mnPalIndex = nPalIndex; mbProcessed = true; }
216 /** Stores the nearest palette color index of a list color. */
217 struct XclNearest
219 sal_uInt32 mnPalIndex; /// Index to nearest palette color.
220 sal_Int32 mnDist; /// Distance to palette color.
222 explicit XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
225 } // namespace
227 class XclExpPaletteImpl
229 public:
230 explicit XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
232 /** Inserts the color into the list and updates weighting.
233 @param nAutoDefault The Excel palette index for automatic color.
234 @return A unique ID for this color. */
235 sal_uInt32 InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault = 0 );
236 /** Returns the color ID representing a fixed Excel palette index (i.e. for auto colors). */
237 static sal_uInt32 GetColorIdFromIndex( sal_uInt16 nIndex );
239 /** Reduces the color list to the maximum count of the current BIFF version. */
240 void Finalize();
242 /** Returns the Excel palette index of the color with passed color ID. */
243 sal_uInt16 GetColorIndex( sal_uInt32 nColorId ) const;
245 /** Returns a foreground and background color for the two passed color IDs.
246 @descr If rnXclPattern contains a solid pattern, this function tries to find
247 the two best fitting colors and a mix pattern (25%, 50% or 75%) for nForeColorId.
248 This will result in a better approximation to the passed foreground color. */
249 void GetMixedColors(
250 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
251 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const;
253 /** Returns the RGB color for a (non-zero-based) Excel palette entry.
254 @return The color from current or default palette or COL_AUTO, if nothing else found. */
255 Color GetColor( sal_uInt16 nXclIndex ) const;
257 /** Returns true, if all colors of the palette are equal to default palette colors. */
258 bool IsDefaultPalette() const;
259 /** Writes the color list (contents of the palette record) to the passed stream. */
260 void WriteBody( XclExpStream& rStrm );
261 void SaveXml( XclExpXmlStream& rStrm );
263 private:
264 /** Returns the Excel index of a 0-based color index. */
265 static sal_uInt16 GetXclIndex( sal_uInt32 nIndex )
266 { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
268 /** Returns the original inserted color represented by the color ID nColorId. */
269 const Color& GetOriginalColor( sal_uInt32 nColorId ) const;
271 /** Searches for rColor, returns the ordered insertion index for rColor in rnIndex. */
272 XclListColor* SearchListEntry( const Color& rColor, sal_uInt32& rnIndex );
273 /** Creates and inserts a new color list entry at the specified list position. */
274 XclListColor* CreateListEntry( const Color& rColor, sal_uInt32 nIndex );
276 /** Raw and fast reduction of the palette. */
277 void RawReducePalette( sal_uInt32 nPass );
278 /** Reduction of one color using advanced color merging based on color weighting. */
279 void ReduceLeastUsedColor();
281 /** Finds the least used color and returns its current list index. */
282 sal_uInt32 GetLeastUsedListColor() const;
283 /** Returns the list index of the color nearest to rColor.
284 @param nIgnore List index of a color which will be ignored.
285 @return The list index of the found color. */
286 sal_uInt32 GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const;
287 /** Returns the list index of the color nearest to the color with list index nIndex. */
288 sal_uInt32 GetNearestListColor( sal_uInt32 nIndex ) const;
290 /** Returns in rnIndex the palette index of the color nearest to rColor.
291 Searches for default colors only (colors never replaced).
292 @return The distance from passed color to found color. */
293 sal_Int32 GetNearestPaletteColor(
294 sal_uInt32& rnIndex,
295 const Color& rColor ) const;
296 /** Returns in rnFirst and rnSecond the palette indexes of the two colors nearest to rColor.
297 @return The minimum distance from passed color to found colors. */
298 sal_Int32 GetNearPaletteColors(
299 sal_uInt32& rnFirst, sal_uInt32& rnSecond,
300 const Color& rColor ) const;
302 private:
303 typedef std::vector< std::unique_ptr<XclListColor> > XclListColorList;
304 typedef std::shared_ptr< XclListColorList > XclListColorListRef;
306 const XclDefaultPalette& mrDefPal; /// The default palette for the current BIFF version.
307 XclListColorListRef mxColorList; /// Working color list.
308 std::vector< XclColorIdData >
309 maColorIdDataVec; /// Data of all CIDs.
310 std::vector< XclPaletteColor >
311 maPalette; /// Contains resulting colors to export.
312 sal_uInt32 mnLastIdx; /// Last insertion index for search opt.
315 const sal_uInt32 EXC_PAL_INDEXBASE = 0xFFFF0000;
316 const sal_uInt32 EXC_PAL_MAXRAWSIZE = 1024;
318 XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
319 mrDefPal( rDefPal ),
320 mxColorList( std::make_shared<XclListColorList>() ),
321 mnLastIdx( 0 )
323 // initialize maPalette with default colors
324 sal_uInt16 nCount = static_cast< sal_uInt16 >( mrDefPal.GetColorCount() );
325 maPalette.reserve( nCount );
326 for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
327 maPalette.emplace_back( mrDefPal.GetDefColor( GetXclIndex( nIdx ) ) );
329 InsertColor( COL_BLACK, EXC_COLOR_CELLTEXT );
332 sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
334 if( rColor == COL_AUTO )
335 return GetColorIdFromIndex( nAutoDefault );
337 sal_uInt32 nFoundIdx = 0;
338 XclListColor* pEntry = SearchListEntry( rColor, nFoundIdx );
339 if( !pEntry || (pEntry->GetColor() != rColor) )
340 pEntry = CreateListEntry( rColor, nFoundIdx );
341 pEntry->AddWeighting( lclGetWeighting( eType ) );
343 return pEntry->GetColorId();
346 sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
348 return EXC_PAL_INDEXBASE | nIndex;
351 void XclExpPaletteImpl::Finalize()
353 // --- build initial color ID data vector (maColorIdDataVec) ---
355 sal_uInt32 nCount = mxColorList->size();
356 maColorIdDataVec.resize( nCount );
357 for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
359 const XclListColor& listColor = *mxColorList->at( nIdx );
360 maColorIdDataVec[ listColor.GetColorId() ].Set( listColor.GetColor(), nIdx );
363 // --- loop as long as current color count does not fit into palette of current BIFF ---
365 // phase 1: raw reduction (performance reasons, #i36945#)
366 sal_uInt32 nPass = 0;
367 while( mxColorList->size() > EXC_PAL_MAXRAWSIZE )
368 RawReducePalette( nPass++ );
370 // phase 2: precise reduction using advanced color merging based on color weighting
371 while( mxColorList->size() > mrDefPal.GetColorCount() )
372 ReduceLeastUsedColor();
374 // --- use default palette and replace colors with nearest used colors ---
376 nCount = mxColorList->size();
377 std::vector< XclRemap > aRemapVec( nCount );
378 std::vector< XclNearest > aNearestVec( nCount );
380 // in each run: search the best fitting color and replace a default color with it
381 for( sal_uInt32 nRun = 0; nRun < nCount; ++nRun )
383 sal_uInt32 nIndex;
384 // find nearest unused default color for each unprocessed list color
385 for( nIndex = 0; nIndex < nCount; ++nIndex )
386 aNearestVec[ nIndex ].mnDist = aRemapVec[ nIndex ].mbProcessed ? SAL_MAX_INT32 :
387 GetNearestPaletteColor( aNearestVec[ nIndex ].mnPalIndex, mxColorList->at( nIndex )->GetColor() );
388 // find the list color which is nearest to a default color
389 sal_uInt32 nFound = 0;
390 for( nIndex = 1; nIndex < nCount; ++nIndex )
391 if( aNearestVec[ nIndex ].mnDist < aNearestVec[ nFound ].mnDist )
392 nFound = nIndex;
393 // replace default color with list color
394 sal_uInt32 nNearest = aNearestVec[ nFound ].mnPalIndex;
395 OSL_ENSURE( nNearest < maPalette.size(), "XclExpPaletteImpl::Finalize - algorithm error" );
396 maPalette[ nNearest ].SetColor( mxColorList->at( nFound )->GetColor() );
397 aRemapVec[ nFound ].SetIndex( nNearest );
400 // remap color ID data map (maColorIdDataVec) from list indexes to palette indexes
401 for( auto& rColorIdData : maColorIdDataVec )
402 rColorIdData.mnIndex = aRemapVec[ rColorIdData.mnIndex ].mnPalIndex;
405 sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
407 sal_uInt16 nRet = 0;
408 if( nColorId >= EXC_PAL_INDEXBASE )
409 nRet = static_cast< sal_uInt16 >( nColorId & ~EXC_PAL_INDEXBASE );
410 else if( nColorId < maColorIdDataVec.size() )
411 nRet = GetXclIndex( maColorIdDataVec[ nColorId ].mnIndex );
412 return nRet;
415 void XclExpPaletteImpl::GetMixedColors(
416 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
417 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
419 rnXclForeIx = GetColorIndex( nForeColorId );
420 rnXclBackIx = GetColorIndex( nBackColorId );
421 if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
422 return;
424 // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
426 sal_uInt32 nIndex1, nIndex2;
427 Color aForeColor( GetOriginalColor( nForeColorId ) );
428 sal_Int32 nFirstDist = GetNearPaletteColors( nIndex1, nIndex2, aForeColor );
429 if( (nIndex1 >= maPalette.size()) || (nIndex2 >= maPalette.size()) )
430 return;
432 Color aColorArr[ 5 ];
433 aColorArr[ 0 ] = maPalette[ nIndex1 ].maColor;
434 aColorArr[ 4 ] = maPalette[ nIndex2 ].maColor;
435 lclSetMixedColor( aColorArr[ 2 ], aColorArr[ 0 ], aColorArr[ 4 ] );
436 lclSetMixedColor( aColorArr[ 1 ], aColorArr[ 0 ], aColorArr[ 2 ] );
437 lclSetMixedColor( aColorArr[ 3 ], aColorArr[ 2 ], aColorArr[ 4 ] );
439 sal_Int32 nMinDist = nFirstDist;
440 sal_uInt32 nMinIndex = 0;
441 for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
443 sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
444 if( nDist < nMinDist )
446 nMinDist = nDist;
447 nMinIndex = nCnt;
450 rnXclForeIx = GetXclIndex( nIndex1 );
451 rnXclBackIx = GetXclIndex( nIndex2 );
452 if( nMinDist < nFirstDist )
454 switch( nMinIndex )
456 case 1: rnXclPattern = EXC_PATT_75_PERC; break;
457 case 2: rnXclPattern = EXC_PATT_50_PERC; break;
458 case 3: rnXclPattern = EXC_PATT_25_PERC; break;
463 Color XclExpPaletteImpl::GetColor( sal_uInt16 nXclIndex ) const
465 if( nXclIndex >= EXC_COLOR_USEROFFSET )
467 sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
468 if( nIdx < maPalette.size() )
469 return maPalette[ nIdx ].maColor;
471 return mrDefPal.GetDefColor( nXclIndex );
474 bool XclExpPaletteImpl::IsDefaultPalette() const
476 bool bDefault = true;
477 for( sal_uInt32 nIdx = 0, nSize = static_cast< sal_uInt32 >( maPalette.size() ); bDefault && (nIdx < nSize); ++nIdx )
478 bDefault = maPalette[ nIdx ].maColor == mrDefPal.GetDefColor( GetXclIndex( nIdx ) );
479 return bDefault;
482 void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
484 rStrm << static_cast< sal_uInt16 >( maPalette.size() );
485 for( const auto& rColor : maPalette )
486 rStrm << rColor.maColor;
489 void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
491 if( maPalette.empty() )
492 return;
494 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
495 rStyleSheet->startElement(XML_colors);
496 rStyleSheet->startElement(XML_indexedColors);
497 for( const auto& rColor : maPalette )
498 rStyleSheet->singleElement(XML_rgbColor, XML_rgb, XclXmlUtils::ToOString(rColor.maColor));
499 rStyleSheet->endElement( XML_indexedColors );
500 rStyleSheet->endElement( XML_colors );
503 const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
505 if( nColorId < maColorIdDataVec.size() )
506 return maColorIdDataVec[ nColorId ].maColor;
507 return maPalette[ 0 ].maColor;
510 XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
512 rnIndex = 0;
514 if (mxColorList->empty())
515 return nullptr;
517 XclListColor* pEntry = nullptr;
519 // search optimization for equal-colored objects occurring repeatedly
520 if (mnLastIdx < mxColorList->size())
522 pEntry = (*mxColorList)[mnLastIdx].get();
523 if( pEntry->GetColor() == rColor )
525 rnIndex = mnLastIdx;
526 return pEntry;
530 // binary search for color
531 sal_uInt32 nBegIdx = 0;
532 sal_uInt32 nEndIdx = mxColorList->size();
533 bool bFound = false;
534 while( !bFound && (nBegIdx < nEndIdx) )
536 rnIndex = (nBegIdx + nEndIdx) / 2;
537 pEntry = (*mxColorList)[rnIndex].get();
538 bFound = pEntry->GetColor() == rColor;
539 if( !bFound )
541 if( pEntry->GetColor() < rColor )
542 nBegIdx = rnIndex + 1;
543 else
544 nEndIdx = rnIndex;
548 // not found - use end of range as new insertion position
549 if( !bFound )
550 rnIndex = nEndIdx;
552 mnLastIdx = rnIndex;
553 return pEntry;
556 XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
558 XclListColor* pEntry = new XclListColor( rColor, mxColorList->size() );
559 mxColorList->insert(mxColorList->begin() + nIndex, std::unique_ptr<XclListColor>(pEntry));
560 return pEntry;
563 void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
565 /* Fast palette reduction - in each call of this function one RGB component
566 of each color is reduced to a lower number of distinct values.
567 Pass 0: Blue is reduced to 128 distinct values.
568 Pass 1: Red is reduced to 128 distinct values.
569 Pass 2: Green is reduced to 128 distinct values.
570 Pass 3: Blue is reduced to 64 distinct values.
571 Pass 4: Red is reduced to 64 distinct values.
572 Pass 5: Green is reduced to 64 distinct values.
573 And so on...
576 XclListColorListRef xOldList = mxColorList;
577 mxColorList = std::make_shared<XclListColorList>();
579 // maps old list indexes to new list indexes, used to update maColorIdDataVec
580 ScfUInt32Vec aListIndexMap;
581 aListIndexMap.reserve( xOldList->size() );
583 // preparations
584 sal_uInt8 nR, nG, nB;
585 sal_uInt8& rnComp = ((nPass % 3 == 0) ? nB : ((nPass % 3 == 1) ? nR : nG));
586 nPass /= 3;
587 OSL_ENSURE( nPass < 7, "XclExpPaletteImpl::RawReducePalette - reduction not terminated" );
589 static const sal_uInt8 spnFactor2[] = { 0x81, 0x82, 0x84, 0x88, 0x92, 0xAA, 0xFF };
590 sal_uInt8 nFactor1 = static_cast< sal_uInt8 >( 0x02 << nPass );
591 sal_uInt8 nFactor2 = spnFactor2[ nPass ];
592 sal_uInt8 nFactor3 = static_cast< sal_uInt8 >( 0x40 >> nPass );
594 // process each color in the old color list
595 for(const std::unique_ptr<XclListColor> & pOldColor : *xOldList)
597 // get the old list entry
598 const XclListColor* pOldEntry = pOldColor.get();
599 nR = pOldEntry->GetColor().GetRed();
600 nG = pOldEntry->GetColor().GetGreen();
601 nB = pOldEntry->GetColor().GetBlue();
603 /* Calculate the new RGB component (rnComp points to one of nR, nG, nB).
604 Using integer arithmetic with its rounding errors, the results of
605 this calculation are always exactly in the range 0x00 to 0xFF
606 (simply cutting the lower bits would darken the colors slightly). */
607 sal_uInt32 nNewComp = rnComp;
608 nNewComp /= nFactor1;
609 nNewComp *= nFactor2;
610 nNewComp /= nFactor3;
611 rnComp = static_cast< sal_uInt8 >( nNewComp );
612 Color aNewColor( nR, nG, nB );
614 // find or insert the new color
615 sal_uInt32 nFoundIdx = 0;
616 XclListColor* pNewEntry = SearchListEntry( aNewColor, nFoundIdx );
617 if( !pNewEntry || (pNewEntry->GetColor() != aNewColor) )
618 pNewEntry = CreateListEntry( aNewColor, nFoundIdx );
619 pNewEntry->AddWeighting( pOldEntry->GetWeighting() );
620 aListIndexMap.push_back( nFoundIdx );
623 // update color ID data map (maps color IDs to color list indexes), replace old by new list indexes
624 for( auto& rColorIdData : maColorIdDataVec )
625 rColorIdData.mnIndex = aListIndexMap[ rColorIdData.mnIndex ];
628 void XclExpPaletteImpl::ReduceLeastUsedColor()
630 // find a list color to remove
631 sal_uInt32 nRemove = GetLeastUsedListColor();
632 // find its nearest neighbor
633 sal_uInt32 nKeep = GetNearestListColor( nRemove );
635 // merge both colors to one color, remove one color from list
636 XclListColor* pKeepEntry = mxColorList->at(nKeep).get();
637 XclListColor* pRemoveEntry = mxColorList->at(nRemove).get();
638 if( !(pKeepEntry && pRemoveEntry) )
639 return;
641 // merge both colors (if pKeepEntry is a base color, it will not change)
642 pKeepEntry->Merge( *pRemoveEntry );
643 // remove the less used color, adjust nKeep index if kept color follows removed color
644 XclListColorList::iterator itr = mxColorList->begin();
645 ::std::advance(itr, nRemove);
646 mxColorList->erase(itr);
647 if( nKeep > nRemove ) --nKeep;
649 // recalculate color ID data map (maps color IDs to color list indexes)
650 for( auto& rColorIdData : maColorIdDataVec )
652 if( rColorIdData.mnIndex > nRemove )
653 --rColorIdData.mnIndex;
654 else if( rColorIdData.mnIndex == nRemove )
655 rColorIdData.mnIndex = nKeep;
659 sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
661 sal_uInt32 nFound = 0;
662 sal_uInt32 nMinW = SAL_MAX_UINT32;
664 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
666 XclListColor& rEntry = *mxColorList->at( nIdx );
667 // ignore the base colors
668 if( !rEntry.IsBaseColor() && (rEntry.GetWeighting() < nMinW) )
670 nFound = nIdx;
671 nMinW = rEntry.GetWeighting();
674 return nFound;
677 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
679 sal_uInt32 nFound = 0;
680 sal_Int32 nMinD = SAL_MAX_INT32;
682 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
684 if( nIdx != nIgnore )
686 if( XclListColor* pEntry = mxColorList->at(nIdx).get() )
688 sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
689 if( nDist < nMinD )
691 nFound = nIdx;
692 nMinD = nDist;
697 return nFound;
700 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
702 if (nIndex >= mxColorList->size())
703 return 0;
704 XclListColor* pEntry = mxColorList->at(nIndex).get();
705 return GetNearestListColor( pEntry->GetColor(), nIndex );
708 sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
709 sal_uInt32& rnIndex, const Color& rColor ) const
711 rnIndex = 0;
712 sal_Int32 nDist = SAL_MAX_INT32;
714 sal_uInt32 nPaletteIndex = 0;
715 for( const auto& rPaletteColor : maPalette )
717 if( !rPaletteColor.mbUsed )
719 sal_Int32 nCurrDist = lclGetColorDistance( rColor, rPaletteColor.maColor );
720 if( nCurrDist < nDist )
722 rnIndex = nPaletteIndex;
723 nDist = nCurrDist;
726 ++nPaletteIndex;
728 return nDist;
731 sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
732 sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
734 rnFirst = rnSecond = 0;
735 sal_Int32 nDist1 = SAL_MAX_INT32;
736 sal_Int32 nDist2 = SAL_MAX_INT32;
738 sal_uInt32 nPaletteIndex = 0;
739 for( const auto& rPaletteColor : maPalette )
741 sal_Int32 nCurrDist = lclGetColorDistance( rColor, rPaletteColor.maColor );
742 if( nCurrDist < nDist1 )
744 rnSecond = rnFirst;
745 nDist2 = nDist1;
746 rnFirst = nPaletteIndex;
747 nDist1 = nCurrDist;
749 else if( nCurrDist < nDist2 )
751 rnSecond = nPaletteIndex;
752 nDist2 = nCurrDist;
754 ++nPaletteIndex;
756 return nDist1;
759 XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
760 XclDefaultPalette( rRoot ),
761 XclExpRecord( EXC_ID_PALETTE )
763 mxImpl = std::make_shared<XclExpPaletteImpl>( *this );
764 SetRecSize( GetColorCount() * 4 + 2 );
767 XclExpPalette::~XclExpPalette()
771 sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
773 return mxImpl->InsertColor( rColor, eType, nAutoDefault );
776 sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
778 return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
781 void XclExpPalette::Finalize()
783 mxImpl->Finalize();
786 sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
788 return mxImpl->GetColorIndex( nColorId );
791 void XclExpPalette::GetMixedColors(
792 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
793 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
795 return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
798 Color XclExpPalette::GetColor( sal_uInt16 nXclIndex ) const
800 return mxImpl->GetColor( nXclIndex );
803 void XclExpPalette::Save( XclExpStream& rStrm )
805 if( !mxImpl->IsDefaultPalette() )
806 XclExpRecord::Save( rStrm );
809 void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
811 if( !mxImpl->IsDefaultPalette() )
812 mxImpl->SaveXml( rStrm );
815 void XclExpPalette::WriteBody( XclExpStream& rStrm )
817 mxImpl->WriteBody( rStrm );
820 // FONT record - font information =============================================
822 namespace {
824 typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
826 sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
827 const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
829 if( ScfTools::CheckItem( rItemSet, rWAS1.first, false ) ) return rWAS1.second;
830 if( ScfTools::CheckItem( rItemSet, rWAS2.first, false ) ) return rWAS2.second;
831 if( ScfTools::CheckItem( rItemSet, rWAS3.first, false ) ) return rWAS3.second;
832 return 0;
835 } // namespace
837 sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
839 namespace ApiScriptType = css::i18n::ScriptType;
841 /* #i17050# #i107170# We need to determine which font items are set in the
842 item set, and which script type we should prefer according to the
843 current languages and locales. */
845 static const WhichAndScript WAS_LATIN( ATTR_FONT, css::i18n::ScriptType::LATIN );
846 static const WhichAndScript WAS_ASIAN( ATTR_CJK_FONT, css::i18n::ScriptType::ASIAN );
847 static const WhichAndScript WAS_CMPLX( ATTR_CTL_FONT, css::i18n::ScriptType::COMPLEX );
849 /* do not let a font from a parent style override an explicit
850 cell font. */
852 sal_Int16 nDefScript = rRoot.GetDefApiScript();
853 sal_Int16 nScript = 0;
854 const SfxItemSet* pCurrSet = &rItemSet;
856 while( (nScript == 0) && pCurrSet )
858 switch( nDefScript )
860 case ApiScriptType::LATIN:
861 nScript = lclCheckFontItems( *pCurrSet, WAS_LATIN, WAS_CMPLX, WAS_ASIAN );
862 break;
863 case ApiScriptType::ASIAN:
864 nScript = lclCheckFontItems( *pCurrSet, WAS_ASIAN, WAS_CMPLX, WAS_LATIN );
865 break;
866 case ApiScriptType::COMPLEX:
867 nScript = lclCheckFontItems( *pCurrSet, WAS_CMPLX, WAS_ASIAN, WAS_LATIN );
868 break;
869 default:
870 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
871 nScript = ApiScriptType::LATIN;
873 pCurrSet = pCurrSet->GetParent();
876 if (nScript == 0)
877 nScript = nDefScript;
879 if (nScript == 0)
881 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
882 nScript = ApiScriptType::LATIN;
885 return nScript;
888 vcl::Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
890 // if WEAK is passed, guess script type from existing items in the item set
891 if( nScript == css::i18n::ScriptType::WEAK )
892 nScript = GetFirstUsedScript( rRoot, rItemSet );
894 // convert to core script type constants
895 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
897 // fill the font object
898 vcl::Font aFont;
899 ScPatternAttr::fillFontOnly(aFont, rItemSet, nullptr, nullptr, nullptr, nScScript);
900 return aFont;
903 ScDxfFont XclExpFontHelper::GetDxfFontFromItemSet(const XclExpRoot& rRoot, const SfxItemSet& rItemSet)
905 sal_Int16 nScript = GetFirstUsedScript(rRoot, rItemSet);
907 // convert to core script type constants
908 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
909 return ScPatternAttr::GetDxfFont(rItemSet, nScScript);
912 bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
914 static const sal_uInt16 pnCommonIds[] = {
915 ATTR_FONT_UNDERLINE, ATTR_FONT_CROSSEDOUT, ATTR_FONT_CONTOUR,
916 ATTR_FONT_SHADOWED, ATTR_FONT_COLOR, ATTR_FONT_LANGUAGE, 0 };
917 static const sal_uInt16 pnLatinIds[] = {
918 ATTR_FONT, ATTR_FONT_HEIGHT, ATTR_FONT_WEIGHT, ATTR_FONT_POSTURE, 0 };
919 static const sal_uInt16 pnAsianIds[] = {
920 ATTR_CJK_FONT, ATTR_CJK_FONT_HEIGHT, ATTR_CJK_FONT_WEIGHT, ATTR_CJK_FONT_POSTURE, 0 };
921 static const sal_uInt16 pnComplexIds[] = {
922 ATTR_CTL_FONT, ATTR_CTL_FONT_HEIGHT, ATTR_CTL_FONT_WEIGHT, ATTR_CTL_FONT_POSTURE, 0 };
924 bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
925 if( !bUsed )
927 namespace ApiScriptType = css::i18n::ScriptType;
928 // if WEAK is passed, guess script type from existing items in the item set
929 if( nScript == ApiScriptType::WEAK )
930 nScript = GetFirstUsedScript( rRoot, rItemSet );
931 // check the correct items
932 switch( nScript )
934 case ApiScriptType::LATIN: bUsed = ScfTools::CheckItems( rItemSet, pnLatinIds, bDeep ); break;
935 case ApiScriptType::ASIAN: bUsed = ScfTools::CheckItems( rItemSet, pnAsianIds, bDeep ); break;
936 case ApiScriptType::COMPLEX: bUsed = ScfTools::CheckItems( rItemSet, pnComplexIds, bDeep ); break;
937 default: OSL_FAIL( "XclExpFontHelper::CheckItems - unknown script type" );
940 return bUsed;
943 namespace {
945 std::size_t lclCalcHash( const XclFontData& rFontData )
947 std::size_t seed = 0;
948 o3tl::hash_combine(seed, rFontData.maName);
949 o3tl::hash_combine(seed, rFontData.maComplexColor);
950 o3tl::hash_combine(seed, rFontData.mnWeight);
951 o3tl::hash_combine(seed, rFontData.mnCharSet);
952 o3tl::hash_combine(seed, rFontData.mnFamily);
953 o3tl::hash_combine(seed, rFontData.mnHeight);
954 o3tl::hash_combine(seed, rFontData.mnUnderline);
955 o3tl::hash_combine(seed, rFontData.mnEscapem);
956 o3tl::hash_combine(seed, rFontData.mbItalic);
957 o3tl::hash_combine(seed, rFontData.mbStrikeout);
958 o3tl::hash_combine(seed, rFontData.mbOutline);
959 o3tl::hash_combine(seed, rFontData.mbShadow);
960 return seed;
963 } // namespace
965 XclExpFont::XclExpFont( const XclExpRoot& rRoot,
966 const XclFontData& rFontData, XclExpColorType eColorType ) :
967 XclExpRecord( EXC_ID2_FONT, 14 ),
968 XclExpRoot( rRoot ),
969 maData( rFontData )
971 // insert font color into palette
972 mnColorId = rRoot.GetPalette().InsertColor(rFontData.maComplexColor.getFinalColor(), eColorType, EXC_COLOR_FONTAUTO);
973 // hash value for faster comparison
974 mnHash = lclCalcHash( maData );
975 // record size
976 sal_Int32 nStrLen = maData.maName.getLength();
977 SetRecSize( ((GetBiff() == EXC_BIFF8) ? (nStrLen * 2 + 1) : nStrLen) + 15 );
980 bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
982 return (mnHash == nHash) && (maData == rFontData);
985 void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
987 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
988 rStyleSheet->startElement(XML_font);
989 XclXmlUtils::WriteFontData( rStyleSheet, maData, XML_name );
990 // OOXTODO: XML_scheme; //scheme/@val values: "major", "minor", "none"
991 rStyleSheet->endElement( XML_font );
994 // private --------------------------------------------------------------------
996 void XclExpFont::WriteBody( XclExpStream& rStrm )
998 sal_uInt16 nAttr = EXC_FONTATTR_NONE;
999 ::set_flag( nAttr, EXC_FONTATTR_ITALIC, maData.mbItalic );
1000 if( maData.mnUnderline > 0 )
1001 ::set_flag( nAttr, EXC_FONTATTR_UNDERLINE, true );
1002 ::set_flag( nAttr, EXC_FONTATTR_STRIKEOUT, maData.mbStrikeout );
1003 ::set_flag( nAttr, EXC_FONTATTR_OUTLINE, maData.mbOutline );
1004 ::set_flag( nAttr, EXC_FONTATTR_SHADOW, maData.mbShadow );
1006 OSL_ENSURE( maData.maName.getLength() < 256, "XclExpFont::WriteBody - font name too long" );
1007 XclExpString aFontName;
1008 if( GetBiff() <= EXC_BIFF5 )
1009 aFontName.AssignByte( maData.maName, GetTextEncoding(), XclStrFlags::EightBitLength );
1010 else
1011 aFontName.Assign( maData.maName, XclStrFlags::ForceUnicode | XclStrFlags::EightBitLength );
1013 rStrm << maData.mnHeight
1014 << nAttr
1015 << GetPalette().GetColorIndex( mnColorId )
1016 << maData.mnWeight
1017 << maData.mnEscapem
1018 << maData.mnUnderline
1019 << maData.mnFamily
1020 << maData.mnCharSet
1021 << sal_uInt8( 0 )
1022 << aFontName;
1025 XclExpDxfFont::XclExpDxfFont(const XclExpRoot& rRoot,
1026 const SfxItemSet& rItemSet):
1027 XclExpRoot(rRoot)
1029 maDxfData = XclExpFontHelper::GetDxfFontFromItemSet(rRoot, rItemSet);
1032 namespace {
1034 const char* getUnderlineOOXValue(FontLineStyle eUnderline)
1036 switch (eUnderline)
1038 case LINESTYLE_NONE:
1039 case LINESTYLE_DONTKNOW:
1040 return "none";
1041 case LINESTYLE_DOUBLE:
1042 case LINESTYLE_DOUBLEWAVE:
1043 return "double";
1044 default:
1045 return "single";
1049 const char* getFontFamilyOOXValue(FontFamily eValue)
1051 switch (eValue)
1053 case FAMILY_DONTKNOW:
1054 return "0";
1055 case FAMILY_SWISS:
1056 case FAMILY_SYSTEM:
1057 return "2";
1058 case FAMILY_ROMAN:
1059 return "1";
1060 case FAMILY_SCRIPT:
1061 return "4";
1062 case FAMILY_MODERN:
1063 return "3";
1064 case FAMILY_DECORATIVE:
1065 return "5";
1066 default:
1067 return "0";
1073 void XclExpDxfFont::SaveXml(XclExpXmlStream& rStrm)
1075 if (maDxfData.isEmpty())
1076 return;
1078 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1079 rStyleSheet->startElement(XML_font);
1081 if (maDxfData.pFontAttr)
1083 OUString aFontName = (*maDxfData.pFontAttr)->GetFamilyName();
1085 aFontName = XclTools::GetXclFontName(aFontName);
1086 if (!aFontName.isEmpty())
1088 rStyleSheet->singleElement(XML_name, XML_val, aFontName);
1091 rtl_TextEncoding eTextEnc = (*maDxfData.pFontAttr)->GetCharSet();
1092 sal_uInt8 nExcelCharSet = rtl_getBestWindowsCharsetFromTextEncoding(eTextEnc);
1093 if (nExcelCharSet)
1095 rStyleSheet->singleElement(XML_charset, XML_val, OString::number(nExcelCharSet));
1098 FontFamily eFamily = (*maDxfData.pFontAttr)->GetFamily();
1099 const char* pVal = getFontFamilyOOXValue(eFamily);
1100 if (pVal)
1102 rStyleSheet->singleElement(XML_family, XML_val, pVal);
1106 if (maDxfData.eWeight)
1108 rStyleSheet->singleElement(XML_b,
1109 XML_val, ToPsz10(*maDxfData.eWeight != WEIGHT_NORMAL));
1112 if (maDxfData.eItalic)
1114 bool bItalic = (*maDxfData.eItalic == ITALIC_OBLIQUE) || (*maDxfData.eItalic == ITALIC_NORMAL);
1115 rStyleSheet->singleElement(XML_i, XML_val, ToPsz10(bItalic));
1118 if (maDxfData.eStrike)
1120 bool bStrikeout =
1121 (*maDxfData.eStrike == STRIKEOUT_SINGLE) || (*maDxfData.eStrike == STRIKEOUT_DOUBLE) ||
1122 (*maDxfData.eStrike == STRIKEOUT_BOLD) || (*maDxfData.eStrike == STRIKEOUT_SLASH) ||
1123 (*maDxfData.eStrike == STRIKEOUT_X);
1125 rStyleSheet->singleElement(XML_strike, XML_val, ToPsz10(bStrikeout));
1128 if (maDxfData.bOutline)
1130 rStyleSheet->singleElement(XML_outline, XML_val, ToPsz10(*maDxfData.bOutline));
1133 if (maDxfData.bShadow)
1135 rStyleSheet->singleElement(XML_shadow, XML_val, ToPsz10(*maDxfData.bShadow));
1138 if (maDxfData.aColor)
1140 rStyleSheet->singleElement(XML_color,
1141 XML_rgb, XclXmlUtils::ToOString(*maDxfData.aColor));
1144 if (maDxfData.nFontHeight)
1146 rStyleSheet->singleElement(XML_sz,
1147 XML_val, OString::number(*maDxfData.nFontHeight/20));
1150 if (maDxfData.eUnder)
1152 const char* pVal = getUnderlineOOXValue(*maDxfData.eUnder);
1153 rStyleSheet->singleElement(XML_u, XML_val, pVal);
1156 rStyleSheet->endElement(XML_font);
1159 XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
1160 XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
1164 bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
1166 return false;
1169 void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
1171 // do nothing
1174 XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
1175 XclExpRoot( rRoot ),
1176 mnXclMaxSize( 0 )
1178 switch( GetBiff() )
1180 case EXC_BIFF4: mnXclMaxSize = EXC_FONT_MAXCOUNT4; break;
1181 case EXC_BIFF5: mnXclMaxSize = EXC_FONT_MAXCOUNT5; break;
1182 case EXC_BIFF8: mnXclMaxSize = EXC_FONT_MAXCOUNT8; break;
1183 default: DBG_ERROR_BIFF();
1185 InitDefaultFonts();
1188 const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
1190 return maFontList.GetRecord( nXclFont );
1193 const XclFontData& XclExpFontBuffer::GetAppFontData() const
1195 return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
1198 sal_uInt16 XclExpFontBuffer::Insert(
1199 const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
1201 if( bAppFont )
1203 XclExpFontRef xFont = new XclExpFont( GetRoot(), rFontData, eColorType );
1204 maFontList.ReplaceRecord( xFont, EXC_FONT_APP );
1205 // set width of '0' character for column width export
1206 SetCharWidth( xFont->GetFontData() );
1207 return EXC_FONT_APP;
1210 size_t nPos = Find( rFontData );
1211 if( nPos == EXC_FONTLIST_NOTFOUND )
1213 // not found in buffer - create new font
1214 size_t nSize = maFontList.GetSize();
1215 if( nSize < mnXclMaxSize )
1217 // possible to insert
1218 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1219 nPos = nSize; // old size is last position now
1221 else
1223 // buffer is full - ignore new font, use default font
1224 nPos = EXC_FONT_APP;
1227 return static_cast< sal_uInt16 >( nPos );
1230 sal_uInt16 XclExpFontBuffer::Insert(const SvxFont& rFont, model::ComplexColor const& rComplexColor, XclExpColorType eColorType )
1232 return Insert(XclFontData(rFont, rComplexColor), eColorType);
1235 sal_uInt16 XclExpFontBuffer::Insert(const SfxItemSet& rItemSet, sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1237 // #i17050# script type now provided by caller
1238 vcl::Font aFont = XclExpFontHelper::GetFontFromItemSet(GetRoot(), rItemSet, nScript);
1239 model::ComplexColor aComplexColor;
1240 ScPatternAttr::fillColor(aComplexColor, rItemSet, ScAutoFontColorMode::Raw);
1241 return Insert(XclFontData(aFont, aComplexColor), eColorType, bAppFont );
1244 void XclExpFontBuffer::Save( XclExpStream& rStrm )
1246 maFontList.Save( rStrm );
1249 void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
1251 if( maFontList.IsEmpty() )
1252 return;
1254 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1255 rStyleSheet->startElement(XML_fonts, XML_count, OString::number(maFontList.GetSize()));
1257 maFontList.SaveXml( rStrm );
1259 rStyleSheet->endElement( XML_fonts );
1262 // private --------------------------------------------------------------------
1264 void XclExpFontBuffer::InitDefaultFonts()
1266 XclFontData aFontData;
1267 aFontData.maName = "Arial";
1268 aFontData.SetScFamily( FAMILY_DONTKNOW );
1269 aFontData.SetFontEncoding( ScfTools::GetSystemTextEncoding() );
1270 aFontData.SetScHeight( 200 ); // 200 twips = 10 pt
1271 aFontData.SetScWeight( WEIGHT_NORMAL );
1273 switch( GetBiff() )
1275 case EXC_BIFF5:
1277 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1278 aFontData.SetScWeight( WEIGHT_BOLD );
1279 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1280 aFontData.SetScWeight( WEIGHT_NORMAL );
1281 aFontData.SetScPosture( ITALIC_NORMAL );
1282 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1283 aFontData.SetScWeight( WEIGHT_BOLD );
1284 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1285 // the blind font with index 4
1286 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1287 // already add the first user defined font (Excel does it too)
1288 aFontData.SetScWeight( WEIGHT_NORMAL );
1289 aFontData.SetScPosture( ITALIC_NONE );
1290 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1292 break;
1293 case EXC_BIFF8:
1295 XclExpFontRef xFont = new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT );
1296 maFontList.AppendRecord( xFont );
1297 maFontList.AppendRecord( xFont );
1298 maFontList.AppendRecord( xFont );
1299 maFontList.AppendRecord( xFont );
1300 if( GetOutput() == EXC_OUTPUT_BINARY )
1301 // the blind font with index 4
1302 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1304 break;
1305 default:
1306 DBG_ERROR_BIFF();
1310 size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
1312 sal_uInt32 nHash = lclCalcHash( rFontData );
1313 for( size_t nPos = 0, nSize = maFontList.GetSize(); nPos < nSize; ++nPos )
1314 if( maFontList.GetRecord( nPos )->Equals( rFontData, nHash ) )
1315 return nPos;
1316 return EXC_FONTLIST_NOTFOUND;
1319 // FORMAT record - number formats =============================================
1321 namespace {
1323 /** Predicate for search algorithm. */
1324 struct XclExpNumFmtPred
1326 sal_uInt32 mnScNumFmt;
1327 explicit XclExpNumFmtPred( sal_uInt32 nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
1328 bool operator()( const XclExpNumFmt& rFormat ) const
1329 { return rFormat.mnScNumFmt == mnScNumFmt; }
1334 void XclExpNumFmt::SaveXml( XclExpXmlStream& rStrm )
1336 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1337 rStyleSheet->singleElement( XML_numFmt,
1338 XML_numFmtId, OString::number(mnXclNumFmt),
1339 XML_formatCode, maNumFmtString );
1342 XclExpNumFmtBuffer::XclExpNumFmtBuffer( const XclExpRoot& rRoot ) :
1343 XclExpRoot( rRoot ),
1344 mxFormatter( new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ) ),
1345 mpKeywordTable( new NfKeywordTable ),
1346 mnStdFmt( GetFormatter().GetStandardIndex( ScGlobal::eLnge ) )
1348 switch( GetBiff() )
1350 case EXC_BIFF5: mnXclOffset = EXC_FORMAT_OFFSET5; break;
1351 case EXC_BIFF8: mnXclOffset = EXC_FORMAT_OFFSET8; break;
1352 default: mnXclOffset = 0; DBG_ERROR_BIFF();
1355 mxFormatter->FillKeywordTableForExcel( *mpKeywordTable );
1358 XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
1362 sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uInt32 nScNumFmt )
1364 XclExpNumFmtVec::const_iterator aIt =
1365 ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
1366 if( aIt != maFormatMap.end() )
1367 return aIt->mnXclNumFmt;
1369 size_t nSize = maFormatMap.size();
1370 if( nSize < o3tl::make_unsigned( 0xFFFF - mnXclOffset ) )
1372 sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
1373 maFormatMap.emplace_back( nScNumFmt, nXclNumFmt, GetFormatCode( nScNumFmt ) );
1374 return nXclNumFmt;
1377 return 0;
1380 void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
1382 for( const auto& rEntry : maFormatMap )
1383 WriteFormatRecord( rStrm, rEntry );
1386 void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
1388 if( maFormatMap.empty() )
1389 return;
1391 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1392 rStyleSheet->startElement(XML_numFmts, XML_count, OString::number(maFormatMap.size()));
1393 for( auto& rEntry : maFormatMap )
1395 rEntry.SaveXml( rStrm );
1397 rStyleSheet->endElement( XML_numFmts );
1400 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const OUString& rFormatStr )
1402 XclExpString aExpStr;
1403 if( GetBiff() <= EXC_BIFF5 )
1404 aExpStr.AssignByte( rFormatStr, GetTextEncoding(), XclStrFlags::EightBitLength );
1405 else
1406 aExpStr.Assign( rFormatStr );
1408 rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
1409 rStrm << nXclNumFmt << aExpStr;
1410 rStrm.EndRecord();
1413 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
1415 WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat.mnScNumFmt ) );
1418 namespace {
1420 OUString GetNumberFormatCode(const XclRoot& rRoot, const sal_uInt32 nScNumFmt, SvNumberFormatter* pFormatter, const NfKeywordTable* pKeywordTable)
1422 return rRoot.GetFormatter().GetFormatStringForExcel( nScNumFmt, *pKeywordTable, *pFormatter);
1427 OUString XclExpNumFmtBuffer::GetFormatCode( sal_uInt32 nScNumFmt )
1429 return GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() );
1432 // XF, STYLE record - Cell formatting =========================================
1434 bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
1436 const ScProtectionAttr& rProtItem = rItemSet.Get( ATTR_PROTECTION );
1437 mbLocked = rProtItem.GetProtection();
1438 mbHidden = rProtItem.GetHideFormula() || rProtItem.GetHideCell();
1439 return ScfTools::CheckItem( rItemSet, ATTR_PROTECTION, bStyle );
1442 void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
1444 ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
1445 ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
1448 void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
1450 rStrm.GetCurrentStream()->singleElement( XML_protection,
1451 XML_locked, ToPsz( mbLocked ),
1452 XML_hidden, ToPsz( mbHidden ) );
1455 bool XclExpCellAlign::FillFromItemSet(const XclRoot& rRoot, const SfxItemSet& rItemSet,
1456 bool bForceLineBreak, XclBiff eBiff, bool bStyle)
1458 bool bUsed = false;
1459 SvxCellHorJustify eHorAlign = rItemSet.Get( ATTR_HOR_JUSTIFY ).GetValue();
1460 SvxCellVerJustify eVerAlign = rItemSet.Get( ATTR_VER_JUSTIFY ).GetValue();
1462 switch( eBiff )
1464 case EXC_BIFF8: // attributes new in BIFF8
1466 // text indent
1467 tools::Long nTmpIndent = rItemSet.Get( ATTR_INDENT ).GetValue(); // already in twips
1468 tools::Long nSpaceWidth = rRoot.GetSpaceWidth();
1469 sal_Int32 nIndent = static_cast<double>(nTmpIndent) / (3.0 * nSpaceWidth) + 0.5;
1470 mnIndent = limit_cast< sal_uInt8 >( nIndent, 0, 15 );
1471 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_INDENT, bStyle );
1473 // shrink to fit
1474 mbShrink = rItemSet.Get( ATTR_SHRINKTOFIT ).GetValue();
1475 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
1477 // CTL text direction
1478 SetScFrameDir( rItemSet.Get( ATTR_WRITINGDIR ).GetValue() );
1479 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
1481 [[fallthrough]];
1484 case EXC_BIFF5: // attributes new in BIFF5
1485 case EXC_BIFF4: // attributes new in BIFF4
1487 // vertical alignment
1488 SetScVerAlign( eVerAlign );
1489 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
1491 // stacked/rotation
1492 bool bStacked = rItemSet.Get( ATTR_STACKED ).GetValue();
1493 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
1494 if( bStacked )
1496 mnRotation = EXC_ROT_STACKED;
1498 else
1500 // rotation
1501 Degree100 nScRot = rItemSet.Get( ATTR_ROTATE_VALUE ).GetValue();
1502 mnRotation = XclTools::GetXclRotation( nScRot );
1503 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_ROTATE_VALUE, bStyle );
1505 mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
1507 [[fallthrough]];
1510 case EXC_BIFF3: // attributes new in BIFF3
1512 // text wrap
1513 mbLineBreak = bForceLineBreak || rItemSet.Get( ATTR_LINEBREAK ).GetValue();
1514 bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
1516 [[fallthrough]];
1519 case EXC_BIFF2: // attributes new in BIFF2
1521 // horizontal alignment
1522 SetScHorAlign( eHorAlign );
1523 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
1526 break;
1527 default: DBG_ERROR_BIFF();
1530 if (eBiff == EXC_BIFF8)
1532 // Adjust for distributed alignments.
1533 if (eHorAlign == SvxCellHorJustify::Block)
1535 SvxCellJustifyMethod eHorJustMethod =
1536 rItemSet.GetItem<SvxJustifyMethodItem>(ATTR_HOR_JUSTIFY_METHOD)->GetValue();
1537 if (eHorJustMethod == SvxCellJustifyMethod::Distribute)
1538 mnHorAlign = EXC_XF_HOR_DISTRIB;
1541 if (eVerAlign == SvxCellVerJustify::Block)
1543 SvxCellJustifyMethod eVerJustMethod =
1544 rItemSet.GetItem<SvxJustifyMethodItem>(ATTR_VER_JUSTIFY_METHOD)->GetValue();
1545 if (eVerJustMethod == SvxCellJustifyMethod::Distribute)
1546 mnVerAlign = EXC_XF_VER_DISTRIB;
1550 return bUsed;
1553 void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
1555 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1556 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1557 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1558 ::insert_value( rnAlign, mnOrient, 8, 2 );
1561 void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
1563 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1564 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1565 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1566 ::insert_value( rnAlign, mnRotation, 8, 8 );
1567 ::insert_value( rnMiscAttrib, mnIndent, 0, 4 );
1568 ::set_flag( rnMiscAttrib, EXC_XF8_SHRINK, mbShrink );
1569 ::insert_value( rnMiscAttrib, mnTextDir, 6, 2 );
1572 static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
1574 switch( nHorAlign )
1576 case EXC_XF_HOR_GENERAL: return "general";
1577 case EXC_XF_HOR_LEFT: return "left";
1578 case EXC_XF_HOR_CENTER: return "center";
1579 case EXC_XF_HOR_RIGHT: return "right";
1580 case EXC_XF_HOR_FILL: return "fill";
1581 case EXC_XF_HOR_JUSTIFY: return "justify";
1582 case EXC_XF_HOR_CENTER_AS: return "centerContinuous";
1583 case EXC_XF_HOR_DISTRIB: return "distributed";
1585 return "*unknown*";
1588 static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
1590 switch( nVerAlign )
1592 case EXC_XF_VER_TOP: return "top";
1593 case EXC_XF_VER_CENTER: return "center";
1594 case EXC_XF_VER_BOTTOM: return "bottom";
1595 case EXC_XF_VER_JUSTIFY: return "justify";
1596 case EXC_XF_VER_DISTRIB: return "distributed";
1598 return "*unknown*";
1601 void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
1603 rStrm.GetCurrentStream()->singleElement( XML_alignment,
1604 XML_horizontal, ToHorizontalAlignment( mnHorAlign ),
1605 XML_vertical, ToVerticalAlignment( mnVerAlign ),
1606 XML_textRotation, OString::number(mnRotation),
1607 XML_wrapText, ToPsz( mbLineBreak ),
1608 XML_indent, OString::number(mnIndent),
1609 // OOXTODO: XML_relativeIndent, mnIndent?
1610 // OOXTODO: XML_justifyLastLine,
1611 XML_shrinkToFit, ToPsz( mbShrink ),
1612 XML_readingOrder, sax_fastparser::UseIf(OString::number(mnTextDir), mnTextDir != EXC_XF_TEXTDIR_CONTEXT) );
1615 namespace {
1617 void lclGetBorderLine(
1618 sal_uInt8& rnXclLine, sal_uInt32& rnColorId, model::ComplexColor& rComplexColor,
1619 const ::editeng::SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
1621 // Document: sc/qa/unit/data/README.cellborders
1623 enum CalcLineIndex{Idx_None, Idx_Solid, Idx_Dotted, Idx_Dashed, Idx_FineDashed, Idx_DashDot, Idx_DashDotDot, Idx_DoubleThin, Idx_Last};
1624 enum ExcelWidthIndex{Width_Hair, Width_Thin, Width_Medium, Width_Thick, Width_Last};
1625 static sal_uInt8 Map_LineLO_toMS[Idx_Last][Width_Last] =
1627 // 0,05 - 0,74 0,75 - 1,49 1,50 - 2,49 2,50 - 9,00 Width Range [pt]
1628 // EXC_BORDER_HAIR EXC_BORDER_THIN EXC_BORDER_MEDIUM EXC_BORDER_THICK MS Width
1629 {EXC_LINE_NONE , EXC_LINE_NONE , EXC_LINE_NONE , EXC_LINE_NONE }, // 0 BorderLineStyle::NONE
1630 {EXC_LINE_HAIR , EXC_LINE_THIN , EXC_LINE_MEDIUM , EXC_LINE_THICK }, // 1 BorderLineStyle::SOLID
1631 {EXC_LINE_DOTTED , EXC_LINE_DOTTED , EXC_LINE_MEDIUM_SLANT_DASHDOT, EXC_LINE_MEDIUM_SLANT_DASHDOT}, // 2 BorderLineStyle::DOTTED
1632 {EXC_LINE_DOTTED , EXC_LINE_DASHED , EXC_LINE_MEDIUM_DASHED , EXC_LINE_MEDIUM_DASHED }, // 3 BorderLineStyle::DASHED
1633 {EXC_LINE_DASHED , EXC_LINE_DASHED , EXC_LINE_MEDIUM_SLANT_DASHDOT, EXC_LINE_MEDIUM_SLANT_DASHDOT}, // 4 BorderLineStyle::FINE_DASHED
1634 {EXC_LINE_DASHED , EXC_LINE_THIN_DASHDOT , EXC_LINE_MEDIUM_DASHDOT , EXC_LINE_MEDIUM_DASHDOT }, // 5 BorderLineStyle::DASH_DOT
1635 {EXC_LINE_DASHED , EXC_LINE_THIN_DASHDOTDOT , EXC_LINE_MEDIUM_DASHDOTDOT , EXC_LINE_MEDIUM_DASHDOTDOT }, // 6 BorderLineStyle::DASH_DOT_DOT
1636 {EXC_LINE_DOUBLE , EXC_LINE_DOUBLE , EXC_LINE_DOUBLE , EXC_LINE_DOUBLE } // 7 BorderLineStyle::DOUBLE_THIN
1637 }; // Line Name
1639 rnXclLine = EXC_LINE_NONE;
1640 if( pLine )
1642 sal_uInt16 nOuterWidth = pLine->GetOutWidth();
1643 ExcelWidthIndex nOuterWidthIndx;
1644 CalcLineIndex nStyleIndex;
1646 switch (pLine->GetBorderLineStyle())
1648 case SvxBorderLineStyle::NONE:
1649 nStyleIndex = Idx_None;
1650 break;
1651 case SvxBorderLineStyle::SOLID:
1652 nStyleIndex = Idx_Solid;
1653 break;
1654 case SvxBorderLineStyle::DOTTED:
1655 nStyleIndex = Idx_Dotted;
1656 break;
1657 case SvxBorderLineStyle::DASHED:
1658 nStyleIndex = Idx_Dashed;
1659 break;
1660 case SvxBorderLineStyle::FINE_DASHED:
1661 nStyleIndex = Idx_FineDashed;
1662 break;
1663 case SvxBorderLineStyle::DASH_DOT:
1664 nStyleIndex = Idx_DashDot;
1665 break;
1666 case SvxBorderLineStyle::DASH_DOT_DOT:
1667 nStyleIndex = Idx_DashDotDot;
1668 break;
1669 case SvxBorderLineStyle::DOUBLE_THIN:
1670 // the "nOuterWidth" is not right for this line type
1671 // but at the moment width it not important for that
1672 // the right function is nOuterWidth = (sal_uInt16) pLine->GetWidth();
1673 nStyleIndex = Idx_DoubleThin;
1674 break;
1675 default:
1676 nStyleIndex = Idx_Solid;
1679 if( nOuterWidth >= EXC_BORDER_THICK )
1680 nOuterWidthIndx = Width_Thick;
1681 else if( nOuterWidth >= EXC_BORDER_MEDIUM )
1682 nOuterWidthIndx = Width_Medium;
1683 else if( nOuterWidth >= EXC_BORDER_THIN )
1684 nOuterWidthIndx = Width_Thin;
1685 else if ( nOuterWidth >= EXC_BORDER_HAIR )
1686 nOuterWidthIndx = Width_Hair;
1687 else
1688 nOuterWidthIndx = Width_Thin;
1690 rnXclLine = Map_LineLO_toMS[nStyleIndex][nOuterWidthIndx];
1693 if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
1694 rnXclLine = EXC_LINE_THIN;
1696 if (pLine && (rnXclLine != EXC_LINE_NONE))
1698 rnColorId = rPalette.InsertColor(pLine->GetColor(), EXC_COLOR_CELLBORDER);
1699 rComplexColor = pLine->getComplexColor();
1701 else
1703 rnColorId = XclExpPalette::GetColorIdFromIndex(0);
1707 } // namespace
1709 XclExpCellBorder::XclExpCellBorder() :
1710 mnLeftColorId( XclExpPalette::GetColorIdFromIndex( mnLeftColor ) ),
1711 mnRightColorId( XclExpPalette::GetColorIdFromIndex( mnRightColor ) ),
1712 mnTopColorId( XclExpPalette::GetColorIdFromIndex( mnTopColor ) ),
1713 mnBottomColorId( XclExpPalette::GetColorIdFromIndex( mnBottomColor ) ),
1714 mnDiagColorId( XclExpPalette::GetColorIdFromIndex( mnDiagColor ) )
1718 bool XclExpCellBorder::FillFromItemSet(
1719 const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
1721 bool bUsed = false;
1723 switch( eBiff )
1725 case EXC_BIFF8: // attributes new in BIFF8
1727 const SvxLineItem& rTLBRItem = rItemSet.Get( ATTR_BORDER_TLBR );
1728 sal_uInt8 nTLBRLine;
1729 sal_uInt32 nTLBRColorId;
1730 model::ComplexColor aTLBRComplexColor;
1731 lclGetBorderLine( nTLBRLine, nTLBRColorId, aTLBRComplexColor, rTLBRItem.GetLine(), rPalette, eBiff );
1732 mbDiagTLtoBR = (nTLBRLine != EXC_LINE_NONE);
1734 const SvxLineItem& rBLTRItem = rItemSet.Get( ATTR_BORDER_BLTR );
1735 sal_uInt8 nBLTRLine;
1736 sal_uInt32 nBLTRColorId;
1737 model::ComplexColor aBLTRComplexColor;
1738 lclGetBorderLine( nBLTRLine, nBLTRColorId, aBLTRComplexColor, rBLTRItem.GetLine(), rPalette, eBiff );
1739 mbDiagBLtoTR = (nBLTRLine != EXC_LINE_NONE);
1741 if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
1743 mnDiagLine = nTLBRLine;
1744 mnDiagColorId = nTLBRColorId;
1746 else
1748 mnDiagLine = nBLTRLine;
1749 mnDiagColorId = nBLTRColorId;
1752 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
1753 ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
1755 [[fallthrough]];
1758 case EXC_BIFF5:
1759 case EXC_BIFF4:
1760 case EXC_BIFF3:
1761 case EXC_BIFF2:
1763 const SvxBoxItem& rBoxItem = rItemSet.Get( ATTR_BORDER );
1765 lclGetBorderLine(mnLeftLine, mnLeftColorId, maComplexColorLeft, rBoxItem.GetLeft(), rPalette, eBiff);
1766 lclGetBorderLine(mnRightLine, mnRightColorId, maComplexColorRight, rBoxItem.GetRight(), rPalette, eBiff);
1767 lclGetBorderLine(mnTopLine, mnTopColorId, maComplexColorTop, rBoxItem.GetTop(), rPalette, eBiff);
1768 lclGetBorderLine(mnBottomLine, mnBottomColorId, maComplexColorBottom, rBoxItem.GetBottom(), rPalette, eBiff);
1770 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER, bStyle );
1773 break;
1774 default: DBG_ERROR_BIFF();
1777 return bUsed;
1780 void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
1782 mnLeftColor = rPalette.GetColorIndex( mnLeftColorId );
1783 mnRightColor = rPalette.GetColorIndex( mnRightColorId );
1784 mnTopColor = rPalette.GetColorIndex( mnTopColorId );
1785 mnBottomColor = rPalette.GetColorIndex( mnBottomColorId );
1786 mnDiagColor = rPalette.GetColorIndex( mnDiagColorId );
1789 void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
1791 ::insert_value( rnBorder, mnTopLine, 0, 3 );
1792 ::insert_value( rnBorder, mnLeftLine, 3, 3 );
1793 ::insert_value( rnArea, mnBottomLine, 22, 3 );
1794 ::insert_value( rnBorder, mnRightLine, 6, 3 );
1795 ::insert_value( rnBorder, mnTopColor, 9, 7 );
1796 ::insert_value( rnBorder, mnLeftColor, 16, 7 );
1797 ::insert_value( rnArea, mnBottomColor, 25, 7 );
1798 ::insert_value( rnBorder, mnRightColor, 23, 7 );
1801 void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
1803 ::insert_value( rnBorder1, mnLeftLine, 0, 4 );
1804 ::insert_value( rnBorder1, mnRightLine, 4, 4 );
1805 ::insert_value( rnBorder1, mnTopLine, 8, 4 );
1806 ::insert_value( rnBorder1, mnBottomLine, 12, 4 );
1807 ::insert_value( rnBorder1, mnLeftColor, 16, 7 );
1808 ::insert_value( rnBorder1, mnRightColor, 23, 7 );
1809 ::insert_value( rnBorder2, mnTopColor, 0, 7 );
1810 ::insert_value( rnBorder2, mnBottomColor, 7, 7 );
1811 ::insert_value( rnBorder2, mnDiagColor, 14, 7 );
1812 ::insert_value( rnBorder2, mnDiagLine, 21, 4 );
1813 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_TL_TO_BR, mbDiagTLtoBR );
1814 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_BL_TO_TR, mbDiagBLtoTR );
1817 void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
1819 ::insert_value( rnLine, mnLeftLine, 0, 4 );
1820 ::insert_value( rnLine, mnRightLine, 4, 4 );
1821 ::insert_value( rnLine, mnTopLine, 8, 4 );
1822 ::insert_value( rnLine, mnBottomLine, 12, 4 );
1823 ::insert_value( rnColor, mnLeftColor, 0, 7 );
1824 ::insert_value( rnColor, mnRightColor, 7, 7 );
1825 ::insert_value( rnColor, mnTopColor, 16, 7 );
1826 ::insert_value( rnColor, mnBottomColor, 23, 7 );
1829 static const char* ToLineStyle( sal_uInt8 nLineStyle )
1831 switch( nLineStyle )
1833 case EXC_LINE_NONE: return "none";
1834 case EXC_LINE_THIN: return "thin";
1835 case EXC_LINE_MEDIUM: return "medium";
1836 case EXC_LINE_THICK: return "thick";
1837 case EXC_LINE_DOUBLE: return "double";
1838 case EXC_LINE_HAIR: return "hair";
1839 case EXC_LINE_DOTTED: return "dotted";
1840 case EXC_LINE_DASHED: return "dashed";
1841 case EXC_LINE_MEDIUM_DASHED: return "mediumDashed";
1842 case EXC_LINE_THIN_DASHDOT: return "dashDot";
1843 case EXC_LINE_THIN_DASHDOTDOT: return "dashDotDot";
1844 case EXC_LINE_MEDIUM_DASHDOT: return "mediumDashDot";
1845 case EXC_LINE_MEDIUM_DASHDOTDOT: return "mediumDashDotDot";
1846 case EXC_LINE_MEDIUM_SLANT_DASHDOT: return "slantDashDot";
1848 return "*unknown*";
1851 namespace
1853 void lcl_WriteBorder(XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor, model::ComplexColor const& rComplexColor)
1855 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1856 if( nLineStyle == EXC_LINE_NONE )
1858 rStyleSheet->singleElement(nElement);
1859 return;
1861 else if (rColor == Color(0, 0, 0) && !rComplexColor.isValidThemeType())
1863 rStyleSheet->singleElement(nElement, XML_style, ToLineStyle(nLineStyle));
1864 return;
1867 rStyleSheet->startElement(nElement, XML_style, ToLineStyle(nLineStyle));
1868 oox::xls::writeComplexColor(rStyleSheet, XML_color, rComplexColor, rColor);
1869 rStyleSheet->endElement(nElement);
1871 } // end anonymous namespace
1873 void XclExpCellBorder::SaveXml(XclExpXmlStream& rStream) const
1875 sax_fastparser::FSHelperPtr& rStyleSheet = rStream.GetCurrentStream();
1877 XclExpPalette& rPalette = rStream.GetRoot().GetPalette();
1879 rStyleSheet->startElement( XML_border,
1880 XML_diagonalUp, ToPsz( mbDiagBLtoTR ),
1881 XML_diagonalDown, ToPsz( mbDiagTLtoBR )
1882 // OOXTODO: XML_outline
1885 lcl_WriteBorder(rStream, XML_left, mnLeftLine, rPalette.GetColor(mnLeftColor), maComplexColorLeft);
1886 lcl_WriteBorder(rStream, XML_right, mnRightLine, rPalette.GetColor(mnRightColor), maComplexColorRight);
1887 lcl_WriteBorder(rStream, XML_top, mnTopLine, rPalette.GetColor(mnTopColor), maComplexColorTop);
1888 lcl_WriteBorder(rStream, XML_bottom, mnBottomLine, rPalette.GetColor(mnBottomColor), maComplexColorBottom);
1889 lcl_WriteBorder(rStream, XML_diagonal, mnDiagLine, rPalette.GetColor(mnDiagColor), maComplexColorDiagonal);
1891 // OOXTODO: XML_vertical, XML_horizontal
1892 rStyleSheet->endElement( XML_border );
1895 XclExpCellArea::XclExpCellArea() :
1896 mnForeColorId(XclExpPalette::GetColorIdFromIndex(mnForeColor)),
1897 mnBackColorId(XclExpPalette::GetColorIdFromIndex(mnBackColor)),
1898 maForeColor(COL_TRANSPARENT),
1899 maBackColor(COL_TRANSPARENT)
1903 XclExpCellArea::XclExpCellArea(Color aForeColor, Color aBackColor)
1904 : XclCellArea(EXC_PATT_SOLID)
1905 , mnForeColorId(0)
1906 , mnBackColorId(0)
1907 , maForeColor(aForeColor)
1908 , maBackColor(aBackColor)
1912 bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
1914 const SvxBrushItem& rBrushItem = rItemSet.Get( ATTR_BACKGROUND );
1916 if (rBrushItem.getComplexColor().getType() != model::ColorType::Unused)
1917 maForegroundComplexColor = rBrushItem.getComplexColor();
1919 if( rBrushItem.GetColor().IsTransparent() )
1921 mnPattern = EXC_PATT_NONE;
1922 mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1923 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
1925 else
1927 mnPattern = EXC_PATT_SOLID;
1928 mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
1929 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1931 return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
1934 void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
1936 rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
1939 void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
1941 ::insert_value( rnArea, mnPattern, 16, 6 );
1942 ::insert_value( rnArea, mnForeColor, 0, 7 );
1943 ::insert_value( rnArea, mnBackColor, 7, 7 );
1946 void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
1948 ::insert_value( rnBorder2, mnPattern, 26, 6 );
1949 ::insert_value( rnArea, mnForeColor, 0, 7 );
1950 ::insert_value( rnArea, mnBackColor, 7, 7 );
1953 void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
1955 XclCellArea aTmp( *this );
1956 if( !aTmp.IsTransparent() && (aTmp.mnBackColor == EXC_COLOR_WINDOWTEXT) )
1957 aTmp.mnBackColor = 0;
1958 if( aTmp.mnPattern == EXC_PATT_SOLID )
1959 ::std::swap( aTmp.mnForeColor, aTmp.mnBackColor );
1960 ::insert_value( rnColor, aTmp.mnForeColor, 0, 7 );
1961 ::insert_value( rnColor, aTmp.mnBackColor, 7, 7 );
1962 ::insert_value( rnPattern, aTmp.mnPattern, 10, 6 );
1965 static const char* ToPatternType( sal_uInt8 nPattern )
1967 switch( nPattern )
1969 case EXC_PATT_NONE: return "none";
1970 case EXC_PATT_SOLID: return "solid";
1971 case EXC_PATT_50_PERC: return "mediumGray";
1972 case EXC_PATT_75_PERC: return "darkGray";
1973 case EXC_PATT_25_PERC: return "lightGray";
1974 case EXC_PATT_12_5_PERC: return "gray125";
1975 case EXC_PATT_6_25_PERC: return "gray0625";
1977 return "*unknown*";
1980 void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
1982 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1983 rStyleSheet->startElement(XML_fill);
1985 // OOXTODO: XML_gradientFill
1987 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1989 if (mnPattern == EXC_PATT_NONE ||
1990 (mnForeColor == 0 && mnBackColor == 0 && maForeColor == COL_TRANSPARENT && maBackColor == COL_TRANSPARENT))
1992 rStyleSheet->singleElement(XML_patternFill, XML_patternType, ToPatternType(mnPattern));
1994 else
1996 rStyleSheet->startElement(XML_patternFill, XML_patternType, ToPatternType(mnPattern));
1998 if (maForeColor != COL_TRANSPARENT || maBackColor != COL_TRANSPARENT)
2000 oox::xls::writeComplexColor(rStyleSheet, XML_fgColor, maForegroundComplexColor, maForeColor);
2001 oox::xls::writeComplexColor(rStyleSheet, XML_bgColor, maBackgroundComplexColor, maBackColor);
2003 else
2006 Color aColor = rPalette.GetColor(mnForeColor);
2007 if (maForegroundComplexColor.isValidThemeType() || mnForeColor != 0)
2008 oox::xls::writeComplexColor(rStyleSheet, XML_fgColor, maForegroundComplexColor, aColor);
2009 else if (mnForeColor != 0)
2010 oox::xls::writeComplexColor(rStyleSheet, XML_fgColor, maForegroundComplexColor, aColor);
2014 Color aColor = rPalette.GetColor(mnBackColor);
2015 if (maBackgroundComplexColor.isValidThemeType() || mnBackColor != 0)
2016 oox::xls::writeComplexColor(rStyleSheet, XML_bgColor, maBackgroundComplexColor, aColor);
2019 rStyleSheet->endElement( XML_patternFill );
2022 rStyleSheet->endElement( XML_fill );
2025 bool XclExpColor::FillFromItemSet( const SfxItemSet& rItemSet )
2027 if( !ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true ) )
2028 return false;
2030 const SvxBrushItem& rBrushItem = rItemSet.Get( ATTR_BACKGROUND );
2031 maColor = rBrushItem.GetColor();
2032 maComplexColor = rBrushItem.getComplexColor();
2034 return true;
2037 void XclExpColor::SaveXml( XclExpXmlStream& rStrm ) const
2039 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2040 rStyleSheet->startElement(XML_fill);
2041 rStyleSheet->startElement(XML_patternFill);
2043 oox::xls::writeComplexColor(rStyleSheet, XML_bgColor, maComplexColor, maColor);
2045 rStyleSheet->endElement( XML_patternFill );
2046 rStyleSheet->endElement( XML_fill );
2049 XclExpXFId::XclExpXFId() :
2050 mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
2051 mnXFIndex( EXC_XF_DEFAULTCELL )
2055 void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
2057 mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
2060 XclExpXF::XclExpXF(
2061 const XclExpRoot& rRoot, const ScPatternAttr& rPattern, sal_Int16 nScript,
2062 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) :
2063 XclXFBase( true ),
2064 XclExpRoot( rRoot )
2066 mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
2067 Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
2070 XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet ) :
2071 XclXFBase( false ),
2072 XclExpRoot( rRoot ),
2073 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2075 bool bDefStyle = (rStyleSheet.GetName() == ScResId( STR_STYLENAME_STANDARD ));
2076 sal_Int16 nScript = bDefStyle ? GetDefApiScript() : css::i18n::ScriptType::WEAK;
2077 Init( const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet(), nScript,
2078 NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false, bDefStyle );
2081 XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF ) :
2082 XclXFBase( bCellXF ),
2083 XclExpRoot( rRoot ),
2084 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2086 InitDefault();
2089 bool XclExpXF::Equals( const ScPatternAttr& rPattern,
2090 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2092 return IsCellXF() && (mpItemSet == &rPattern.GetItemSet()) &&
2093 (!bForceLineBreak || maAlignment.mbLineBreak) &&
2094 ((nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) || (mnScNumFmt == nForceScNumFmt)) &&
2095 ((nForceXclFont == EXC_FONT_NOTFOUND) || (mnXclFont == nForceXclFont));
2098 bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
2100 return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
2103 void XclExpXF::SetFinalColors()
2105 maBorder.SetFinalColors( GetPalette() );
2106 maArea.SetFinalColors( GetPalette() );
2109 bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
2111 return XclXFBase::Equals( rCmpXF ) &&
2112 (maProtection == rCmpXF.maProtection) && (maAlignment == rCmpXF.maAlignment) &&
2113 (maBorder == rCmpXF.maBorder) && (maArea == rCmpXF.maArea) &&
2114 (mnXclFont == rCmpXF.mnXclFont) && (mnXclNumFmt == rCmpXF.mnXclNumFmt) &&
2115 (mnParentXFId == rCmpXF.mnParentXFId);
2118 void XclExpXF::InitDefault()
2120 SetRecHeader( EXC_ID5_XF, (GetBiff() == EXC_BIFF8) ? 20 : 16 );
2121 mpItemSet = nullptr;
2122 mnScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
2123 mnXclFont = mnXclNumFmt = 0;
2124 SetXmlIds(0, 0);
2127 void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
2128 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
2130 InitDefault();
2131 mpItemSet = &rItemSet;
2133 // cell protection
2134 mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
2136 // font
2137 if( nForceXclFont == EXC_FONT_NOTFOUND )
2139 mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
2140 mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
2142 else
2144 mnXclFont = nForceXclFont;
2145 mbFontUsed = true;
2148 // number format
2149 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
2150 mnScNumFmt = nForceScNumFmt;
2151 else
2153 // Built-in formats of dedicated languages may be attributed using the
2154 // system language (or even other?) format with a language attribute,
2155 // obtain the "real" format key.
2156 mnScNumFmt = rItemSet.Get( ATTR_VALUE_FORMAT ).GetValue();
2157 LanguageType nLang = rItemSet.Get( ATTR_LANGUAGE_FORMAT).GetLanguage();
2158 if (mnScNumFmt >= SV_COUNTRY_LANGUAGE_OFFSET || nLang != LANGUAGE_SYSTEM)
2159 mnScNumFmt = GetFormatter().GetFormatForLanguageIfBuiltIn( mnScNumFmt, nLang);
2161 mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
2162 mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
2164 // alignment
2165 mbAlignUsed = maAlignment.FillFromItemSet(*this, rItemSet, bForceLineBreak, GetBiff(), IsStyleXF());
2167 // cell border
2168 mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
2170 // background area
2171 mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
2173 // set all b***Used flags to true in "Default"/"Normal" style
2174 if( bDefStyle )
2175 SetAllUsedFlags( true );
2178 sal_uInt8 XclExpXF::GetUsedFlags() const
2180 sal_uInt8 nUsedFlags = 0;
2181 /* In cell XFs a set bit means a used attribute, in style XFs a cleared bit.
2182 "mbCellXF == mb***Used" evaluates to correct value in cell and style XFs. */
2183 ::set_flag( nUsedFlags, EXC_XF_DIFF_PROT, mbCellXF == mbProtUsed );
2184 ::set_flag( nUsedFlags, EXC_XF_DIFF_FONT, mbCellXF == mbFontUsed );
2185 ::set_flag( nUsedFlags, EXC_XF_DIFF_VALFMT, mbCellXF == mbFmtUsed );
2186 ::set_flag( nUsedFlags, EXC_XF_DIFF_ALIGN, mbCellXF == mbAlignUsed );
2187 ::set_flag( nUsedFlags, EXC_XF_DIFF_BORDER, mbCellXF == mbBorderUsed );
2188 ::set_flag( nUsedFlags, EXC_XF_DIFF_AREA, mbCellXF == mbAreaUsed );
2189 return nUsedFlags;
2192 void XclExpXF::WriteBody5( XclExpStream& rStrm )
2194 sal_uInt16 nTypeProt = 0, nAlign = 0;
2195 sal_uInt32 nArea = 0, nBorder = 0;
2197 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2198 ::insert_value( nTypeProt, mnParent, 4, 12 );
2199 ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
2201 maProtection.FillToXF3( nTypeProt );
2202 maAlignment.FillToXF5( nAlign );
2203 maBorder.FillToXF5( nBorder, nArea );
2204 maArea.FillToXF5( nArea );
2206 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
2209 void XclExpXF::WriteBody8( XclExpStream& rStrm )
2211 sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
2212 sal_uInt32 nBorder1 = 0, nBorder2 = 0;
2214 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2215 ::insert_value( nTypeProt, mnParent, 4, 12 );
2216 ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
2218 maProtection.FillToXF3( nTypeProt );
2219 maAlignment.FillToXF8( nAlign, nMiscAttrib );
2220 maBorder.FillToXF8( nBorder1, nBorder2 );
2221 maArea.FillToXF8( nBorder2, nArea );
2223 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
2226 void XclExpXF::WriteBody( XclExpStream& rStrm )
2228 XclExpXFId aParentId( mnParentXFId );
2229 aParentId.ConvertXFIndex( GetRoot() );
2230 mnParent = aParentId.mnXFIndex;
2231 switch( GetBiff() )
2233 case EXC_BIFF5: WriteBody5( rStrm ); break;
2234 case EXC_BIFF8: WriteBody8( rStrm ); break;
2235 default: DBG_ERROR_BIFF();
2239 void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
2241 mnBorderId = nBorderId;
2242 mnFillId = nFillId;
2245 void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
2247 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2249 sal_Int32 nXfId = 0;
2250 const XclExpXF* pStyleXF = nullptr;
2251 if( IsCellXF() )
2253 sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
2254 nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
2255 pStyleXF = rStrm.GetRoot().GetXFBuffer().GetXFById( mnParentXFId );
2258 rStyleSheet->startElement( XML_xf,
2259 XML_numFmtId, OString::number(mnXclNumFmt),
2260 XML_fontId, OString::number(mnXclFont),
2261 XML_fillId, OString::number(mnFillId),
2262 XML_borderId, OString::number(mnBorderId),
2263 XML_xfId, sax_fastparser::UseIf(OString::number(nXfId), !IsStyleXF()),
2264 // OOXTODO: XML_quotePrefix,
2265 // OOXTODO: XML_pivotButton,
2266 // OOXTODO: XML_applyNumberFormat, ;
2267 XML_applyFont, ToPsz( mbFontUsed ),
2268 // OOXTODO: XML_applyFill,
2269 XML_applyBorder, ToPsz( mbBorderUsed ),
2270 XML_applyAlignment, ToPsz( mbAlignUsed ),
2271 XML_applyProtection, ToPsz( mbProtUsed ) );
2272 if( mbAlignUsed )
2273 maAlignment.SaveXml( rStrm );
2274 else if ( pStyleXF )
2275 pStyleXF->GetAlignmentData().SaveXml( rStrm );
2276 if( mbProtUsed )
2277 maProtection.SaveXml( rStrm );
2278 else if ( pStyleXF )
2279 pStyleXF->GetProtectionData().SaveXml( rStrm );
2281 // OOXTODO: XML_extLst
2282 rStyleSheet->endElement( XML_xf );
2285 XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
2286 XclExpXF( rRoot, bCellXF )
2290 void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
2292 mnXclFont = nXclFont;
2293 mbFontUsed = true;
2296 void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
2298 mnXclNumFmt = nXclNumFmt;
2299 mbFmtUsed = true;
2302 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, OUString aStyleName ) :
2303 XclExpRecord( EXC_ID_STYLE, 4 ),
2304 maName(std::move( aStyleName )),
2305 maXFId( nXFId ),
2306 mnStyleId( EXC_STYLE_USERDEF ),
2307 mnLevel( EXC_STYLE_NOLEVEL )
2309 OSL_ENSURE( !maName.isEmpty(), "XclExpStyle::XclExpStyle - empty style name" );
2310 #if OSL_DEBUG_LEVEL > 0
2311 sal_uInt8 nStyleId, nLevel; // do not use members for debug tests
2312 OSL_ENSURE( !XclTools::GetBuiltInStyleId( nStyleId, nLevel, maName ),
2313 "XclExpStyle::XclExpStyle - this is a built-in style" );
2314 #endif
2317 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, sal_uInt8 nStyleId, sal_uInt8 nLevel ) :
2318 XclExpRecord( EXC_ID_STYLE, 4 ),
2319 maXFId( nXFId ),
2320 mnStyleId( nStyleId ),
2321 mnLevel( nLevel )
2325 void XclExpStyle::WriteBody( XclExpStream& rStrm )
2327 maXFId.ConvertXFIndex( rStrm.GetRoot() );
2328 ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
2329 rStrm << maXFId.mnXFIndex;
2331 if( IsBuiltIn() )
2333 rStrm << mnStyleId << mnLevel;
2335 else
2337 XclExpString aNameEx;
2338 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
2339 aNameEx.Assign( maName );
2340 else
2341 aNameEx.AssignByte( maName, rStrm.GetRoot().GetTextEncoding(), XclStrFlags::EightBitLength );
2342 rStrm << aNameEx;
2346 static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
2348 switch( nStyleId )
2350 case 0: return "Normal";
2351 case 3: return "Comma";
2352 case 4: return "Currency";
2353 case 5: return "Percent";
2354 case 6: return "Comma [0]";
2355 case 7: return "Currency [0]";
2357 return "*unknown*";
2360 void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
2362 constexpr sal_Int32 CELL_STYLE_MAX_BUILTIN_ID = 54;
2363 OString sName;
2364 OString sBuiltinId;
2365 const char* pBuiltinId = nullptr;
2366 if( IsBuiltIn() )
2368 sName = OString( lcl_StyleNameFromId( mnStyleId ) );
2369 sBuiltinId = OString::number( std::min( static_cast<sal_Int32>( CELL_STYLE_MAX_BUILTIN_ID - 1 ), static_cast <sal_Int32>( mnStyleId ) ) );
2370 pBuiltinId = sBuiltinId.getStr();
2372 else
2373 sName = maName.toUtf8();
2375 // get the index in sortedlist associated with the mnXId
2376 sal_Int32 nXFId = rStrm.GetRoot().GetXFBuffer().GetXFIndex( maXFId.mnXFId );
2377 // get the style index associated with index into sortedlist
2378 nXFId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFId );
2379 rStrm.GetCurrentStream()->singleElement( XML_cellStyle,
2380 XML_name, sName,
2381 XML_xfId, OString::number(nXFId),
2382 // builtinId of 54 or above is invalid according to OpenXML SDK validator.
2383 XML_builtinId, pBuiltinId
2384 // OOXTODO: XML_iLevel,
2385 // OOXTODO: XML_hidden,
2386 // XML_customBuiltin, ToPsz( ! IsBuiltIn() )
2388 // OOXTODO: XML_extLst
2391 namespace {
2393 const sal_uInt32 EXC_XFLIST_INDEXBASE = 0xFFFE0000;
2394 /** Maximum count of XF records to store in the XF list (performance). */
2395 const sal_uInt32 EXC_XFLIST_HARDLIMIT = 256 * 1024;
2397 bool lclIsBuiltInStyle( const OUString& rStyleName )
2399 return
2400 XclTools::IsBuiltInStyleName( rStyleName ) ||
2401 XclTools::IsCondFormatStyleName( rStyleName );
2404 } // namespace
2406 XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
2407 mnStyleId( EXC_STYLE_USERDEF ),
2408 mnLevel( EXC_STYLE_NOLEVEL ),
2409 mbPredefined( true ),
2410 mbHasStyleRec( false )
2414 namespace {
2416 /** Predicate for search algorithm. */
2417 struct XclExpBorderPred
2419 const XclExpCellBorder&
2420 mrBorder;
2421 explicit XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
2422 bool operator()( const XclExpCellBorder& rBorder ) const;
2427 bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
2429 return
2430 mrBorder.mnLeftColor == rBorder.mnLeftColor &&
2431 mrBorder.mnRightColor == rBorder.mnRightColor &&
2432 mrBorder.mnTopColor == rBorder.mnTopColor &&
2433 mrBorder.mnBottomColor == rBorder.mnBottomColor &&
2434 mrBorder.mnDiagColor == rBorder.mnDiagColor &&
2435 mrBorder.mnLeftLine == rBorder.mnLeftLine &&
2436 mrBorder.mnRightLine == rBorder.mnRightLine &&
2437 mrBorder.mnTopLine == rBorder.mnTopLine &&
2438 mrBorder.mnBottomLine == rBorder.mnBottomLine &&
2439 mrBorder.mnDiagLine == rBorder.mnDiagLine &&
2440 mrBorder.mbDiagTLtoBR == rBorder.mbDiagTLtoBR &&
2441 mrBorder.mbDiagBLtoTR == rBorder.mbDiagBLtoTR &&
2442 mrBorder.mnLeftColorId == rBorder.mnLeftColorId &&
2443 mrBorder.mnRightColorId == rBorder.mnRightColorId &&
2444 mrBorder.mnTopColorId == rBorder.mnTopColorId &&
2445 mrBorder.mnBottomColorId == rBorder.mnBottomColorId &&
2446 mrBorder.mnDiagColorId == rBorder.mnDiagColorId;
2449 namespace {
2451 struct XclExpFillPred
2453 const XclExpCellArea&
2454 mrFill;
2455 explicit XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
2456 bool operator()( const XclExpCellArea& rFill ) const;
2461 bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
2463 return
2464 mrFill.mnForeColor == rFill.mnForeColor &&
2465 mrFill.mnBackColor == rFill.mnBackColor &&
2466 mrFill.mnPattern == rFill.mnPattern &&
2467 mrFill.mnForeColorId == rFill.mnForeColorId &&
2468 mrFill.mnBackColorId == rFill.mnBackColorId;
2471 XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot ) :
2472 XclExpRoot( rRoot )
2476 void XclExpXFBuffer::Initialize()
2478 InsertDefaultRecords();
2479 InsertUserStyles();
2482 sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
2484 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
2487 sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
2488 sal_uInt16 nForceXclFont, bool bForceLineBreak )
2490 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
2493 sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForceScNumFmt, bool bForceLineBreak )
2495 return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
2498 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
2500 return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2503 sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
2505 return EXC_XFLIST_INDEXBASE | nXFIndex;
2508 sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
2510 return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
2513 const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
2515 return maXFList.GetRecord( nXFId );
2518 void XclExpXFBuffer::Finalize()
2520 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2521 maXFList.GetRecord( nPos )->SetFinalColors();
2523 sal_uInt32 nTotalCount = static_cast< sal_uInt32 >( maXFList.GetSize() );
2524 sal_uInt32 nId;
2525 maXFIndexVec.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2526 maStyleIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2527 maCellIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2529 XclExpBuiltInMap::const_iterator aBuiltInEnd = maBuiltInMap.end();
2530 /* nMaxBuiltInXFId used to decide faster whether an XF record is
2531 user-defined. If the current XF ID is greater than this value,
2532 maBuiltInMap doesn't need to be searched. */
2533 sal_uInt32 nMaxBuiltInXFId = maBuiltInMap.empty() ? 0 : maBuiltInMap.rbegin()->first;
2535 // *** map all built-in XF records (cell and style) *** -------------------
2537 // do not change XF order -> std::map<> iterates elements in ascending order
2538 for( const auto& rEntry : maBuiltInMap )
2539 AppendXFIndex( rEntry.first );
2541 // *** insert all user-defined style XF records, without reduce *** -------
2543 sal_uInt32 nStyleXFCount = 0; // counts up to EXC_XF_MAXSTYLECOUNT limit
2545 for( nId = 0; nId < nTotalCount; ++nId )
2547 XclExpXFRef xXF = maXFList.GetRecord( nId );
2548 if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2550 if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
2552 // maximum count of styles not reached
2553 AppendXFIndex( nId );
2554 ++nStyleXFCount;
2556 else
2558 /* Maximum count of styles reached - do not append more
2559 pointers to XFs; use default style XF instead; do not break
2560 the loop to initialize all maXFIndexVec elements. */
2561 maXFIndexVec[ nId ] = EXC_XF_DEFAULTSTYLE;
2566 // *** insert all cell XF records *** -------------------------------------
2568 // start position to search for equal inserted XF records
2569 size_t nSearchStart = maSortedXFList.GetSize();
2571 // break the loop if XF limit reached - maXFIndexVec is already initialized with default index
2572 XclExpXFRef xDefCellXF = maXFList.GetRecord( EXC_XF_DEFAULTCELL );
2573 for( nId = 0; (nId < nTotalCount) && (maSortedXFList.GetSize() < EXC_XF_MAXCOUNT); ++nId )
2575 XclExpXFRef xXF = maXFList.GetRecord( nId );
2576 if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2578 // try to find an XF record equal to *xXF, which is already inserted
2579 sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
2581 // first try if it is equal to the default cell XF
2582 if( xDefCellXF->Equals( *xXF ) )
2584 nFoundIndex = EXC_XF_DEFAULTCELL;
2586 else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
2587 (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
2589 if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
2590 nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
2593 if( nFoundIndex != EXC_XF_NOTFOUND )
2594 // equal XF already in the list, use its resulting XF index
2595 maXFIndexVec[ nId ] = nFoundIndex;
2596 else
2597 AppendXFIndex( nId );
2601 sal_uInt16 nXmlStyleIndex = 0;
2602 sal_uInt16 nXmlCellIndex = 0;
2604 size_t nXFCount = maSortedXFList.GetSize();
2605 for( size_t i = 0; i < nXFCount; ++i )
2607 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2608 if( xXF->IsStyleXF() )
2609 maStyleIndexes[ i ] = nXmlStyleIndex++;
2610 else
2611 maCellIndexes[ i ] = nXmlCellIndex++;
2615 sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
2617 sal_uInt16 nXFIndex = EXC_XF_DEFAULTSTYLE;
2618 if( nXFId >= EXC_XFLIST_INDEXBASE )
2619 nXFIndex = static_cast< sal_uInt16 >( nXFId & ~EXC_XFLIST_INDEXBASE );
2620 else if( nXFId < maXFIndexVec.size() )
2621 nXFIndex = maXFIndexVec[ nXFId ];
2622 return nXFIndex;
2625 sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
2627 OSL_ENSURE( nXFIndex < maStyleIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2628 if( nXFIndex >= maStyleIndexes.size() )
2629 return 0; // should be caught/debugged via above assert; return "valid" index.
2630 return maStyleIndexes[ nXFIndex ];
2633 sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
2635 OSL_ENSURE( nXFIndex < maCellIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2636 if( nXFIndex >= maCellIndexes.size() )
2637 return 0; // should be caught/debugged via above assert; return "valid" index.
2638 return maCellIndexes[ nXFIndex ];
2641 void XclExpXFBuffer::Save( XclExpStream& rStrm )
2643 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2644 maSortedXFList.Save( rStrm );
2645 // save all STYLE records
2646 maStyleList.Save( rStrm );
2649 static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
2651 rCells = 0;
2652 rStyles = 0;
2653 size_t nXFCount = rXFList.GetSize();
2654 for( size_t i = 0; i < nXFCount; ++i )
2656 XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
2657 if( xXF->IsCellXF() )
2658 ++rCells;
2659 else if( xXF->IsStyleXF() )
2660 ++rStyles;
2664 void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
2666 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2668 rStyleSheet->startElement(XML_fills, XML_count, OString::number(maFills.size()));
2669 for( const auto& rFill : maFills )
2671 rFill.SaveXml( rStrm );
2673 rStyleSheet->endElement( XML_fills );
2675 rStyleSheet->startElement(XML_borders, XML_count, OString::number(maBorders.size()));
2676 for( const auto& rBorder : maBorders )
2678 rBorder.SaveXml( rStrm );
2680 rStyleSheet->endElement( XML_borders );
2682 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2683 sal_Int32 nCells, nStyles;
2684 lcl_GetCellCounts( maSortedXFList, nCells, nStyles );
2686 if( nStyles > 0 )
2688 rStyleSheet->startElement(XML_cellStyleXfs, XML_count, OString::number(nStyles));
2689 size_t nXFCount = maSortedXFList.GetSize();
2690 for( size_t i = 0; i < nXFCount; ++i )
2692 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2693 if( ! xXF->IsStyleXF() )
2694 continue;
2695 SaveXFXml( rStrm, *xXF );
2697 rStyleSheet->endElement( XML_cellStyleXfs );
2700 if( nCells > 0 )
2702 rStyleSheet->startElement(XML_cellXfs, XML_count, OString::number(nCells));
2703 size_t nXFCount = maSortedXFList.GetSize();
2704 for( size_t i = 0; i < nXFCount; ++i )
2706 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2707 if( ! xXF->IsCellXF() )
2708 continue;
2709 SaveXFXml( rStrm, *xXF );
2711 rStyleSheet->endElement( XML_cellXfs );
2714 // save all STYLE records
2715 rStyleSheet->startElement(XML_cellStyles, XML_count, OString::number(maStyleList.GetSize()));
2716 maStyleList.SaveXml( rStrm );
2717 rStyleSheet->endElement( XML_cellStyles );
2720 void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
2722 XclExpBorderList::iterator aBorderPos =
2723 std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) );
2724 OSL_ENSURE( aBorderPos != maBorders.end(), "XclExpXFBuffer::SaveXml - Invalid @borderId!" );
2725 XclExpFillList::iterator aFillPos =
2726 std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) );
2727 OSL_ENSURE( aFillPos != maFills.end(), "XclExpXFBuffer::SaveXml - Invalid @fillId!" );
2729 sal_Int32 nBorderId = 0, nFillId = 0;
2730 if( aBorderPos != maBorders.end() )
2731 nBorderId = std::distance( maBorders.begin(), aBorderPos );
2732 if( aFillPos != maFills.end() )
2733 nFillId = std::distance( maFills.begin(), aFillPos );
2735 rXF.SetXmlIds( nBorderId, nFillId );
2736 rXF.SaveXml( rStrm );
2739 sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
2740 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2742 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND && nForceXclFont == EXC_FONT_NOTFOUND)
2744 FindKey key1 { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, 0 };
2745 FindKey key2 { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, EXC_FONT_NOTFOUND };
2746 auto it1 = maXFFindMap.lower_bound(key1);
2747 if (it1 != maXFFindMap.end())
2749 auto it2 = maXFFindMap.upper_bound(key2);
2750 for (auto it = it1; it != it2; ++it)
2751 for (auto const & nPos : it->second)
2752 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2753 return nPos;
2756 else if (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND || nForceXclFont == EXC_FONT_NOTFOUND)
2758 FindKey key1 { /*mbCellXF*/true, &rPattern.GetItemSet(), 0, 0 };
2759 FindKey key2 { /*mbCellXF*/true, &rPattern.GetItemSet(), NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND };
2760 auto it1 = maXFFindMap.lower_bound(key1);
2761 if (it1 != maXFFindMap.end())
2763 auto it2 = maXFFindMap.upper_bound(key2);
2764 for (auto it = it1; it != it2; ++it)
2765 for (auto const & nPos : it->second)
2766 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2767 return nPos;
2770 else
2772 FindKey key { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, nForceXclFont };
2773 auto it = maXFFindMap.find(key);
2774 if (it == maXFFindMap.end())
2775 return EXC_XFID_NOTFOUND;
2776 for (auto const & nPos : it->second)
2777 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2778 return nPos;
2780 return EXC_XFID_NOTFOUND;
2783 sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
2785 const SfxItemSet* pItemSet = &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet();
2786 FindKey key1 { /*mbCellXF*/false, pItemSet, 0, 0 };
2787 FindKey key2 { /*mbCellXF*/false, pItemSet, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND };
2788 auto it1 = maXFFindMap.lower_bound(key1);
2789 auto it2 = maXFFindMap.upper_bound(key2);
2790 for (auto it = it1; it != it2; ++it)
2791 for (auto const & nPos : it->second)
2792 if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
2793 return nPos;
2794 return EXC_XFID_NOTFOUND;
2797 sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
2799 auto aIt = std::find_if(maBuiltInMap.begin(), maBuiltInMap.end(),
2800 [&nStyleId, nLevel](const XclExpBuiltInMap::value_type& rEntry) {
2801 return (rEntry.second.mnStyleId == nStyleId) && (rEntry.second.mnLevel == nLevel);
2803 if (aIt != maBuiltInMap.end())
2804 return aIt->first;
2805 return EXC_XFID_NOTFOUND;
2808 XclExpXFBuffer::FindKey XclExpXFBuffer::ToFindKey(XclExpXF const & rRec)
2810 return { rRec.IsCellXF(), rRec.GetItemSet(), rRec.GetScNumFmt(), rRec.GetXclFont() };
2813 sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
2814 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
2816 if( !pPattern )
2817 pPattern = &GetDoc().getCellAttributeHelper().getDefaultCellAttribute();
2819 // special handling for default cell formatting
2820 if ( pPattern->isDefault() && !bForceLineBreak &&
2821 (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
2822 (nForceXclFont == EXC_FONT_NOTFOUND) )
2824 // Is it the first try to insert the default cell format?
2825 bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
2826 if( rbPredefined )
2828 // remove old entry in find-map
2829 auto & rPositions = maXFFindMap[ToFindKey(*maXFList.GetRecord(EXC_XF_DEFAULTCELL))];
2830 auto it = std::find(rPositions.begin(), rPositions.end(), EXC_XF_DEFAULTCELL);
2831 rPositions.erase(it);
2832 // replace default cell pattern
2833 XclExpXFRef xNewXF = new XclExpXF( GetRoot(), *pPattern, nScript );
2834 maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
2835 // and add new entry in find-map
2836 maXFFindMap[ToFindKey(*xNewXF)].push_back(EXC_XF_DEFAULTCELL);
2837 rbPredefined = false;
2839 return GetDefCellXFId();
2842 sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2843 if( nXFId == EXC_XFID_NOTFOUND )
2845 // not found - insert new cell XF
2846 if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
2848 auto pNewExp = new XclExpXF(
2849 GetRoot(), *pPattern, nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2850 maXFList.AppendNewRecord( pNewExp );
2851 // do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
2852 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
2853 maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
2855 else
2857 // list full - fall back to default cell XF
2858 nXFId = GetDefCellXFId();
2861 return nXFId;
2864 sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
2866 // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
2868 sal_uInt8 nStyleId, nLevel;
2869 if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
2871 // try to find the built-in XF record (if already created in InsertDefaultRecords())
2872 sal_uInt32 nXFId = FindBuiltInXF( nStyleId, nLevel );
2873 if( nXFId == EXC_XFID_NOTFOUND )
2875 // built-in style XF not yet created - do it now
2876 XclExpXFRef xXF = new XclExpXF( GetRoot(), rStyleSheet );
2877 nXFId = AppendBuiltInXFWithStyle( xXF, nStyleId, nLevel );
2878 // this new XF record is not predefined
2879 maBuiltInMap[ nXFId ].mbPredefined = false;
2881 else
2883 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::InsertStyleXF - built-in XF not found" );
2884 // XF record still predefined? -> Replace with real XF
2885 bool& rbPredefined = maBuiltInMap[ nXFId ].mbPredefined;
2886 if( rbPredefined )
2888 // remove old entry in find-map
2889 auto & rPositions = maXFFindMap[ToFindKey(*maXFList.GetRecord(nXFId))];
2890 auto it = std::find(rPositions.begin(), rPositions.end(), nXFId);
2891 rPositions.erase(it);
2892 // replace predefined built-in style (ReplaceRecord() deletes old record)
2893 XclExpXFRef pNewExp = new XclExpXF( GetRoot(), rStyleSheet );
2894 maXFList.ReplaceRecord( pNewExp, nXFId );
2895 // and add new entry in find-map
2896 maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
2897 rbPredefined = false;
2901 // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
2902 bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
2903 if( !rbHasStyleRec )
2905 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2906 rbHasStyleRec = true;
2909 return nXFId;
2912 // *** try to find the XF record of a user-defined style ***
2914 sal_uInt32 nXFId = FindXF( rStyleSheet );
2915 if( nXFId == EXC_XFID_NOTFOUND )
2917 // not found - insert new style XF and STYLE
2918 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2919 if( nXFId < EXC_XFLIST_HARDLIMIT )
2921 auto pNewExp = new XclExpXF( GetRoot(), rStyleSheet );
2922 maXFList.AppendNewRecord( pNewExp );
2923 // create the STYLE record
2924 if( !rStyleSheet.GetName().isEmpty() )
2925 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
2926 maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
2928 else
2929 // list full - fall back to default style XF
2930 nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2932 return nXFId;
2935 void XclExpXFBuffer::InsertUserStyles()
2937 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SfxStyleFamily::Para );
2938 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
2939 if( pStyleSheet->IsUserDefined() && !lclIsBuiltInStyle( pStyleSheet->GetName() ) )
2940 InsertStyleXF( *pStyleSheet );
2943 sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef const & xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2945 sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2946 maXFList.AppendRecord( xXF );
2947 maXFFindMap[ToFindKey(*xXF)].push_back(nXFId);
2948 XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
2949 rInfo.mnStyleId = nStyleId;
2950 rInfo.mnLevel = nLevel;
2951 rInfo.mbPredefined = true;
2952 return nXFId;
2955 sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef const & xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2957 sal_uInt32 nXFId = AppendBuiltInXF( xXF, nStyleId, nLevel );
2958 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2959 maBuiltInMap[ nXFId ].mbHasStyleRec = true; // mark existing STYLE record
2960 return nXFId;
2963 static XclExpCellArea lcl_GetPatternFill_None()
2965 XclExpCellArea aFill;
2966 aFill.mnPattern = EXC_PATT_NONE;
2967 return aFill;
2970 static XclExpCellArea lcl_GetPatternFill_Gray125()
2972 XclExpCellArea aFill;
2973 aFill.mnPattern = EXC_PATT_12_5_PERC;
2974 aFill.mnForeColor = 0;
2975 aFill.mnBackColor = 0;
2976 return aFill;
2979 void XclExpXFBuffer::InsertDefaultRecords()
2981 maFills.push_back( lcl_GetPatternFill_None() );
2982 maFills.push_back( lcl_GetPatternFill_Gray125() );
2984 // index 0: default style
2985 if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScResId( STR_STYLENAME_STANDARD ), SfxStyleFamily::Para ) )
2987 XclExpXFRef xDefStyle = new XclExpXF( GetRoot(), *pDefStyleSheet );
2988 sal_uInt32 nXFId = AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2989 // mark this XF as not predefined, prevents overwriting
2990 maBuiltInMap[ nXFId ].mbPredefined = false;
2992 else
2994 OSL_FAIL( "XclExpXFBuffer::InsertDefaultRecords - default style not found" );
2995 XclExpXFRef xDefStyle = new XclExpDefaultXF( GetRoot(), false );
2996 xDefStyle->SetAllUsedFlags( true );
2997 AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
3000 // index 1-14: RowLevel and ColLevel styles (without STYLE records)
3001 XclExpDefaultXF aLevelStyle( GetRoot(), false );
3002 // RowLevel_1, ColLevel_1
3003 aLevelStyle.SetFont( 1 );
3004 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_ROWLEVEL, 0 );
3005 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_COLLEVEL, 0 );
3006 // RowLevel_2, ColLevel_2
3007 aLevelStyle.SetFont( 2 );
3008 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_ROWLEVEL, 1 );
3009 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_COLLEVEL, 1 );
3010 // RowLevel_3, ColLevel_3 ... RowLevel_7, ColLevel_7
3011 aLevelStyle.SetFont( 0 );
3012 for( sal_uInt8 nLevel = 2; nLevel < EXC_STYLE_LEVELCOUNT; ++nLevel )
3014 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_ROWLEVEL, nLevel );
3015 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_COLLEVEL, nLevel );
3018 // index 15: default hard cell format, placeholder to be able to add more built-in styles
3019 maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
3020 maXFFindMap[ToFindKey(*maXFList.GetRecord(maXFList.GetSize()-1))].push_back(maXFList.GetSize()-1);
3021 maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
3023 // index 16-20: other built-in styles
3025 XclExpDefaultXF aFormatStyle( GetRoot(), false );
3026 aFormatStyle.SetFont( 1 );
3027 aFormatStyle.SetNumFmt( 43 );
3028 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_COMMA );
3029 aFormatStyle.SetNumFmt( 41 );
3030 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_COMMA_0 );
3031 aFormatStyle.SetNumFmt( 44 );
3032 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_CURRENCY );
3033 aFormatStyle.SetNumFmt( 42 );
3034 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_CURRENCY_0 );
3035 aFormatStyle.SetNumFmt( 9 );
3036 AppendBuiltInXFWithStyle( new XclExpDefaultXF( std::move(aFormatStyle) ), EXC_STYLE_PERCENT );
3039 // other built-in style XF records (i.e. Hyperlink styles) are created on demand
3041 /* Insert the real default hard cell format -> 0 is document default pattern.
3042 Do it here (and not already above) to really have all built-in styles. */
3043 Insert( nullptr, GetDefApiScript() );
3046 void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
3048 OSL_ENSURE( nXFId < maXFIndexVec.size(), "XclExpXFBuffer::AppendXFIndex - XF ID out of range" );
3049 maXFIndexVec[ nXFId ] = static_cast< sal_uInt16 >( maSortedXFList.GetSize() );
3050 XclExpXFRef xXF = maXFList.GetRecord( nXFId );
3051 AddBorderAndFill( *xXF );
3052 maSortedXFList.AppendRecord( xXF );
3053 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::AppendXFIndex - XF not found" );
3056 void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
3058 if( std::none_of( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) )
3060 maBorders.push_back( rXF.GetBorderData() );
3063 if( std::none_of( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) )
3065 maFills.push_back( rXF.GetAreaData() );
3069 XclExpDxfs::XclExpDxfs( const XclExpRoot& rRoot )
3070 : XclExpRoot( rRoot ),
3071 mpKeywordTable( new NfKeywordTable )
3073 sal_Int32 nDxfId = 0;
3074 // Special number formatter for conversion.
3075 SvNumberFormatterPtr xFormatter(new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ));
3076 xFormatter->FillKeywordTableForExcel( *mpKeywordTable );
3078 SCTAB nTables = rRoot.GetDoc().GetTableCount();
3079 for(SCTAB nTab = 0; nTab < nTables; ++nTab)
3081 // Color filters
3082 std::vector<ScDBData*> pDBData = rRoot.GetDoc().GetDBCollection()->GetAllDBsFromTab(nTab);
3083 for (auto& pData : pDBData)
3085 ScRange aRange;
3086 pData->GetArea(aRange);
3087 for (auto nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); nCol++)
3089 ScFilterEntries aFilterEntries;
3090 rRoot.GetDoc().GetFilterEntriesArea(nCol, aRange.aStart.Row(),
3091 aRange.aEnd.Row(), nTab, true, aFilterEntries);
3093 // Excel has all filter values stored as foreground colors
3094 // Does not matter it is text color or cell background color
3095 for (auto& rColor : aFilterEntries.getBackgroundColors())
3097 if (!maColorToDxfId.emplace(rColor, nDxfId).second)
3098 continue;
3100 std::unique_ptr<XclExpCellArea> pExpCellArea(new XclExpCellArea(rColor, 0));
3101 maDxf.push_back(std::make_unique<XclExpDxf>(rRoot, std::move(pExpCellArea)));
3102 nDxfId++;
3104 for (auto& rColor : aFilterEntries.getTextColors())
3106 if (!maColorToDxfId.emplace(rColor, nDxfId).second)
3107 continue;
3109 std::unique_ptr<XclExpCellArea> pExpCellArea(new XclExpCellArea(rColor, 0));
3110 maDxf.push_back(std::make_unique<XclExpDxf>(rRoot, std::move(pExpCellArea)));
3111 nDxfId++;
3116 // Conditional formatting
3117 ScConditionalFormatList* pList = rRoot.GetDoc().GetCondFormList(nTab);
3118 if (pList)
3120 for (const auto& rxItem : *pList)
3122 size_t nEntryCount = rxItem->size();
3123 for (size_t nFormatEntry = 0; nFormatEntry < nEntryCount; ++nFormatEntry)
3125 const ScFormatEntry* pFormatEntry = rxItem->GetEntry(nFormatEntry);
3126 if (!pFormatEntry
3127 || (pFormatEntry->GetType() != ScFormatEntry::Type::Condition
3128 && pFormatEntry->GetType() != ScFormatEntry::Type::Date
3129 && pFormatEntry->GetType() != ScFormatEntry::Type::ExtCondition))
3130 continue;
3132 OUString aStyleName;
3133 if (pFormatEntry->GetType() == ScFormatEntry::Type::Condition
3134 || pFormatEntry->GetType() == ScFormatEntry::Type::ExtCondition)
3136 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
3137 aStyleName= pEntry->GetStyle();
3139 else
3141 const ScCondDateFormatEntry* pEntry = static_cast<const ScCondDateFormatEntry*>(pFormatEntry);
3142 aStyleName = pEntry->GetStyleName();
3145 if (maStyleNameToDxfId.emplace(aStyleName, nDxfId).second)
3147 SfxStyleSheetBase* pStyle = rRoot.GetDoc().GetStyleSheetPool()->Find(aStyleName, SfxStyleFamily::Para);
3148 if(!pStyle)
3149 continue;
3151 SfxItemSet& rSet = pStyle->GetItemSet();
3152 fillDxfFrom(rSet, xFormatter);
3153 nDxfId++;
3161 ScDPCollection* pCollection = rRoot.GetDoc().GetDPCollection();
3162 for (size_t nIndex = 0; nIndex < pCollection->GetCount(); nIndex++)
3164 const ScDPObject& rObject = (*pCollection)[nIndex];
3165 ScDPSaveData* pSaveData = rObject.GetSaveData();
3166 if (pSaveData && pSaveData->hasFormats())
3168 sc::PivotTableFormats const& rFormats = pSaveData->getFormats();
3169 for (sc::PivotTableFormat const& rFormat : rFormats.getVector())
3171 if (!rFormat.pPattern)
3172 continue;
3174 SfxItemSet& rItemSet = rFormat.pPattern->GetItemSet();
3175 fillDxfFrom(rItemSet, xFormatter);
3176 maPatternToDxfId.emplace(rFormat.pPattern.get(), nDxfId);
3177 nDxfId++;
3183 void XclExpDxfs::fillDxfFrom(SfxItemSet& rItemSet, SvNumberFormatterPtr& xFormatter)
3185 std::unique_ptr<XclExpCellBorder> pBorder(new XclExpCellBorder);
3186 if (!pBorder->FillFromItemSet(rItemSet, GetPalette(), GetBiff()))
3187 pBorder.reset();
3189 std::unique_ptr<XclExpCellAlign> pAlign(new XclExpCellAlign);
3190 if (!pAlign->FillFromItemSet(GetRoot(), rItemSet, false, GetBiff()))
3191 pAlign.reset();
3193 std::unique_ptr<XclExpCellProt> pCellProtection(new XclExpCellProt);
3194 if (!pCellProtection->FillFromItemSet(rItemSet))
3195 pCellProtection.reset();
3197 std::unique_ptr<XclExpColor> pColor(new XclExpColor);
3198 if (!pColor->FillFromItemSet(rItemSet))
3199 pColor.reset();
3201 std::unique_ptr<XclExpDxfFont> pFont(new XclExpDxfFont(GetRoot(), rItemSet));
3203 std::unique_ptr<XclExpNumFmt> pNumberFormat;
3204 if (const SfxUInt32Item* pPoolItem = rItemSet.GetItemIfSet(ATTR_VALUE_FORMAT))
3206 sal_uInt32 nScNumberFormat = pPoolItem->GetValue();
3207 sal_Int32 nXclNumberFormat = GetRoot().GetNumFmtBuffer().Insert(nScNumberFormat);
3208 pNumberFormat.reset(new XclExpNumFmt(nScNumberFormat, nXclNumberFormat, GetNumberFormatCode(*this, nScNumberFormat, xFormatter.get(), mpKeywordTable.get())));
3211 maDxf.push_back(std::make_unique<XclExpDxf>(GetRoot(), std::move(pAlign), std::move(pBorder),
3212 std::move(pFont), std::move(pNumberFormat), std::move(pCellProtection), std::move(pColor)));
3215 sal_Int32 XclExpDxfs::GetDxfId( const OUString& rStyleName ) const
3217 std::map<OUString, sal_Int32>::const_iterator itr = maStyleNameToDxfId.find(rStyleName);
3218 if(itr!= maStyleNameToDxfId.end())
3219 return itr->second;
3220 return -1;
3223 sal_Int32 XclExpDxfs::GetDxfByColor(Color aColor) const
3225 std::map<Color, sal_Int32>::const_iterator itr = maColorToDxfId.find(aColor);
3226 if (itr != maColorToDxfId.end())
3227 return itr->second;
3228 return -1;
3231 sal_Int32 XclExpDxfs::GetDxfIdForPattern(ScPatternAttr* pPattern) const
3233 auto iterator = maPatternToDxfId.find(pPattern);
3234 if (iterator != maPatternToDxfId.end())
3235 return iterator->second;
3236 return -1;
3239 void XclExpDxfs::addColor(Color aColor)
3241 maColorToDxfId.emplace(aColor, maDxf.size());
3243 std::unique_ptr<XclExpCellArea> pExpCellArea(new XclExpCellArea(aColor, 0));
3244 maDxf.push_back(std::make_unique<XclExpDxf>(GetRoot(), std::move(pExpCellArea)));
3247 void XclExpDxfs::SaveXml( XclExpXmlStream& rStrm )
3249 if(maDxf.empty())
3250 return;
3252 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3253 rStyleSheet->startElement(XML_dxfs, XML_count, OString::number(maDxf.size()));
3255 for ( auto& rxDxf : maDxf )
3257 rxDxf->SaveXml( rStrm );
3260 rStyleSheet->endElement( XML_dxfs );
3263 void XclExpDxfs::Finalize()
3265 for (auto& rxDxf : maDxf)
3267 rxDxf->SetFinalColors();
3271 XclExpDxf::XclExpDxf( const XclExpRoot& rRoot, std::unique_ptr<XclExpCellAlign> pAlign, std::unique_ptr<XclExpCellBorder> pBorder,
3272 std::unique_ptr<XclExpDxfFont> pFont, std::unique_ptr<XclExpNumFmt> pNumberFmt, std::unique_ptr<XclExpCellProt> pProt,
3273 std::unique_ptr<XclExpColor> pColor)
3274 : XclExpRoot( rRoot ),
3275 mpAlign(std::move(pAlign)),
3276 mpBorder(std::move(pBorder)),
3277 mpFont(std::move(pFont)),
3278 mpNumberFmt(std::move(pNumberFmt)),
3279 mpProt(std::move(pProt)),
3280 mpColor(std::move(pColor))
3284 XclExpDxf::XclExpDxf(const XclExpRoot& rRoot, std::unique_ptr<XclExpCellArea> pCellArea)
3285 : XclExpRoot(rRoot)
3286 , mpCellArea(std::move(pCellArea))
3290 XclExpDxf::~XclExpDxf()
3294 void XclExpDxf::SetFinalColors()
3296 if (mpBorder)
3298 mpBorder->SetFinalColors(GetPalette());
3302 void XclExpDxf::SaveXml( XclExpXmlStream& rStrm )
3304 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3305 rStyleSheet->startElement(XML_dxf);
3307 if (mpFont)
3308 mpFont->SaveXml(rStrm);
3309 if (mpNumberFmt)
3310 mpNumberFmt->SaveXml(rStrm);
3311 if (mpColor)
3312 mpColor->SaveXml(rStrm);
3313 if (mpAlign)
3314 mpAlign->SaveXml(rStrm);
3315 if (mpBorder)
3316 mpBorder->SaveXml(rStrm);
3317 if (mpProt)
3318 mpProt->SaveXml(rStrm);
3319 if (mpCellArea)
3320 mpCellArea->SaveXml(rStrm);
3321 rStyleSheet->endElement( XML_dxf );
3324 void XclExpDxf::SaveXmlExt( XclExpXmlStream& rStrm )
3326 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3327 rStyleSheet->startElementNS( XML_x14, XML_dxf );
3329 if (mpFont)
3330 mpFont->SaveXml(rStrm);
3331 if (mpNumberFmt)
3332 mpNumberFmt->SaveXml(rStrm);
3333 if (mpColor)
3334 mpColor->SaveXml(rStrm);
3335 if (mpAlign)
3336 mpAlign->SaveXml(rStrm);
3337 if (mpBorder)
3338 mpBorder->SaveXml(rStrm);
3339 if (mpProt)
3340 mpProt->SaveXml(rStrm);
3341 rStyleSheet->endElementNS( XML_x14, XML_dxf );
3345 XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
3346 : XclExpRoot( rRoot )
3350 void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
3352 sax_fastparser::FSHelperPtr aStyleSheet = rStrm.CreateOutputStream(
3353 u"xl/styles.xml"_ustr,
3354 u"styles.xml",
3355 rStrm.GetCurrentStream()->getOutputStream(),
3356 "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3357 oox::getRelationship(Relationship::STYLES));
3358 rStrm.PushStream( aStyleSheet );
3360 aStyleSheet->startElement(XML_styleSheet, XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)));
3362 CreateRecord( EXC_ID_FORMATLIST )->SaveXml( rStrm );
3363 CreateRecord( EXC_ID_FONTLIST )->SaveXml( rStrm );
3364 CreateRecord( EXC_ID_XFLIST )->SaveXml( rStrm );
3365 CreateRecord( EXC_ID_DXFS )->SaveXml( rStrm );
3366 CreateRecord( EXC_ID_PALETTE )->SaveXml( rStrm );
3368 aStyleSheet->endElement( XML_styleSheet );
3370 rStrm.PopStream();
3373 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */