LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / excel / xestyle.cxx
blob1dd6401a79eb0a2a0d9e594abd7bced5f411af5b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <xestyle.hxx>
23 #include <algorithm>
24 #include <iterator>
25 #include <com/sun/star/i18n/ScriptType.hpp>
26 #include <comphelper/processfactory.hxx>
27 #include <rtl/tencinfo.h>
28 #include <vcl/font.hxx>
29 #include <svl/languageoptions.hxx>
30 #include <scitems.hxx>
31 #include <editeng/borderline.hxx>
32 #include <editeng/boxitem.hxx>
33 #include <editeng/lineitem.hxx>
34 #include <editeng/brushitem.hxx>
35 #include <editeng/frmdiritem.hxx>
36 #include <editeng/fontitem.hxx>
37 #include <editeng/justifyitem.hxx>
38 #include <editeng/langitem.hxx>
39 #include <document.hxx>
40 #include <stlpool.hxx>
41 #include <stlsheet.hxx>
42 #include <patattr.hxx>
43 #include <attrib.hxx>
44 #include <globstr.hrc>
45 #include <scresid.hxx>
46 #include <xestring.hxx>
47 #include <xltools.hxx>
48 #include <conditio.hxx>
49 #include <dbdata.hxx>
50 #include <filterentries.hxx>
52 #include <o3tl/safeint.hxx>
53 #include <oox/export/utils.hxx>
54 #include <oox/token/tokens.hxx>
55 #include <oox/token/namespaces.hxx>
56 #include <oox/token/relationship.hxx>
57 #include <svl/numformat.hxx>
59 using namespace ::com::sun::star;
60 using namespace oox;
62 // PALETTE record - color information =========================================
64 namespace {
66 sal_uInt32 lclGetWeighting( XclExpColorType eType )
68 switch( eType )
70 case EXC_COLOR_CHARTLINE: return 1;
71 case EXC_COLOR_CELLBORDER:
72 case EXC_COLOR_CHARTAREA: return 2;
73 case EXC_COLOR_CELLTEXT:
74 case EXC_COLOR_CHARTTEXT:
75 case EXC_COLOR_CTRLTEXT: return 10;
76 case EXC_COLOR_TABBG:
77 case EXC_COLOR_CELLAREA: return 20;
78 case EXC_COLOR_GRID: return 50;
79 default: OSL_FAIL( "lclGetWeighting - unknown color type" );
81 return 1;
84 sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
86 sal_Int32 nDist = rColor1.GetRed() - rColor2.GetRed();
87 nDist *= nDist * 77;
88 sal_Int32 nDummy = rColor1.GetGreen() - rColor2.GetGreen();
89 nDist += nDummy * nDummy * 151;
90 nDummy = rColor1.GetBlue() - rColor2.GetBlue();
91 nDist += nDummy * nDummy * 28;
92 return nDist;
95 sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
97 sal_uInt8 nComp1Dist = ::std::min< sal_uInt8 >( nComp1, 0xFF - nComp1 );
98 sal_uInt8 nComp2Dist = ::std::min< sal_uInt8 >( nComp2, 0xFF - nComp2 );
99 if( nComp1Dist != nComp2Dist )
101 /* #i36945# One of the passed RGB components is nearer at the limits (0x00 or 0xFF).
102 Increase its weighting to prevent fading of the colors during reduction. */
103 const sal_uInt8& rnCompNearer = (nComp1Dist < nComp2Dist) ? nComp1 : nComp2;
104 sal_uInt32& rnWeight = (nComp1Dist < nComp2Dist) ? nWeight1 : nWeight2;
105 rnWeight *= ((rnCompNearer - 0x80L) * (rnCompNearer - 0x7FL) / 0x1000L + 1);
107 sal_uInt32 nWSum = nWeight1 + nWeight2;
108 return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
111 void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
113 rDest.SetRed( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetRed() ) + rSrc2.GetRed()) / 2 ) );
114 rDest.SetGreen( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetGreen() ) + rSrc2.GetGreen()) / 2 ) );
115 rDest.SetBlue( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetBlue() ) + rSrc2.GetBlue()) / 2 ) );
118 } // namespace
120 // additional classes for color reduction -------------------------------------
122 namespace {
124 /** Represents an entry in a color list.
126 The color stores a weighting value, which increases the more the color is
127 used in the document. Heavy-weighted colors will change less than others on
128 color reduction.
130 class XclListColor
132 private:
133 Color maColor; /// The color value of this palette entry.
134 sal_uInt32 mnColorId; /// Unique color ID for color reduction.
135 sal_uInt32 mnWeight; /// Weighting for color reduction.
136 bool mbBaseColor; /// true = Handle as base color, (don't remove/merge).
138 public:
139 explicit XclListColor( const Color& rColor, sal_uInt32 nColorId );
141 /** Returns the RGB color value of the color. */
142 const Color& GetColor() const { return maColor; }
143 /** Returns the unique ID of the color. */
144 sal_uInt32 GetColorId() const { return mnColorId; }
145 /** Returns the current weighting of the color. */
146 sal_uInt32 GetWeighting() const { return mnWeight; }
147 /** Returns true, if this color is a base color, i.e. it will not be removed or merged. */
148 bool IsBaseColor() const { return mbBaseColor; }
150 /** Adds the passed weighting to this color. */
151 void AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
152 /** Merges this color with rColor, regarding weighting settings. */
153 void Merge( const XclListColor& rColor );
156 XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
157 maColor( rColor ),
158 mnColorId( nColorId ),
159 mnWeight( 0 )
161 mbBaseColor =
162 ((rColor.GetRed() == 0x00) || (rColor.GetRed() == 0xFF)) &&
163 ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
164 ((rColor.GetBlue() == 0x00) || (rColor.GetBlue() == 0xFF));
167 void XclListColor::Merge( const XclListColor& rColor )
169 sal_uInt32 nWeight2 = rColor.GetWeighting();
170 // do not change RGB value of base colors
171 if( !mbBaseColor )
173 maColor.SetRed( lclGetMergedColorComp( maColor.GetRed(), mnWeight, rColor.maColor.GetRed(), nWeight2 ) );
174 maColor.SetGreen( lclGetMergedColorComp( maColor.GetGreen(), mnWeight, rColor.maColor.GetGreen(), nWeight2 ) );
175 maColor.SetBlue( lclGetMergedColorComp( maColor.GetBlue(), mnWeight, rColor.maColor.GetBlue(), nWeight2 ) );
177 AddWeighting( nWeight2 );
180 /** Data for each inserted original color, represented by a color ID. */
181 struct XclColorIdData
183 Color maColor; /// The original inserted color.
184 sal_uInt32 mnIndex; /// Maps current color ID to color list or export color vector.
185 /** Sets the contents of this struct. */
186 void Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
189 /** A color that will be written to the Excel file. */
190 struct XclPaletteColor
192 Color maColor; /// Resulting color to export.
193 bool mbUsed; /// true = Entry is used in the document.
195 explicit XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
196 void SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
199 /** Maps a color list index to a palette index.
200 @descr Used to remap the color ID data vector from list indexes to palette indexes. */
201 struct XclRemap
203 sal_uInt32 mnPalIndex; /// Index to palette.
204 bool mbProcessed; /// true = List color already processed.
206 explicit XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
207 void SetIndex( sal_uInt32 nPalIndex )
208 { mnPalIndex = nPalIndex; mbProcessed = true; }
211 /** Stores the nearest palette color index of a list color. */
212 struct XclNearest
214 sal_uInt32 mnPalIndex; /// Index to nearest palette color.
215 sal_Int32 mnDist; /// Distance to palette color.
217 explicit XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
220 } // namespace
222 class XclExpPaletteImpl
224 public:
225 explicit XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
227 /** Inserts the color into the list and updates weighting.
228 @param nAutoDefault The Excel palette index for automatic color.
229 @return A unique ID for this color. */
230 sal_uInt32 InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault = 0 );
231 /** Returns the color ID representing a fixed Excel palette index (i.e. for auto colors). */
232 static sal_uInt32 GetColorIdFromIndex( sal_uInt16 nIndex );
234 /** Reduces the color list to the maximum count of the current BIFF version. */
235 void Finalize();
237 /** Returns the Excel palette index of the color with passed color ID. */
238 sal_uInt16 GetColorIndex( sal_uInt32 nColorId ) const;
240 /** Returns a foreground and background color for the two passed color IDs.
241 @descr If rnXclPattern contains a solid pattern, this function tries to find
242 the two best fitting colors and a mix pattern (25%, 50% or 75%) for nForeColorId.
243 This will result in a better approximation to the passed foreground color. */
244 void GetMixedColors(
245 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
246 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const;
248 /** Returns the RGB color for a (non-zero-based) Excel palette entry.
249 @return The color from current or default palette or COL_AUTO, if nothing else found. */
250 Color GetColor( sal_uInt16 nXclIndex ) const;
252 /** Returns true, if all colors of the palette are equal to default palette colors. */
253 bool IsDefaultPalette() const;
254 /** Writes the color list (contents of the palette record) to the passed stream. */
255 void WriteBody( XclExpStream& rStrm );
256 void SaveXml( XclExpXmlStream& rStrm );
258 private:
259 /** Returns the Excel index of a 0-based color index. */
260 static sal_uInt16 GetXclIndex( sal_uInt32 nIndex )
261 { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
263 /** Returns the original inserted color represented by the color ID nColorId. */
264 const Color& GetOriginalColor( sal_uInt32 nColorId ) const;
266 /** Searches for rColor, returns the ordered insertion index for rColor in rnIndex. */
267 XclListColor* SearchListEntry( const Color& rColor, sal_uInt32& rnIndex );
268 /** Creates and inserts a new color list entry at the specified list position. */
269 XclListColor* CreateListEntry( const Color& rColor, sal_uInt32 nIndex );
271 /** Raw and fast reduction of the palette. */
272 void RawReducePalette( sal_uInt32 nPass );
273 /** Reduction of one color using advanced color merging based on color weighting. */
274 void ReduceLeastUsedColor();
276 /** Finds the least used color and returns its current list index. */
277 sal_uInt32 GetLeastUsedListColor() const;
278 /** Returns the list index of the color nearest to rColor.
279 @param nIgnore List index of a color which will be ignored.
280 @return The list index of the found color. */
281 sal_uInt32 GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const;
282 /** Returns the list index of the color nearest to the color with list index nIndex. */
283 sal_uInt32 GetNearestListColor( sal_uInt32 nIndex ) const;
285 /** Returns in rnIndex the palette index of the color nearest to rColor.
286 Searches for default colors only (colors never replaced).
287 @return The distance from passed color to found color. */
288 sal_Int32 GetNearestPaletteColor(
289 sal_uInt32& rnIndex,
290 const Color& rColor ) const;
291 /** Returns in rnFirst and rnSecond the palette indexes of the two colors nearest to rColor.
292 @return The minimum distance from passed color to found colors. */
293 sal_Int32 GetNearPaletteColors(
294 sal_uInt32& rnFirst, sal_uInt32& rnSecond,
295 const Color& rColor ) const;
297 private:
298 typedef std::vector< std::unique_ptr<XclListColor> > XclListColorList;
299 typedef std::shared_ptr< XclListColorList > XclListColorListRef;
301 const XclDefaultPalette& mrDefPal; /// The default palette for the current BIFF version.
302 XclListColorListRef mxColorList; /// Working color list.
303 std::vector< XclColorIdData >
304 maColorIdDataVec; /// Data of all CIDs.
305 std::vector< XclPaletteColor >
306 maPalette; /// Contains resulting colors to export.
307 sal_uInt32 mnLastIdx; /// Last insertion index for search opt.
310 const sal_uInt32 EXC_PAL_INDEXBASE = 0xFFFF0000;
311 const sal_uInt32 EXC_PAL_MAXRAWSIZE = 1024;
313 XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
314 mrDefPal( rDefPal ),
315 mxColorList( std::make_shared<XclListColorList>() ),
316 mnLastIdx( 0 )
318 // initialize maPalette with default colors
319 sal_uInt16 nCount = static_cast< sal_uInt16 >( mrDefPal.GetColorCount() );
320 maPalette.reserve( nCount );
321 for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
322 maPalette.emplace_back( mrDefPal.GetDefColor( GetXclIndex( nIdx ) ) );
324 InsertColor( COL_BLACK, EXC_COLOR_CELLTEXT );
327 sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
329 if( rColor == COL_AUTO )
330 return GetColorIdFromIndex( nAutoDefault );
332 sal_uInt32 nFoundIdx = 0;
333 XclListColor* pEntry = SearchListEntry( rColor, nFoundIdx );
334 if( !pEntry || (pEntry->GetColor() != rColor) )
335 pEntry = CreateListEntry( rColor, nFoundIdx );
336 pEntry->AddWeighting( lclGetWeighting( eType ) );
338 return pEntry->GetColorId();
341 sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
343 return EXC_PAL_INDEXBASE | nIndex;
346 void XclExpPaletteImpl::Finalize()
348 // --- build initial color ID data vector (maColorIdDataVec) ---
350 sal_uInt32 nCount = mxColorList->size();
351 maColorIdDataVec.resize( nCount );
352 for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
354 const XclListColor& listColor = *mxColorList->at( nIdx );
355 maColorIdDataVec[ listColor.GetColorId() ].Set( listColor.GetColor(), nIdx );
358 // --- loop as long as current color count does not fit into palette of current BIFF ---
360 // phase 1: raw reduction (performance reasons, #i36945#)
361 sal_uInt32 nPass = 0;
362 while( mxColorList->size() > EXC_PAL_MAXRAWSIZE )
363 RawReducePalette( nPass++ );
365 // phase 2: precise reduction using advanced color merging based on color weighting
366 while( mxColorList->size() > mrDefPal.GetColorCount() )
367 ReduceLeastUsedColor();
369 // --- use default palette and replace colors with nearest used colors ---
371 nCount = mxColorList->size();
372 std::vector< XclRemap > aRemapVec( nCount );
373 std::vector< XclNearest > aNearestVec( nCount );
375 // in each run: search the best fitting color and replace a default color with it
376 for( sal_uInt32 nRun = 0; nRun < nCount; ++nRun )
378 sal_uInt32 nIndex;
379 // find nearest unused default color for each unprocessed list color
380 for( nIndex = 0; nIndex < nCount; ++nIndex )
381 aNearestVec[ nIndex ].mnDist = aRemapVec[ nIndex ].mbProcessed ? SAL_MAX_INT32 :
382 GetNearestPaletteColor( aNearestVec[ nIndex ].mnPalIndex, mxColorList->at( nIndex )->GetColor() );
383 // find the list color which is nearest to a default color
384 sal_uInt32 nFound = 0;
385 for( nIndex = 1; nIndex < nCount; ++nIndex )
386 if( aNearestVec[ nIndex ].mnDist < aNearestVec[ nFound ].mnDist )
387 nFound = nIndex;
388 // replace default color with list color
389 sal_uInt32 nNearest = aNearestVec[ nFound ].mnPalIndex;
390 OSL_ENSURE( nNearest < maPalette.size(), "XclExpPaletteImpl::Finalize - algorithm error" );
391 maPalette[ nNearest ].SetColor( mxColorList->at( nFound )->GetColor() );
392 aRemapVec[ nFound ].SetIndex( nNearest );
395 // remap color ID data map (maColorIdDataVec) from list indexes to palette indexes
396 for( auto& rColorIdData : maColorIdDataVec )
397 rColorIdData.mnIndex = aRemapVec[ rColorIdData.mnIndex ].mnPalIndex;
400 sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
402 sal_uInt16 nRet = 0;
403 if( nColorId >= EXC_PAL_INDEXBASE )
404 nRet = static_cast< sal_uInt16 >( nColorId & ~EXC_PAL_INDEXBASE );
405 else if( nColorId < maColorIdDataVec.size() )
406 nRet = GetXclIndex( maColorIdDataVec[ nColorId ].mnIndex );
407 return nRet;
410 void XclExpPaletteImpl::GetMixedColors(
411 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
412 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
414 rnXclForeIx = GetColorIndex( nForeColorId );
415 rnXclBackIx = GetColorIndex( nBackColorId );
416 if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
417 return;
419 // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
421 sal_uInt32 nIndex1, nIndex2;
422 Color aForeColor( GetOriginalColor( nForeColorId ) );
423 sal_Int32 nFirstDist = GetNearPaletteColors( nIndex1, nIndex2, aForeColor );
424 if( (nIndex1 >= maPalette.size()) || (nIndex2 >= maPalette.size()) )
425 return;
427 Color aColorArr[ 5 ];
428 aColorArr[ 0 ] = maPalette[ nIndex1 ].maColor;
429 aColorArr[ 4 ] = maPalette[ nIndex2 ].maColor;
430 lclSetMixedColor( aColorArr[ 2 ], aColorArr[ 0 ], aColorArr[ 4 ] );
431 lclSetMixedColor( aColorArr[ 1 ], aColorArr[ 0 ], aColorArr[ 2 ] );
432 lclSetMixedColor( aColorArr[ 3 ], aColorArr[ 2 ], aColorArr[ 4 ] );
434 sal_Int32 nMinDist = nFirstDist;
435 sal_uInt32 nMinIndex = 0;
436 for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
438 sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
439 if( nDist < nMinDist )
441 nMinDist = nDist;
442 nMinIndex = nCnt;
445 rnXclForeIx = GetXclIndex( nIndex1 );
446 rnXclBackIx = GetXclIndex( nIndex2 );
447 if( nMinDist < nFirstDist )
449 switch( nMinIndex )
451 case 1: rnXclPattern = EXC_PATT_75_PERC; break;
452 case 2: rnXclPattern = EXC_PATT_50_PERC; break;
453 case 3: rnXclPattern = EXC_PATT_25_PERC; break;
458 Color XclExpPaletteImpl::GetColor( sal_uInt16 nXclIndex ) const
460 if( nXclIndex >= EXC_COLOR_USEROFFSET )
462 sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
463 if( nIdx < maPalette.size() )
464 return maPalette[ nIdx ].maColor;
466 return mrDefPal.GetDefColor( nXclIndex );
469 bool XclExpPaletteImpl::IsDefaultPalette() const
471 bool bDefault = true;
472 for( sal_uInt32 nIdx = 0, nSize = static_cast< sal_uInt32 >( maPalette.size() ); bDefault && (nIdx < nSize); ++nIdx )
473 bDefault = maPalette[ nIdx ].maColor == mrDefPal.GetDefColor( GetXclIndex( nIdx ) );
474 return bDefault;
477 void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
479 rStrm << static_cast< sal_uInt16 >( maPalette.size() );
480 for( const auto& rColor : maPalette )
481 rStrm << rColor.maColor;
484 void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
486 if( maPalette.empty() )
487 return;
489 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
490 rStyleSheet->startElement(XML_colors);
491 rStyleSheet->startElement(XML_indexedColors);
492 for( const auto& rColor : maPalette )
493 rStyleSheet->singleElement(XML_rgbColor, XML_rgb, XclXmlUtils::ToOString(rColor.maColor));
494 rStyleSheet->endElement( XML_indexedColors );
495 rStyleSheet->endElement( XML_colors );
498 const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
500 if( nColorId < maColorIdDataVec.size() )
501 return maColorIdDataVec[ nColorId ].maColor;
502 return maPalette[ 0 ].maColor;
505 XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
507 rnIndex = 0;
509 if (mxColorList->empty())
510 return nullptr;
512 XclListColor* pEntry = nullptr;
514 // search optimization for equal-colored objects occurring repeatedly
515 if (mnLastIdx < mxColorList->size())
517 pEntry = (*mxColorList)[mnLastIdx].get();
518 if( pEntry->GetColor() == rColor )
520 rnIndex = mnLastIdx;
521 return pEntry;
525 // binary search for color
526 sal_uInt32 nBegIdx = 0;
527 sal_uInt32 nEndIdx = mxColorList->size();
528 bool bFound = false;
529 while( !bFound && (nBegIdx < nEndIdx) )
531 rnIndex = (nBegIdx + nEndIdx) / 2;
532 pEntry = (*mxColorList)[rnIndex].get();
533 bFound = pEntry->GetColor() == rColor;
534 if( !bFound )
536 if( pEntry->GetColor() < rColor )
537 nBegIdx = rnIndex + 1;
538 else
539 nEndIdx = rnIndex;
543 // not found - use end of range as new insertion position
544 if( !bFound )
545 rnIndex = nEndIdx;
547 mnLastIdx = rnIndex;
548 return pEntry;
551 XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
553 XclListColor* pEntry = new XclListColor( rColor, mxColorList->size() );
554 mxColorList->insert(mxColorList->begin() + nIndex, std::unique_ptr<XclListColor>(pEntry));
555 return pEntry;
558 void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
560 /* Fast palette reduction - in each call of this function one RGB component
561 of each color is reduced to a lower number of distinct values.
562 Pass 0: Blue is reduced to 128 distinct values.
563 Pass 1: Red is reduced to 128 distinct values.
564 Pass 2: Green is reduced to 128 distinct values.
565 Pass 3: Blue is reduced to 64 distinct values.
566 Pass 4: Red is reduced to 64 distinct values.
567 Pass 5: Green is reduced to 64 distinct values.
568 And so on...
571 XclListColorListRef xOldList = mxColorList;
572 mxColorList = std::make_shared<XclListColorList>();
574 // maps old list indexes to new list indexes, used to update maColorIdDataVec
575 ScfUInt32Vec aListIndexMap;
576 aListIndexMap.reserve( xOldList->size() );
578 // preparations
579 sal_uInt8 nR, nG, nB;
580 sal_uInt8& rnComp = ((nPass % 3 == 0) ? nB : ((nPass % 3 == 1) ? nR : nG));
581 nPass /= 3;
582 OSL_ENSURE( nPass < 7, "XclExpPaletteImpl::RawReducePalette - reduction not terminated" );
584 static const sal_uInt8 spnFactor2[] = { 0x81, 0x82, 0x84, 0x88, 0x92, 0xAA, 0xFF };
585 sal_uInt8 nFactor1 = static_cast< sal_uInt8 >( 0x02 << nPass );
586 sal_uInt8 nFactor2 = spnFactor2[ nPass ];
587 sal_uInt8 nFactor3 = static_cast< sal_uInt8 >( 0x40 >> nPass );
589 // process each color in the old color list
590 for(const std::unique_ptr<XclListColor> & pOldColor : *xOldList)
592 // get the old list entry
593 const XclListColor* pOldEntry = pOldColor.get();
594 nR = pOldEntry->GetColor().GetRed();
595 nG = pOldEntry->GetColor().GetGreen();
596 nB = pOldEntry->GetColor().GetBlue();
598 /* Calculate the new RGB component (rnComp points to one of nR, nG, nB).
599 Using integer arithmetic with its rounding errors, the results of
600 this calculation are always exactly in the range 0x00 to 0xFF
601 (simply cutting the lower bits would darken the colors slightly). */
602 sal_uInt32 nNewComp = rnComp;
603 nNewComp /= nFactor1;
604 nNewComp *= nFactor2;
605 nNewComp /= nFactor3;
606 rnComp = static_cast< sal_uInt8 >( nNewComp );
607 Color aNewColor( nR, nG, nB );
609 // find or insert the new color
610 sal_uInt32 nFoundIdx = 0;
611 XclListColor* pNewEntry = SearchListEntry( aNewColor, nFoundIdx );
612 if( !pNewEntry || (pNewEntry->GetColor() != aNewColor) )
613 pNewEntry = CreateListEntry( aNewColor, nFoundIdx );
614 pNewEntry->AddWeighting( pOldEntry->GetWeighting() );
615 aListIndexMap.push_back( nFoundIdx );
618 // update color ID data map (maps color IDs to color list indexes), replace old by new list indexes
619 for( auto& rColorIdData : maColorIdDataVec )
620 rColorIdData.mnIndex = aListIndexMap[ rColorIdData.mnIndex ];
623 void XclExpPaletteImpl::ReduceLeastUsedColor()
625 // find a list color to remove
626 sal_uInt32 nRemove = GetLeastUsedListColor();
627 // find its nearest neighbor
628 sal_uInt32 nKeep = GetNearestListColor( nRemove );
630 // merge both colors to one color, remove one color from list
631 XclListColor* pKeepEntry = mxColorList->at(nKeep).get();
632 XclListColor* pRemoveEntry = mxColorList->at(nRemove).get();
633 if( !(pKeepEntry && pRemoveEntry) )
634 return;
636 // merge both colors (if pKeepEntry is a base color, it will not change)
637 pKeepEntry->Merge( *pRemoveEntry );
638 // remove the less used color, adjust nKeep index if kept color follows removed color
639 XclListColorList::iterator itr = mxColorList->begin();
640 ::std::advance(itr, nRemove);
641 mxColorList->erase(itr);
642 if( nKeep > nRemove ) --nKeep;
644 // recalculate color ID data map (maps color IDs to color list indexes)
645 for( auto& rColorIdData : maColorIdDataVec )
647 if( rColorIdData.mnIndex > nRemove )
648 --rColorIdData.mnIndex;
649 else if( rColorIdData.mnIndex == nRemove )
650 rColorIdData.mnIndex = nKeep;
654 sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
656 sal_uInt32 nFound = 0;
657 sal_uInt32 nMinW = SAL_MAX_UINT32;
659 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
661 XclListColor& rEntry = *mxColorList->at( nIdx );
662 // ignore the base colors
663 if( !rEntry.IsBaseColor() && (rEntry.GetWeighting() < nMinW) )
665 nFound = nIdx;
666 nMinW = rEntry.GetWeighting();
669 return nFound;
672 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
674 sal_uInt32 nFound = 0;
675 sal_Int32 nMinD = SAL_MAX_INT32;
677 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
679 if( nIdx != nIgnore )
681 if( XclListColor* pEntry = mxColorList->at(nIdx).get() )
683 sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
684 if( nDist < nMinD )
686 nFound = nIdx;
687 nMinD = nDist;
692 return nFound;
695 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
697 if (nIndex >= mxColorList->size())
698 return 0;
699 XclListColor* pEntry = mxColorList->at(nIndex).get();
700 return GetNearestListColor( pEntry->GetColor(), nIndex );
703 sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
704 sal_uInt32& rnIndex, const Color& rColor ) const
706 rnIndex = 0;
707 sal_Int32 nDist = SAL_MAX_INT32;
709 sal_uInt32 nPaletteIndex = 0;
710 for( const auto& rPaletteColor : maPalette )
712 if( !rPaletteColor.mbUsed )
714 sal_Int32 nCurrDist = lclGetColorDistance( rColor, rPaletteColor.maColor );
715 if( nCurrDist < nDist )
717 rnIndex = nPaletteIndex;
718 nDist = nCurrDist;
721 ++nPaletteIndex;
723 return nDist;
726 sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
727 sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
729 rnFirst = rnSecond = 0;
730 sal_Int32 nDist1 = SAL_MAX_INT32;
731 sal_Int32 nDist2 = SAL_MAX_INT32;
733 sal_uInt32 nPaletteIndex = 0;
734 for( const auto& rPaletteColor : maPalette )
736 sal_Int32 nCurrDist = lclGetColorDistance( rColor, rPaletteColor.maColor );
737 if( nCurrDist < nDist1 )
739 rnSecond = rnFirst;
740 nDist2 = nDist1;
741 rnFirst = nPaletteIndex;
742 nDist1 = nCurrDist;
744 else if( nCurrDist < nDist2 )
746 rnSecond = nPaletteIndex;
747 nDist2 = nCurrDist;
749 ++nPaletteIndex;
751 return nDist1;
754 XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
755 XclDefaultPalette( rRoot ),
756 XclExpRecord( EXC_ID_PALETTE )
758 mxImpl = std::make_shared<XclExpPaletteImpl>( *this );
759 SetRecSize( GetColorCount() * 4 + 2 );
762 XclExpPalette::~XclExpPalette()
766 sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
768 return mxImpl->InsertColor( rColor, eType, nAutoDefault );
771 sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
773 return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
776 void XclExpPalette::Finalize()
778 mxImpl->Finalize();
781 sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
783 return mxImpl->GetColorIndex( nColorId );
786 void XclExpPalette::GetMixedColors(
787 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
788 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
790 return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
793 Color XclExpPalette::GetColor( sal_uInt16 nXclIndex ) const
795 return mxImpl->GetColor( nXclIndex );
798 void XclExpPalette::Save( XclExpStream& rStrm )
800 if( !mxImpl->IsDefaultPalette() )
801 XclExpRecord::Save( rStrm );
804 void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
806 if( !mxImpl->IsDefaultPalette() )
807 mxImpl->SaveXml( rStrm );
810 void XclExpPalette::WriteBody( XclExpStream& rStrm )
812 mxImpl->WriteBody( rStrm );
815 // FONT record - font information =============================================
817 namespace {
819 typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
821 sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
822 const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
824 if( ScfTools::CheckItem( rItemSet, rWAS1.first, false ) ) return rWAS1.second;
825 if( ScfTools::CheckItem( rItemSet, rWAS2.first, false ) ) return rWAS2.second;
826 if( ScfTools::CheckItem( rItemSet, rWAS3.first, false ) ) return rWAS3.second;
827 return 0;
830 } // namespace
832 sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
834 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
836 /* #i17050# #i107170# We need to determine which font items are set in the
837 item set, and which script type we should prefer according to the
838 current language settings. */
840 static const WhichAndScript WAS_LATIN( ATTR_FONT, css::i18n::ScriptType::LATIN );
841 static const WhichAndScript WAS_ASIAN( ATTR_CJK_FONT, css::i18n::ScriptType::ASIAN );
842 static const WhichAndScript WAS_CMPLX( ATTR_CTL_FONT, css::i18n::ScriptType::COMPLEX );
844 /* do not let a font from a parent style override an explicit
845 cell font. */
847 sal_Int16 nDefScript = rRoot.GetDefApiScript();
848 sal_Int16 nScript = 0;
849 const SfxItemSet* pCurrSet = &rItemSet;
851 while( (nScript == 0) && pCurrSet )
853 switch( nDefScript )
855 case ApiScriptType::LATIN:
856 nScript = lclCheckFontItems( *pCurrSet, WAS_LATIN, WAS_CMPLX, WAS_ASIAN );
857 break;
858 case ApiScriptType::ASIAN:
859 nScript = lclCheckFontItems( *pCurrSet, WAS_ASIAN, WAS_CMPLX, WAS_LATIN );
860 break;
861 case ApiScriptType::COMPLEX:
862 nScript = lclCheckFontItems( *pCurrSet, WAS_CMPLX, WAS_ASIAN, WAS_LATIN );
863 break;
864 default:
865 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
866 nScript = ApiScriptType::LATIN;
868 pCurrSet = pCurrSet->GetParent();
871 if (nScript == 0)
872 nScript = nDefScript;
874 if (nScript == 0)
876 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
877 nScript = ApiScriptType::LATIN;
880 return nScript;
883 vcl::Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
885 // if WEAK is passed, guess script type from existing items in the item set
886 if( nScript == css::i18n::ScriptType::WEAK )
887 nScript = GetFirstUsedScript( rRoot, rItemSet );
889 // convert to core script type constants
890 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
892 // fill the font object
893 vcl::Font aFont;
894 ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW, nullptr, nullptr, nullptr, nScScript );
895 return aFont;
898 ScDxfFont XclExpFontHelper::GetDxfFontFromItemSet(const XclExpRoot& rRoot, const SfxItemSet& rItemSet)
900 sal_Int16 nScript = GetFirstUsedScript(rRoot, rItemSet);
902 // convert to core script type constants
903 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
904 return ScPatternAttr::GetDxfFont(rItemSet, nScScript);
907 bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
909 static const sal_uInt16 pnCommonIds[] = {
910 ATTR_FONT_UNDERLINE, ATTR_FONT_CROSSEDOUT, ATTR_FONT_CONTOUR,
911 ATTR_FONT_SHADOWED, ATTR_FONT_COLOR, ATTR_FONT_LANGUAGE, 0 };
912 static const sal_uInt16 pnLatinIds[] = {
913 ATTR_FONT, ATTR_FONT_HEIGHT, ATTR_FONT_WEIGHT, ATTR_FONT_POSTURE, 0 };
914 static const sal_uInt16 pnAsianIds[] = {
915 ATTR_CJK_FONT, ATTR_CJK_FONT_HEIGHT, ATTR_CJK_FONT_WEIGHT, ATTR_CJK_FONT_POSTURE, 0 };
916 static const sal_uInt16 pnComplexIds[] = {
917 ATTR_CTL_FONT, ATTR_CTL_FONT_HEIGHT, ATTR_CTL_FONT_WEIGHT, ATTR_CTL_FONT_POSTURE, 0 };
919 bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
920 if( !bUsed )
922 namespace ApiScriptType = css::i18n::ScriptType;
923 // if WEAK is passed, guess script type from existing items in the item set
924 if( nScript == ApiScriptType::WEAK )
925 nScript = GetFirstUsedScript( rRoot, rItemSet );
926 // check the correct items
927 switch( nScript )
929 case ApiScriptType::LATIN: bUsed = ScfTools::CheckItems( rItemSet, pnLatinIds, bDeep ); break;
930 case ApiScriptType::ASIAN: bUsed = ScfTools::CheckItems( rItemSet, pnAsianIds, bDeep ); break;
931 case ApiScriptType::COMPLEX: bUsed = ScfTools::CheckItems( rItemSet, pnComplexIds, bDeep ); break;
932 default: OSL_FAIL( "XclExpFontHelper::CheckItems - unknown script type" );
935 return bUsed;
938 namespace {
940 sal_uInt32 lclCalcHash( const XclFontData& rFontData )
942 sal_uInt32 nHash = rFontData.maName.getLength();
943 nHash += sal_uInt32(rFontData.maColor) * 2;
944 nHash += rFontData.mnWeight * 3;
945 nHash += rFontData.mnCharSet * 5;
946 nHash += rFontData.mnFamily * 7;
947 nHash += rFontData.mnHeight * 11;
948 nHash += rFontData.mnUnderline * 13;
949 nHash += rFontData.mnEscapem * 17;
950 if( rFontData.mbItalic ) nHash += 19;
951 if( rFontData.mbStrikeout ) nHash += 23;
952 if( rFontData.mbOutline ) nHash += 29;
953 if( rFontData.mbShadow ) nHash += 31;
954 return nHash;
957 } // namespace
959 XclExpFont::XclExpFont( const XclExpRoot& rRoot,
960 const XclFontData& rFontData, XclExpColorType eColorType ) :
961 XclExpRecord( EXC_ID2_FONT, 14 ),
962 XclExpRoot( rRoot ),
963 maData( rFontData )
965 // insert font color into palette
966 mnColorId = rRoot.GetPalette().InsertColor( rFontData.maColor, eColorType, EXC_COLOR_FONTAUTO );
967 // hash value for faster comparison
968 mnHash = lclCalcHash( maData );
969 // record size
970 sal_Int32 nStrLen = maData.maName.getLength();
971 SetRecSize( ((GetBiff() == EXC_BIFF8) ? (nStrLen * 2 + 1) : nStrLen) + 15 );
974 bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
976 return (mnHash == nHash) && (maData == rFontData);
979 void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
981 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
982 rStyleSheet->startElement(XML_font);
983 XclXmlUtils::WriteFontData( rStyleSheet, maData, XML_name );
984 // OOXTODO: XML_scheme; //scheme/@val values: "major", "minor", "none"
985 rStyleSheet->endElement( XML_font );
988 // private --------------------------------------------------------------------
990 void XclExpFont::WriteBody( XclExpStream& rStrm )
992 sal_uInt16 nAttr = EXC_FONTATTR_NONE;
993 ::set_flag( nAttr, EXC_FONTATTR_ITALIC, maData.mbItalic );
994 if( maData.mnUnderline > 0 )
995 ::set_flag( nAttr, EXC_FONTATTR_UNDERLINE, true );
996 ::set_flag( nAttr, EXC_FONTATTR_STRIKEOUT, maData.mbStrikeout );
997 ::set_flag( nAttr, EXC_FONTATTR_OUTLINE, maData.mbOutline );
998 ::set_flag( nAttr, EXC_FONTATTR_SHADOW, maData.mbShadow );
1000 OSL_ENSURE( maData.maName.getLength() < 256, "XclExpFont::WriteBody - font name too long" );
1001 XclExpString aFontName;
1002 if( GetBiff() <= EXC_BIFF5 )
1003 aFontName.AssignByte( maData.maName, GetTextEncoding(), XclStrFlags::EightBitLength );
1004 else
1005 aFontName.Assign( maData.maName, XclStrFlags::ForceUnicode | XclStrFlags::EightBitLength );
1007 rStrm << maData.mnHeight
1008 << nAttr
1009 << GetPalette().GetColorIndex( mnColorId )
1010 << maData.mnWeight
1011 << maData.mnEscapem
1012 << maData.mnUnderline
1013 << maData.mnFamily
1014 << maData.mnCharSet
1015 << sal_uInt8( 0 )
1016 << aFontName;
1019 XclExpDxfFont::XclExpDxfFont(const XclExpRoot& rRoot,
1020 const SfxItemSet& rItemSet):
1021 XclExpRoot(rRoot)
1023 maDxfData = XclExpFontHelper::GetDxfFontFromItemSet(rRoot, rItemSet);
1026 namespace {
1028 const char* getUnderlineOOXValue(FontLineStyle eUnderline)
1030 switch (eUnderline)
1032 case LINESTYLE_NONE:
1033 case LINESTYLE_DONTKNOW:
1034 return "none";
1035 case LINESTYLE_DOUBLE:
1036 case LINESTYLE_DOUBLEWAVE:
1037 return "double";
1038 default:
1039 return "single";
1043 const char* getFontFamilyOOXValue(FontFamily eValue)
1045 switch (eValue)
1047 case FAMILY_DONTKNOW:
1048 return "0";
1049 case FAMILY_SWISS:
1050 case FAMILY_SYSTEM:
1051 return "2";
1052 case FAMILY_ROMAN:
1053 return "1";
1054 case FAMILY_SCRIPT:
1055 return "4";
1056 case FAMILY_MODERN:
1057 return "3";
1058 case FAMILY_DECORATIVE:
1059 return "5";
1060 default:
1061 return "0";
1067 void XclExpDxfFont::SaveXml(XclExpXmlStream& rStrm)
1069 if (maDxfData.isEmpty())
1070 return;
1072 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1073 rStyleSheet->startElement(XML_font);
1075 if (maDxfData.pFontAttr)
1077 OUString aFontName = (*maDxfData.pFontAttr)->GetFamilyName();
1079 aFontName = XclTools::GetXclFontName(aFontName);
1080 if (!aFontName.isEmpty())
1082 rStyleSheet->singleElement(XML_name, XML_val, aFontName);
1085 rtl_TextEncoding eTextEnc = (*maDxfData.pFontAttr)->GetCharSet();
1086 sal_uInt8 nExcelCharSet = rtl_getBestWindowsCharsetFromTextEncoding(eTextEnc);
1087 if (nExcelCharSet)
1089 rStyleSheet->singleElement(XML_charset, XML_val, OString::number(nExcelCharSet));
1092 FontFamily eFamily = (*maDxfData.pFontAttr)->GetFamily();
1093 const char* pVal = getFontFamilyOOXValue(eFamily);
1094 if (pVal)
1096 rStyleSheet->singleElement(XML_family, XML_val, pVal);
1100 if (maDxfData.eWeight)
1102 rStyleSheet->singleElement(XML_b,
1103 XML_val, ToPsz10(*maDxfData.eWeight != WEIGHT_NORMAL));
1106 if (maDxfData.eItalic)
1108 bool bItalic = (*maDxfData.eItalic == ITALIC_OBLIQUE) || (*maDxfData.eItalic == ITALIC_NORMAL);
1109 rStyleSheet->singleElement(XML_i, XML_val, ToPsz10(bItalic));
1112 if (maDxfData.eStrike)
1114 bool bStrikeout =
1115 (*maDxfData.eStrike == STRIKEOUT_SINGLE) || (*maDxfData.eStrike == STRIKEOUT_DOUBLE) ||
1116 (*maDxfData.eStrike == STRIKEOUT_BOLD) || (*maDxfData.eStrike == STRIKEOUT_SLASH) ||
1117 (*maDxfData.eStrike == STRIKEOUT_X);
1119 rStyleSheet->singleElement(XML_strike, XML_val, ToPsz10(bStrikeout));
1122 if (maDxfData.bOutline)
1124 rStyleSheet->singleElement(XML_outline, XML_val, ToPsz10(*maDxfData.bOutline));
1127 if (maDxfData.bShadow)
1129 rStyleSheet->singleElement(XML_shadow, XML_val, ToPsz10(*maDxfData.bShadow));
1132 if (maDxfData.aColor)
1134 rStyleSheet->singleElement(XML_color,
1135 XML_rgb, XclXmlUtils::ToOString(*maDxfData.aColor));
1138 if (maDxfData.nFontHeight)
1140 rStyleSheet->singleElement(XML_sz,
1141 XML_val, OString::number(*maDxfData.nFontHeight/20));
1144 if (maDxfData.eUnder)
1146 const char* pVal = getUnderlineOOXValue(*maDxfData.eUnder);
1147 rStyleSheet->singleElement(XML_u, XML_val, pVal);
1150 rStyleSheet->endElement(XML_font);
1153 XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
1154 XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
1158 bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
1160 return false;
1163 void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
1165 // do nothing
1168 XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
1169 XclExpRoot( rRoot ),
1170 mnXclMaxSize( 0 )
1172 switch( GetBiff() )
1174 case EXC_BIFF4: mnXclMaxSize = EXC_FONT_MAXCOUNT4; break;
1175 case EXC_BIFF5: mnXclMaxSize = EXC_FONT_MAXCOUNT5; break;
1176 case EXC_BIFF8: mnXclMaxSize = EXC_FONT_MAXCOUNT8; break;
1177 default: DBG_ERROR_BIFF();
1179 InitDefaultFonts();
1182 const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
1184 return maFontList.GetRecord( nXclFont );
1187 const XclFontData& XclExpFontBuffer::GetAppFontData() const
1189 return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
1192 sal_uInt16 XclExpFontBuffer::Insert(
1193 const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
1195 if( bAppFont )
1197 XclExpFontRef xFont = new XclExpFont( GetRoot(), rFontData, eColorType );
1198 maFontList.ReplaceRecord( xFont, EXC_FONT_APP );
1199 // set width of '0' character for column width export
1200 SetCharWidth( xFont->GetFontData() );
1201 return EXC_FONT_APP;
1204 size_t nPos = Find( rFontData );
1205 if( nPos == EXC_FONTLIST_NOTFOUND )
1207 // not found in buffer - create new font
1208 size_t nSize = maFontList.GetSize();
1209 if( nSize < mnXclMaxSize )
1211 // possible to insert
1212 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1213 nPos = nSize; // old size is last position now
1215 else
1217 // buffer is full - ignore new font, use default font
1218 nPos = EXC_FONT_APP;
1221 return static_cast< sal_uInt16 >( nPos );
1224 sal_uInt16 XclExpFontBuffer::Insert(
1225 const SvxFont& rFont, XclExpColorType eColorType )
1227 return Insert( XclFontData( rFont ), eColorType );
1230 sal_uInt16 XclExpFontBuffer::Insert( const SfxItemSet& rItemSet,
1231 sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1233 // #i17050# script type now provided by caller
1234 vcl::Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rItemSet, nScript );
1235 return Insert( XclFontData( aFont ), eColorType, bAppFont );
1238 void XclExpFontBuffer::Save( XclExpStream& rStrm )
1240 maFontList.Save( rStrm );
1243 void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
1245 if( maFontList.IsEmpty() )
1246 return;
1248 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1249 rStyleSheet->startElement(XML_fonts, XML_count, OString::number(maFontList.GetSize()));
1251 maFontList.SaveXml( rStrm );
1253 rStyleSheet->endElement( XML_fonts );
1256 // private --------------------------------------------------------------------
1258 void XclExpFontBuffer::InitDefaultFonts()
1260 XclFontData aFontData;
1261 aFontData.maName = "Arial";
1262 aFontData.SetScFamily( FAMILY_DONTKNOW );
1263 aFontData.SetFontEncoding( ScfTools::GetSystemTextEncoding() );
1264 aFontData.SetScHeight( 200 ); // 200 twips = 10 pt
1265 aFontData.SetScWeight( WEIGHT_NORMAL );
1267 switch( GetBiff() )
1269 case EXC_BIFF5:
1271 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1272 aFontData.SetScWeight( WEIGHT_BOLD );
1273 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1274 aFontData.SetScWeight( WEIGHT_NORMAL );
1275 aFontData.SetScPosture( ITALIC_NORMAL );
1276 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1277 aFontData.SetScWeight( WEIGHT_BOLD );
1278 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1279 // the blind font with index 4
1280 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1281 // already add the first user defined font (Excel does it too)
1282 aFontData.SetScWeight( WEIGHT_NORMAL );
1283 aFontData.SetScPosture( ITALIC_NONE );
1284 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1286 break;
1287 case EXC_BIFF8:
1289 XclExpFontRef xFont = new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT );
1290 maFontList.AppendRecord( xFont );
1291 maFontList.AppendRecord( xFont );
1292 maFontList.AppendRecord( xFont );
1293 maFontList.AppendRecord( xFont );
1294 if( GetOutput() == EXC_OUTPUT_BINARY )
1295 // the blind font with index 4
1296 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1298 break;
1299 default:
1300 DBG_ERROR_BIFF();
1304 size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
1306 sal_uInt32 nHash = lclCalcHash( rFontData );
1307 for( size_t nPos = 0, nSize = maFontList.GetSize(); nPos < nSize; ++nPos )
1308 if( maFontList.GetRecord( nPos )->Equals( rFontData, nHash ) )
1309 return nPos;
1310 return EXC_FONTLIST_NOTFOUND;
1313 // FORMAT record - number formats =============================================
1315 namespace {
1317 /** Predicate for search algorithm. */
1318 struct XclExpNumFmtPred
1320 sal_uInt32 mnScNumFmt;
1321 explicit XclExpNumFmtPred( sal_uInt32 nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
1322 bool operator()( const XclExpNumFmt& rFormat ) const
1323 { return rFormat.mnScNumFmt == mnScNumFmt; }
1328 void XclExpNumFmt::SaveXml( XclExpXmlStream& rStrm )
1330 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1331 rStyleSheet->singleElement( XML_numFmt,
1332 XML_numFmtId, OString::number(mnXclNumFmt),
1333 XML_formatCode, maNumFmtString );
1336 XclExpNumFmtBuffer::XclExpNumFmtBuffer( const XclExpRoot& rRoot ) :
1337 XclExpRoot( rRoot ),
1338 mxFormatter( new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ) ),
1339 mpKeywordTable( new NfKeywordTable ),
1340 mnStdFmt( GetFormatter().GetStandardIndex( ScGlobal::eLnge ) )
1342 switch( GetBiff() )
1344 case EXC_BIFF5: mnXclOffset = EXC_FORMAT_OFFSET5; break;
1345 case EXC_BIFF8: mnXclOffset = EXC_FORMAT_OFFSET8; break;
1346 default: mnXclOffset = 0; DBG_ERROR_BIFF();
1349 mxFormatter->FillKeywordTableForExcel( *mpKeywordTable );
1352 XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
1356 sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uInt32 nScNumFmt )
1358 XclExpNumFmtVec::const_iterator aIt =
1359 ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
1360 if( aIt != maFormatMap.end() )
1361 return aIt->mnXclNumFmt;
1363 size_t nSize = maFormatMap.size();
1364 if( nSize < o3tl::make_unsigned( 0xFFFF - mnXclOffset ) )
1366 sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
1367 maFormatMap.emplace_back( nScNumFmt, nXclNumFmt, GetFormatCode( nScNumFmt ) );
1368 return nXclNumFmt;
1371 return 0;
1374 void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
1376 for( const auto& rEntry : maFormatMap )
1377 WriteFormatRecord( rStrm, rEntry );
1380 void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
1382 if( maFormatMap.empty() )
1383 return;
1385 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1386 rStyleSheet->startElement(XML_numFmts, XML_count, OString::number(maFormatMap.size()));
1387 for( auto& rEntry : maFormatMap )
1389 rEntry.SaveXml( rStrm );
1391 rStyleSheet->endElement( XML_numFmts );
1394 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const OUString& rFormatStr )
1396 XclExpString aExpStr;
1397 if( GetBiff() <= EXC_BIFF5 )
1398 aExpStr.AssignByte( rFormatStr, GetTextEncoding(), XclStrFlags::EightBitLength );
1399 else
1400 aExpStr.Assign( rFormatStr );
1402 rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
1403 rStrm << nXclNumFmt << aExpStr;
1404 rStrm.EndRecord();
1407 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
1409 WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat.mnScNumFmt ) );
1412 namespace {
1414 OUString GetNumberFormatCode(const XclRoot& rRoot, const sal_uInt32 nScNumFmt, SvNumberFormatter* pFormatter, const NfKeywordTable* pKeywordTable)
1416 return rRoot.GetFormatter().GetFormatStringForExcel( nScNumFmt, *pKeywordTable, *pFormatter);
1421 OUString XclExpNumFmtBuffer::GetFormatCode( sal_uInt32 nScNumFmt )
1423 return GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() );
1426 // XF, STYLE record - Cell formatting =========================================
1428 bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
1430 const ScProtectionAttr& rProtItem = rItemSet.Get( ATTR_PROTECTION );
1431 mbLocked = rProtItem.GetProtection();
1432 mbHidden = rProtItem.GetHideFormula() || rProtItem.GetHideCell();
1433 return ScfTools::CheckItem( rItemSet, ATTR_PROTECTION, bStyle );
1436 void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
1438 ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
1439 ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
1442 void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
1444 rStrm.GetCurrentStream()->singleElement( XML_protection,
1445 XML_locked, ToPsz( mbLocked ),
1446 XML_hidden, ToPsz( mbHidden ) );
1449 bool XclExpCellAlign::FillFromItemSet(const XclRoot& rRoot, const SfxItemSet& rItemSet,
1450 bool bForceLineBreak, XclBiff eBiff, bool bStyle)
1452 bool bUsed = false;
1453 SvxCellHorJustify eHorAlign = rItemSet.Get( ATTR_HOR_JUSTIFY ).GetValue();
1454 SvxCellVerJustify eVerAlign = rItemSet.Get( ATTR_VER_JUSTIFY ).GetValue();
1456 switch( eBiff )
1458 case EXC_BIFF8: // attributes new in BIFF8
1460 // text indent
1461 tools::Long nTmpIndent = rItemSet.Get( ATTR_INDENT ).GetValue(); // already in twips
1462 tools::Long nSpaceWidth = rRoot.GetSpaceWidth();
1463 sal_Int32 nIndent = static_cast<double>(nTmpIndent) / (3.0 * nSpaceWidth) + 0.5;
1464 mnIndent = limit_cast< sal_uInt8 >( nIndent, 0, 15 );
1465 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_INDENT, bStyle );
1467 // shrink to fit
1468 mbShrink = rItemSet.Get( ATTR_SHRINKTOFIT ).GetValue();
1469 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
1471 // CTL text direction
1472 SetScFrameDir( rItemSet.Get( ATTR_WRITINGDIR ).GetValue() );
1473 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
1475 [[fallthrough]];
1478 case EXC_BIFF5: // attributes new in BIFF5
1479 case EXC_BIFF4: // attributes new in BIFF4
1481 // vertical alignment
1482 SetScVerAlign( eVerAlign );
1483 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
1485 // stacked/rotation
1486 bool bStacked = rItemSet.Get( ATTR_STACKED ).GetValue();
1487 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
1488 if( bStacked )
1490 mnRotation = EXC_ROT_STACKED;
1492 else
1494 // rotation
1495 Degree100 nScRot = rItemSet.Get( ATTR_ROTATE_VALUE ).GetValue();
1496 mnRotation = XclTools::GetXclRotation( nScRot );
1497 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_ROTATE_VALUE, bStyle );
1499 mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
1501 [[fallthrough]];
1504 case EXC_BIFF3: // attributes new in BIFF3
1506 // text wrap
1507 mbLineBreak = bForceLineBreak || rItemSet.Get( ATTR_LINEBREAK ).GetValue();
1508 bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
1510 [[fallthrough]];
1513 case EXC_BIFF2: // attributes new in BIFF2
1515 // horizontal alignment
1516 SetScHorAlign( eHorAlign );
1517 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
1520 break;
1521 default: DBG_ERROR_BIFF();
1524 if (eBiff == EXC_BIFF8)
1526 // Adjust for distributed alignments.
1527 if (eHorAlign == SvxCellHorJustify::Block)
1529 SvxCellJustifyMethod eHorJustMethod =
1530 rItemSet.GetItem<SvxJustifyMethodItem>(ATTR_HOR_JUSTIFY_METHOD)->GetValue();
1531 if (eHorJustMethod == SvxCellJustifyMethod::Distribute)
1532 mnHorAlign = EXC_XF_HOR_DISTRIB;
1535 if (eVerAlign == SvxCellVerJustify::Block)
1537 SvxCellJustifyMethod eVerJustMethod =
1538 rItemSet.GetItem<SvxJustifyMethodItem>(ATTR_VER_JUSTIFY_METHOD)->GetValue();
1539 if (eVerJustMethod == SvxCellJustifyMethod::Distribute)
1540 mnVerAlign = EXC_XF_VER_DISTRIB;
1544 return bUsed;
1547 void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
1549 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1550 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1551 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1552 ::insert_value( rnAlign, mnOrient, 8, 2 );
1555 void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
1557 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1558 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1559 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1560 ::insert_value( rnAlign, mnRotation, 8, 8 );
1561 ::insert_value( rnMiscAttrib, mnIndent, 0, 4 );
1562 ::set_flag( rnMiscAttrib, EXC_XF8_SHRINK, mbShrink );
1563 ::insert_value( rnMiscAttrib, mnTextDir, 6, 2 );
1566 static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
1568 switch( nHorAlign )
1570 case EXC_XF_HOR_GENERAL: return "general";
1571 case EXC_XF_HOR_LEFT: return "left";
1572 case EXC_XF_HOR_CENTER: return "center";
1573 case EXC_XF_HOR_RIGHT: return "right";
1574 case EXC_XF_HOR_FILL: return "fill";
1575 case EXC_XF_HOR_JUSTIFY: return "justify";
1576 case EXC_XF_HOR_CENTER_AS: return "centerContinuous";
1577 case EXC_XF_HOR_DISTRIB: return "distributed";
1579 return "*unknown*";
1582 static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
1584 switch( nVerAlign )
1586 case EXC_XF_VER_TOP: return "top";
1587 case EXC_XF_VER_CENTER: return "center";
1588 case EXC_XF_VER_BOTTOM: return "bottom";
1589 case EXC_XF_VER_JUSTIFY: return "justify";
1590 case EXC_XF_VER_DISTRIB: return "distributed";
1592 return "*unknown*";
1595 void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
1597 rStrm.GetCurrentStream()->singleElement( XML_alignment,
1598 XML_horizontal, ToHorizontalAlignment( mnHorAlign ),
1599 XML_vertical, ToVerticalAlignment( mnVerAlign ),
1600 XML_textRotation, OString::number(mnRotation),
1601 XML_wrapText, ToPsz( mbLineBreak ),
1602 XML_indent, OString::number(mnIndent),
1603 // OOXTODO: XML_relativeIndent, mnIndent?
1604 // OOXTODO: XML_justifyLastLine,
1605 XML_shrinkToFit, ToPsz( mbShrink ),
1606 XML_readingOrder, sax_fastparser::UseIf(OString::number(mnTextDir), mnTextDir != EXC_XF_TEXTDIR_CONTEXT) );
1609 namespace {
1611 void lclGetBorderLine(
1612 sal_uInt8& rnXclLine, sal_uInt32& rnColorId,
1613 const ::editeng::SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
1615 // Document: sc/qa/unit/data/README.cellborders
1617 enum CalcLineIndex{Idx_None, Idx_Solid, Idx_Dotted, Idx_Dashed, Idx_FineDashed, Idx_DashDot, Idx_DashDotDot, Idx_DoubleThin, Idx_Last};
1618 enum ExcelWidthIndex{Width_Hair, Width_Thin, Width_Medium, Width_Thick, Width_Last};
1619 static sal_uInt8 Map_LineLO_toMS[Idx_Last][Width_Last] =
1621 // 0,05 - 0,74 0,75 - 1,49 1,50 - 2,49 2,50 - 9,00 Width Range [pt]
1622 // EXC_BORDER_HAIR EXC_BORDER_THIN EXC_BORDER_MEDIUM EXC_BORDER_THICK MS Width
1623 {EXC_LINE_NONE , EXC_LINE_NONE , EXC_LINE_NONE , EXC_LINE_NONE }, // 0 BorderLineStyle::NONE
1624 {EXC_LINE_HAIR , EXC_LINE_THIN , EXC_LINE_MEDIUM , EXC_LINE_THICK }, // 1 BorderLineStyle::SOLID
1625 {EXC_LINE_DOTTED , EXC_LINE_DOTTED , EXC_LINE_MEDIUM_SLANT_DASHDOT, EXC_LINE_MEDIUM_SLANT_DASHDOT}, // 2 BorderLineStyle::DOTTED
1626 {EXC_LINE_DOTTED , EXC_LINE_DASHED , EXC_LINE_MEDIUM_DASHED , EXC_LINE_MEDIUM_DASHED }, // 3 BorderLineStyle::DASHED
1627 {EXC_LINE_DASHED , EXC_LINE_DASHED , EXC_LINE_MEDIUM_SLANT_DASHDOT, EXC_LINE_MEDIUM_SLANT_DASHDOT}, // 4 BorderLineStyle::FINE_DASHED
1628 {EXC_LINE_DASHED , EXC_LINE_THIN_DASHDOT , EXC_LINE_MEDIUM_DASHDOT , EXC_LINE_MEDIUM_DASHDOT }, // 5 BorderLineStyle::DASH_DOT
1629 {EXC_LINE_DASHED , EXC_LINE_THIN_DASHDOTDOT , EXC_LINE_MEDIUM_DASHDOTDOT , EXC_LINE_MEDIUM_DASHDOTDOT }, // 6 BorderLineStyle::DASH_DOT_DOT
1630 {EXC_LINE_DOUBLE , EXC_LINE_DOUBLE , EXC_LINE_DOUBLE , EXC_LINE_DOUBLE } // 7 BorderLineStyle::DOUBLE_THIN
1631 }; // Line Name
1633 rnXclLine = EXC_LINE_NONE;
1634 if( pLine )
1636 sal_uInt16 nOuterWidth = pLine->GetOutWidth();
1637 ExcelWidthIndex nOuterWidthIndx;
1638 CalcLineIndex nStyleIndex;
1640 switch (pLine->GetBorderLineStyle())
1642 case SvxBorderLineStyle::NONE:
1643 nStyleIndex = Idx_None;
1644 break;
1645 case SvxBorderLineStyle::SOLID:
1646 nStyleIndex = Idx_Solid;
1647 break;
1648 case SvxBorderLineStyle::DOTTED:
1649 nStyleIndex = Idx_Dotted;
1650 break;
1651 case SvxBorderLineStyle::DASHED:
1652 nStyleIndex = Idx_Dashed;
1653 break;
1654 case SvxBorderLineStyle::FINE_DASHED:
1655 nStyleIndex = Idx_FineDashed;
1656 break;
1657 case SvxBorderLineStyle::DASH_DOT:
1658 nStyleIndex = Idx_DashDot;
1659 break;
1660 case SvxBorderLineStyle::DASH_DOT_DOT:
1661 nStyleIndex = Idx_DashDotDot;
1662 break;
1663 case SvxBorderLineStyle::DOUBLE_THIN:
1664 // the "nOuterWidth" is not right for this line type
1665 // but at the moment width it not important for that
1666 // the right function is nOuterWidth = (sal_uInt16) pLine->GetWidth();
1667 nStyleIndex = Idx_DoubleThin;
1668 break;
1669 default:
1670 nStyleIndex = Idx_Solid;
1673 if( nOuterWidth >= EXC_BORDER_THICK )
1674 nOuterWidthIndx = Width_Thick;
1675 else if( nOuterWidth >= EXC_BORDER_MEDIUM )
1676 nOuterWidthIndx = Width_Medium;
1677 else if( nOuterWidth >= EXC_BORDER_THIN )
1678 nOuterWidthIndx = Width_Thin;
1679 else if ( nOuterWidth >= EXC_BORDER_HAIR )
1680 nOuterWidthIndx = Width_Hair;
1681 else
1682 nOuterWidthIndx = Width_Thin;
1684 rnXclLine = Map_LineLO_toMS[nStyleIndex][nOuterWidthIndx];
1687 if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
1688 rnXclLine = EXC_LINE_THIN;
1690 rnColorId = (pLine && (rnXclLine != EXC_LINE_NONE)) ?
1691 rPalette.InsertColor( pLine->GetColor(), EXC_COLOR_CELLBORDER ) :
1692 XclExpPalette::GetColorIdFromIndex( 0 );
1695 } // namespace
1697 XclExpCellBorder::XclExpCellBorder() :
1698 mnLeftColorId( XclExpPalette::GetColorIdFromIndex( mnLeftColor ) ),
1699 mnRightColorId( XclExpPalette::GetColorIdFromIndex( mnRightColor ) ),
1700 mnTopColorId( XclExpPalette::GetColorIdFromIndex( mnTopColor ) ),
1701 mnBottomColorId( XclExpPalette::GetColorIdFromIndex( mnBottomColor ) ),
1702 mnDiagColorId( XclExpPalette::GetColorIdFromIndex( mnDiagColor ) )
1706 bool XclExpCellBorder::FillFromItemSet(
1707 const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
1709 bool bUsed = false;
1711 switch( eBiff )
1713 case EXC_BIFF8: // attributes new in BIFF8
1715 const SvxLineItem& rTLBRItem = rItemSet.Get( ATTR_BORDER_TLBR );
1716 sal_uInt8 nTLBRLine;
1717 sal_uInt32 nTLBRColorId;
1718 lclGetBorderLine( nTLBRLine, nTLBRColorId, rTLBRItem.GetLine(), rPalette, eBiff );
1719 mbDiagTLtoBR = (nTLBRLine != EXC_LINE_NONE);
1721 const SvxLineItem& rBLTRItem = rItemSet.Get( ATTR_BORDER_BLTR );
1722 sal_uInt8 nBLTRLine;
1723 sal_uInt32 nBLTRColorId;
1724 lclGetBorderLine( nBLTRLine, nBLTRColorId, rBLTRItem.GetLine(), rPalette, eBiff );
1725 mbDiagBLtoTR = (nBLTRLine != EXC_LINE_NONE);
1727 if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
1729 mnDiagLine = nTLBRLine;
1730 mnDiagColorId = nTLBRColorId;
1732 else
1734 mnDiagLine = nBLTRLine;
1735 mnDiagColorId = nBLTRColorId;
1738 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
1739 ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
1741 [[fallthrough]];
1744 case EXC_BIFF5:
1745 case EXC_BIFF4:
1746 case EXC_BIFF3:
1747 case EXC_BIFF2:
1749 const SvxBoxItem& rBoxItem = rItemSet.Get( ATTR_BORDER );
1750 lclGetBorderLine( mnLeftLine, mnLeftColorId, rBoxItem.GetLeft(), rPalette, eBiff );
1751 lclGetBorderLine( mnRightLine, mnRightColorId, rBoxItem.GetRight(), rPalette, eBiff );
1752 lclGetBorderLine( mnTopLine, mnTopColorId, rBoxItem.GetTop(), rPalette, eBiff );
1753 lclGetBorderLine( mnBottomLine, mnBottomColorId, rBoxItem.GetBottom(), rPalette, eBiff );
1754 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER, bStyle );
1757 break;
1758 default: DBG_ERROR_BIFF();
1761 return bUsed;
1764 void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
1766 mnLeftColor = rPalette.GetColorIndex( mnLeftColorId );
1767 mnRightColor = rPalette.GetColorIndex( mnRightColorId );
1768 mnTopColor = rPalette.GetColorIndex( mnTopColorId );
1769 mnBottomColor = rPalette.GetColorIndex( mnBottomColorId );
1770 mnDiagColor = rPalette.GetColorIndex( mnDiagColorId );
1773 void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
1775 ::insert_value( rnBorder, mnTopLine, 0, 3 );
1776 ::insert_value( rnBorder, mnLeftLine, 3, 3 );
1777 ::insert_value( rnArea, mnBottomLine, 22, 3 );
1778 ::insert_value( rnBorder, mnRightLine, 6, 3 );
1779 ::insert_value( rnBorder, mnTopColor, 9, 7 );
1780 ::insert_value( rnBorder, mnLeftColor, 16, 7 );
1781 ::insert_value( rnArea, mnBottomColor, 25, 7 );
1782 ::insert_value( rnBorder, mnRightColor, 23, 7 );
1785 void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
1787 ::insert_value( rnBorder1, mnLeftLine, 0, 4 );
1788 ::insert_value( rnBorder1, mnRightLine, 4, 4 );
1789 ::insert_value( rnBorder1, mnTopLine, 8, 4 );
1790 ::insert_value( rnBorder1, mnBottomLine, 12, 4 );
1791 ::insert_value( rnBorder1, mnLeftColor, 16, 7 );
1792 ::insert_value( rnBorder1, mnRightColor, 23, 7 );
1793 ::insert_value( rnBorder2, mnTopColor, 0, 7 );
1794 ::insert_value( rnBorder2, mnBottomColor, 7, 7 );
1795 ::insert_value( rnBorder2, mnDiagColor, 14, 7 );
1796 ::insert_value( rnBorder2, mnDiagLine, 21, 4 );
1797 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_TL_TO_BR, mbDiagTLtoBR );
1798 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_BL_TO_TR, mbDiagBLtoTR );
1801 void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
1803 ::insert_value( rnLine, mnLeftLine, 0, 4 );
1804 ::insert_value( rnLine, mnRightLine, 4, 4 );
1805 ::insert_value( rnLine, mnTopLine, 8, 4 );
1806 ::insert_value( rnLine, mnBottomLine, 12, 4 );
1807 ::insert_value( rnColor, mnLeftColor, 0, 7 );
1808 ::insert_value( rnColor, mnRightColor, 7, 7 );
1809 ::insert_value( rnColor, mnTopColor, 16, 7 );
1810 ::insert_value( rnColor, mnBottomColor, 23, 7 );
1813 static const char* ToLineStyle( sal_uInt8 nLineStyle )
1815 switch( nLineStyle )
1817 case EXC_LINE_NONE: return "none";
1818 case EXC_LINE_THIN: return "thin";
1819 case EXC_LINE_MEDIUM: return "medium";
1820 case EXC_LINE_THICK: return "thick";
1821 case EXC_LINE_DOUBLE: return "double";
1822 case EXC_LINE_HAIR: return "hair";
1823 case EXC_LINE_DOTTED: return "dotted";
1824 case EXC_LINE_DASHED: return "dashed";
1825 case EXC_LINE_MEDIUM_DASHED: return "mediumDashed";
1826 case EXC_LINE_THIN_DASHDOT: return "dashDot";
1827 case EXC_LINE_THIN_DASHDOTDOT: return "dashDotDot";
1828 case EXC_LINE_MEDIUM_DASHDOT: return "mediumDashDot";
1829 case EXC_LINE_MEDIUM_DASHDOTDOT: return "mediumDashDotDot";
1830 case EXC_LINE_MEDIUM_SLANT_DASHDOT: return "slantDashDot";
1832 return "*unknown*";
1835 static void lcl_WriteBorder( XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor )
1837 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1838 if( nLineStyle == EXC_LINE_NONE )
1839 rStyleSheet->singleElement(nElement);
1840 else if( rColor == Color( 0, 0, 0 ) )
1841 rStyleSheet->singleElement(nElement, XML_style, ToLineStyle(nLineStyle));
1842 else
1844 rStyleSheet->startElement(nElement, XML_style, ToLineStyle(nLineStyle));
1845 rStyleSheet->singleElement(XML_color, XML_rgb, XclXmlUtils::ToOString(rColor));
1846 rStyleSheet->endElement( nElement );
1850 void XclExpCellBorder::SaveXml( XclExpXmlStream& rStrm ) const
1852 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1854 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1856 rStyleSheet->startElement( XML_border,
1857 XML_diagonalUp, ToPsz( mbDiagBLtoTR ),
1858 XML_diagonalDown, ToPsz( mbDiagTLtoBR )
1859 // OOXTODO: XML_outline
1861 lcl_WriteBorder( rStrm, XML_left, mnLeftLine, rPalette.GetColor( mnLeftColor ) );
1862 lcl_WriteBorder( rStrm, XML_right, mnRightLine, rPalette.GetColor( mnRightColor ) );
1863 lcl_WriteBorder( rStrm, XML_top, mnTopLine, rPalette.GetColor( mnTopColor ) );
1864 lcl_WriteBorder( rStrm, XML_bottom, mnBottomLine, rPalette.GetColor( mnBottomColor ) );
1865 lcl_WriteBorder( rStrm, XML_diagonal, mnDiagLine, rPalette.GetColor( mnDiagColor ) );
1866 // OOXTODO: XML_vertical, XML_horizontal
1867 rStyleSheet->endElement( XML_border );
1870 XclExpCellArea::XclExpCellArea() :
1871 mnForeColorId( XclExpPalette::GetColorIdFromIndex( mnForeColor ) ),
1872 mnBackColorId( XclExpPalette::GetColorIdFromIndex( mnBackColor ) ),
1873 maForeColor(0),
1874 maBackColor(0)
1878 XclExpCellArea::XclExpCellArea(Color aForeColor, Color aBackColor)
1879 : XclCellArea(EXC_PATT_SOLID)
1880 , mnForeColorId(0)
1881 , mnBackColorId(0)
1882 , maForeColor(aForeColor)
1883 , maBackColor(aBackColor)
1887 bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
1889 const SvxBrushItem& rBrushItem = rItemSet.Get( ATTR_BACKGROUND );
1890 if( rBrushItem.GetColor().IsTransparent() )
1892 mnPattern = EXC_PATT_NONE;
1893 mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1894 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
1896 else
1898 mnPattern = EXC_PATT_SOLID;
1899 mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
1900 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1902 return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
1905 void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
1907 rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
1910 void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
1912 ::insert_value( rnArea, mnPattern, 16, 6 );
1913 ::insert_value( rnArea, mnForeColor, 0, 7 );
1914 ::insert_value( rnArea, mnBackColor, 7, 7 );
1917 void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
1919 ::insert_value( rnBorder2, mnPattern, 26, 6 );
1920 ::insert_value( rnArea, mnForeColor, 0, 7 );
1921 ::insert_value( rnArea, mnBackColor, 7, 7 );
1924 void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
1926 XclCellArea aTmp( *this );
1927 if( !aTmp.IsTransparent() && (aTmp.mnBackColor == EXC_COLOR_WINDOWTEXT) )
1928 aTmp.mnBackColor = 0;
1929 if( aTmp.mnPattern == EXC_PATT_SOLID )
1930 ::std::swap( aTmp.mnForeColor, aTmp.mnBackColor );
1931 ::insert_value( rnColor, aTmp.mnForeColor, 0, 7 );
1932 ::insert_value( rnColor, aTmp.mnBackColor, 7, 7 );
1933 ::insert_value( rnPattern, aTmp.mnPattern, 10, 6 );
1936 static const char* ToPatternType( sal_uInt8 nPattern )
1938 switch( nPattern )
1940 case EXC_PATT_NONE: return "none";
1941 case EXC_PATT_SOLID: return "solid";
1942 case EXC_PATT_50_PERC: return "mediumGray";
1943 case EXC_PATT_75_PERC: return "darkGray";
1944 case EXC_PATT_25_PERC: return "lightGray";
1945 case EXC_PATT_12_5_PERC: return "gray125";
1946 case EXC_PATT_6_25_PERC: return "gray0625";
1948 return "*unknown*";
1951 void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
1953 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1954 rStyleSheet->startElement(XML_fill);
1956 // OOXTODO: XML_gradientFill
1958 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1960 if (mnPattern == EXC_PATT_NONE
1961 || (mnForeColor == 0 && mnBackColor == 0 && maForeColor == 0 && maBackColor == 0))
1963 rStyleSheet->singleElement(XML_patternFill, XML_patternType, ToPatternType(mnPattern));
1965 else
1967 rStyleSheet->startElement(XML_patternFill, XML_patternType, ToPatternType(mnPattern));
1968 if (maForeColor != 0 || maBackColor != 0)
1970 if (maForeColor != 0)
1972 rStyleSheet->singleElement(XML_fgColor, XML_rgb,
1973 XclXmlUtils::ToOString(maForeColor));
1976 if (maBackColor != 0)
1978 rStyleSheet->singleElement(XML_bgColor, XML_rgb,
1979 XclXmlUtils::ToOString(maBackColor));
1982 else
1984 if (mnForeColor != 0)
1986 rStyleSheet->singleElement(XML_fgColor, XML_rgb,
1987 XclXmlUtils::ToOString(rPalette.GetColor(mnForeColor)));
1989 if (mnBackColor != 0)
1991 rStyleSheet->singleElement(XML_bgColor, XML_rgb,
1992 XclXmlUtils::ToOString(rPalette.GetColor(mnBackColor)));
1996 rStyleSheet->endElement( XML_patternFill );
1999 rStyleSheet->endElement( XML_fill );
2002 bool XclExpColor::FillFromItemSet( const SfxItemSet& rItemSet )
2004 if( !ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true ) )
2005 return false;
2007 const SvxBrushItem& rBrushItem = rItemSet.Get( ATTR_BACKGROUND );
2008 maColor = rBrushItem.GetColor();
2010 return true;
2013 void XclExpColor::SaveXml( XclExpXmlStream& rStrm ) const
2015 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2016 rStyleSheet->startElement(XML_fill);
2017 rStyleSheet->startElement(XML_patternFill);
2018 rStyleSheet->singleElement(XML_bgColor, XML_rgb, XclXmlUtils::ToOString(maColor));
2020 rStyleSheet->endElement( XML_patternFill );
2021 rStyleSheet->endElement( XML_fill );
2024 XclExpXFId::XclExpXFId() :
2025 mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
2026 mnXFIndex( EXC_XF_DEFAULTCELL )
2030 void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
2032 mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
2035 XclExpXF::XclExpXF(
2036 const XclExpRoot& rRoot, const ScPatternAttr& rPattern, sal_Int16 nScript,
2037 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) :
2038 XclXFBase( true ),
2039 XclExpRoot( rRoot )
2041 mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
2042 Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
2045 XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet ) :
2046 XclXFBase( false ),
2047 XclExpRoot( rRoot ),
2048 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2050 bool bDefStyle = (rStyleSheet.GetName() == ScResId( STR_STYLENAME_STANDARD ));
2051 sal_Int16 nScript = bDefStyle ? GetDefApiScript() : css::i18n::ScriptType::WEAK;
2052 Init( const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet(), nScript,
2053 NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false, bDefStyle );
2056 XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF ) :
2057 XclXFBase( bCellXF ),
2058 XclExpRoot( rRoot ),
2059 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2061 InitDefault();
2064 bool XclExpXF::Equals( const ScPatternAttr& rPattern,
2065 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2067 return IsCellXF() && (mpItemSet == &rPattern.GetItemSet()) &&
2068 (!bForceLineBreak || maAlignment.mbLineBreak) &&
2069 ((nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) || (mnScNumFmt == nForceScNumFmt)) &&
2070 ((nForceXclFont == EXC_FONT_NOTFOUND) || (mnXclFont == nForceXclFont));
2073 bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
2075 return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
2078 void XclExpXF::SetFinalColors()
2080 maBorder.SetFinalColors( GetPalette() );
2081 maArea.SetFinalColors( GetPalette() );
2084 bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
2086 return XclXFBase::Equals( rCmpXF ) &&
2087 (maProtection == rCmpXF.maProtection) && (maAlignment == rCmpXF.maAlignment) &&
2088 (maBorder == rCmpXF.maBorder) && (maArea == rCmpXF.maArea) &&
2089 (mnXclFont == rCmpXF.mnXclFont) && (mnXclNumFmt == rCmpXF.mnXclNumFmt) &&
2090 (mnParentXFId == rCmpXF.mnParentXFId);
2093 void XclExpXF::InitDefault()
2095 SetRecHeader( EXC_ID5_XF, (GetBiff() == EXC_BIFF8) ? 20 : 16 );
2096 mpItemSet = nullptr;
2097 mnScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
2098 mnXclFont = mnXclNumFmt = 0;
2099 SetXmlIds(0, 0);
2102 void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
2103 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
2105 InitDefault();
2106 mpItemSet = &rItemSet;
2108 // cell protection
2109 mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
2111 // font
2112 if( nForceXclFont == EXC_FONT_NOTFOUND )
2114 mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
2115 mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
2117 else
2119 mnXclFont = nForceXclFont;
2120 mbFontUsed = true;
2123 // number format
2124 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
2125 mnXclNumFmt = nForceScNumFmt;
2126 else
2128 // Built-in formats of dedicated languages may be attributed using the
2129 // system language (or even other?) format with a language attribute,
2130 // obtain the "real" format key.
2131 mnScNumFmt = rItemSet.Get( ATTR_VALUE_FORMAT ).GetValue();
2132 LanguageType nLang = rItemSet.Get( ATTR_LANGUAGE_FORMAT).GetLanguage();
2133 if (mnScNumFmt >= SV_COUNTRY_LANGUAGE_OFFSET || nLang != LANGUAGE_SYSTEM)
2134 mnScNumFmt = GetFormatter().GetFormatForLanguageIfBuiltIn( mnScNumFmt, nLang);
2136 mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
2137 mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
2139 // alignment
2140 mbAlignUsed = maAlignment.FillFromItemSet(*this, rItemSet, bForceLineBreak, GetBiff(), IsStyleXF());
2142 // cell border
2143 mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
2145 // background area
2146 mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
2148 // set all b***Used flags to true in "Default"/"Normal" style
2149 if( bDefStyle )
2150 SetAllUsedFlags( true );
2153 sal_uInt8 XclExpXF::GetUsedFlags() const
2155 sal_uInt8 nUsedFlags = 0;
2156 /* In cell XFs a set bit means a used attribute, in style XFs a cleared bit.
2157 "mbCellXF == mb***Used" evaluates to correct value in cell and style XFs. */
2158 ::set_flag( nUsedFlags, EXC_XF_DIFF_PROT, mbCellXF == mbProtUsed );
2159 ::set_flag( nUsedFlags, EXC_XF_DIFF_FONT, mbCellXF == mbFontUsed );
2160 ::set_flag( nUsedFlags, EXC_XF_DIFF_VALFMT, mbCellXF == mbFmtUsed );
2161 ::set_flag( nUsedFlags, EXC_XF_DIFF_ALIGN, mbCellXF == mbAlignUsed );
2162 ::set_flag( nUsedFlags, EXC_XF_DIFF_BORDER, mbCellXF == mbBorderUsed );
2163 ::set_flag( nUsedFlags, EXC_XF_DIFF_AREA, mbCellXF == mbAreaUsed );
2164 return nUsedFlags;
2167 void XclExpXF::WriteBody5( XclExpStream& rStrm )
2169 sal_uInt16 nTypeProt = 0, nAlign = 0;
2170 sal_uInt32 nArea = 0, nBorder = 0;
2172 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2173 ::insert_value( nTypeProt, mnParent, 4, 12 );
2174 ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
2176 maProtection.FillToXF3( nTypeProt );
2177 maAlignment.FillToXF5( nAlign );
2178 maBorder.FillToXF5( nBorder, nArea );
2179 maArea.FillToXF5( nArea );
2181 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
2184 void XclExpXF::WriteBody8( XclExpStream& rStrm )
2186 sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
2187 sal_uInt32 nBorder1 = 0, nBorder2 = 0;
2189 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2190 ::insert_value( nTypeProt, mnParent, 4, 12 );
2191 ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
2193 maProtection.FillToXF3( nTypeProt );
2194 maAlignment.FillToXF8( nAlign, nMiscAttrib );
2195 maBorder.FillToXF8( nBorder1, nBorder2 );
2196 maArea.FillToXF8( nBorder2, nArea );
2198 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
2201 void XclExpXF::WriteBody( XclExpStream& rStrm )
2203 XclExpXFId aParentId( mnParentXFId );
2204 aParentId.ConvertXFIndex( GetRoot() );
2205 mnParent = aParentId.mnXFIndex;
2206 switch( GetBiff() )
2208 case EXC_BIFF5: WriteBody5( rStrm ); break;
2209 case EXC_BIFF8: WriteBody8( rStrm ); break;
2210 default: DBG_ERROR_BIFF();
2214 void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
2216 mnBorderId = nBorderId;
2217 mnFillId = nFillId;
2220 void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
2222 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2224 sal_Int32 nXfId = 0;
2225 const XclExpXF* pStyleXF = nullptr;
2226 if( IsCellXF() )
2228 sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
2229 nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
2230 pStyleXF = rStrm.GetRoot().GetXFBuffer().GetXFById( mnParentXFId );
2233 rStyleSheet->startElement( XML_xf,
2234 XML_numFmtId, OString::number(mnXclNumFmt),
2235 XML_fontId, OString::number(mnXclFont),
2236 XML_fillId, OString::number(mnFillId),
2237 XML_borderId, OString::number(mnBorderId),
2238 XML_xfId, sax_fastparser::UseIf(OString::number(nXfId), !IsStyleXF()),
2239 // OOXTODO: XML_quotePrefix,
2240 // OOXTODO: XML_pivotButton,
2241 // OOXTODO: XML_applyNumberFormat, ;
2242 XML_applyFont, ToPsz( mbFontUsed ),
2243 // OOXTODO: XML_applyFill,
2244 XML_applyBorder, ToPsz( mbBorderUsed ),
2245 XML_applyAlignment, ToPsz( mbAlignUsed ),
2246 XML_applyProtection, ToPsz( mbProtUsed ) );
2247 if( mbAlignUsed )
2248 maAlignment.SaveXml( rStrm );
2249 else if ( pStyleXF )
2250 pStyleXF->GetAlignmentData().SaveXml( rStrm );
2251 if( mbProtUsed )
2252 maProtection.SaveXml( rStrm );
2253 else if ( pStyleXF )
2254 pStyleXF->GetProtectionData().SaveXml( rStrm );
2256 // OOXTODO: XML_extLst
2257 rStyleSheet->endElement( XML_xf );
2260 XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
2261 XclExpXF( rRoot, bCellXF )
2265 void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
2267 mnXclFont = nXclFont;
2268 mbFontUsed = true;
2271 void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
2273 mnXclNumFmt = nXclNumFmt;
2274 mbFmtUsed = true;
2277 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, const OUString& rStyleName ) :
2278 XclExpRecord( EXC_ID_STYLE, 4 ),
2279 maName( rStyleName ),
2280 maXFId( nXFId ),
2281 mnStyleId( EXC_STYLE_USERDEF ),
2282 mnLevel( EXC_STYLE_NOLEVEL )
2284 OSL_ENSURE( !maName.isEmpty(), "XclExpStyle::XclExpStyle - empty style name" );
2285 #if OSL_DEBUG_LEVEL > 0
2286 sal_uInt8 nStyleId, nLevel; // do not use members for debug tests
2287 OSL_ENSURE( !XclTools::GetBuiltInStyleId( nStyleId, nLevel, maName ),
2288 "XclExpStyle::XclExpStyle - this is a built-in style" );
2289 #endif
2292 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, sal_uInt8 nStyleId, sal_uInt8 nLevel ) :
2293 XclExpRecord( EXC_ID_STYLE, 4 ),
2294 maXFId( nXFId ),
2295 mnStyleId( nStyleId ),
2296 mnLevel( nLevel )
2300 void XclExpStyle::WriteBody( XclExpStream& rStrm )
2302 maXFId.ConvertXFIndex( rStrm.GetRoot() );
2303 ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
2304 rStrm << maXFId.mnXFIndex;
2306 if( IsBuiltIn() )
2308 rStrm << mnStyleId << mnLevel;
2310 else
2312 XclExpString aNameEx;
2313 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
2314 aNameEx.Assign( maName );
2315 else
2316 aNameEx.AssignByte( maName, rStrm.GetRoot().GetTextEncoding(), XclStrFlags::EightBitLength );
2317 rStrm << aNameEx;
2321 static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
2323 switch( nStyleId )
2325 case 0: return "Normal";
2326 case 3: return "Comma";
2327 case 4: return "Currency";
2328 case 5: return "Percent";
2329 case 6: return "Comma [0]";
2330 case 7: return "Currency [0]";
2332 return "*unknown*";
2335 void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
2337 constexpr sal_Int32 CELL_STYLE_MAX_BUILTIN_ID = 54;
2338 OString sName;
2339 OString sBuiltinId;
2340 const char* pBuiltinId = nullptr;
2341 if( IsBuiltIn() )
2343 sName = OString( lcl_StyleNameFromId( mnStyleId ) );
2344 sBuiltinId = OString::number( std::min( static_cast<sal_Int32>( CELL_STYLE_MAX_BUILTIN_ID - 1 ), static_cast <sal_Int32>( mnStyleId ) ) );
2345 pBuiltinId = sBuiltinId.getStr();
2347 else
2348 sName = maName.toUtf8();
2350 // get the index in sortedlist associated with the mnXId
2351 sal_Int32 nXFId = rStrm.GetRoot().GetXFBuffer().GetXFIndex( maXFId.mnXFId );
2352 // get the style index associated with index into sortedlist
2353 nXFId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFId );
2354 rStrm.GetCurrentStream()->singleElement( XML_cellStyle,
2355 XML_name, sName,
2356 XML_xfId, OString::number(nXFId),
2357 // builtinId of 54 or above is invalid according to OpenXML SDK validator.
2358 XML_builtinId, pBuiltinId
2359 // OOXTODO: XML_iLevel,
2360 // OOXTODO: XML_hidden,
2361 // XML_customBuiltin, ToPsz( ! IsBuiltIn() )
2363 // OOXTODO: XML_extLst
2366 namespace {
2368 const sal_uInt32 EXC_XFLIST_INDEXBASE = 0xFFFE0000;
2369 /** Maximum count of XF records to store in the XF list (performance). */
2370 const sal_uInt32 EXC_XFLIST_HARDLIMIT = 256 * 1024;
2372 bool lclIsBuiltInStyle( const OUString& rStyleName )
2374 return
2375 XclTools::IsBuiltInStyleName( rStyleName ) ||
2376 XclTools::IsCondFormatStyleName( rStyleName );
2379 } // namespace
2381 XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
2382 mnStyleId( EXC_STYLE_USERDEF ),
2383 mnLevel( EXC_STYLE_NOLEVEL ),
2384 mbPredefined( true ),
2385 mbHasStyleRec( false )
2389 namespace {
2391 /** Predicate for search algorithm. */
2392 struct XclExpBorderPred
2394 const XclExpCellBorder&
2395 mrBorder;
2396 explicit XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
2397 bool operator()( const XclExpCellBorder& rBorder ) const;
2402 bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
2404 return
2405 mrBorder.mnLeftColor == rBorder.mnLeftColor &&
2406 mrBorder.mnRightColor == rBorder.mnRightColor &&
2407 mrBorder.mnTopColor == rBorder.mnTopColor &&
2408 mrBorder.mnBottomColor == rBorder.mnBottomColor &&
2409 mrBorder.mnDiagColor == rBorder.mnDiagColor &&
2410 mrBorder.mnLeftLine == rBorder.mnLeftLine &&
2411 mrBorder.mnRightLine == rBorder.mnRightLine &&
2412 mrBorder.mnTopLine == rBorder.mnTopLine &&
2413 mrBorder.mnBottomLine == rBorder.mnBottomLine &&
2414 mrBorder.mnDiagLine == rBorder.mnDiagLine &&
2415 mrBorder.mbDiagTLtoBR == rBorder.mbDiagTLtoBR &&
2416 mrBorder.mbDiagBLtoTR == rBorder.mbDiagBLtoTR &&
2417 mrBorder.mnLeftColorId == rBorder.mnLeftColorId &&
2418 mrBorder.mnRightColorId == rBorder.mnRightColorId &&
2419 mrBorder.mnTopColorId == rBorder.mnTopColorId &&
2420 mrBorder.mnBottomColorId == rBorder.mnBottomColorId &&
2421 mrBorder.mnDiagColorId == rBorder.mnDiagColorId;
2424 namespace {
2426 struct XclExpFillPred
2428 const XclExpCellArea&
2429 mrFill;
2430 explicit XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
2431 bool operator()( const XclExpCellArea& rFill ) const;
2436 bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
2438 return
2439 mrFill.mnForeColor == rFill.mnForeColor &&
2440 mrFill.mnBackColor == rFill.mnBackColor &&
2441 mrFill.mnPattern == rFill.mnPattern &&
2442 mrFill.mnForeColorId == rFill.mnForeColorId &&
2443 mrFill.mnBackColorId == rFill.mnBackColorId;
2446 XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot ) :
2447 XclExpRoot( rRoot )
2451 void XclExpXFBuffer::Initialize()
2453 InsertDefaultRecords();
2454 InsertUserStyles();
2457 sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
2459 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
2462 sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
2463 sal_uInt16 nForceXclFont, bool bForceLineBreak )
2465 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
2468 sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForceScNumFmt, bool bForceLineBreak )
2470 return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
2473 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
2475 return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2478 sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
2480 return EXC_XFLIST_INDEXBASE | nXFIndex;
2483 sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
2485 return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
2488 const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
2490 return maXFList.GetRecord( nXFId );
2493 void XclExpXFBuffer::Finalize()
2495 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2496 maXFList.GetRecord( nPos )->SetFinalColors();
2498 sal_uInt32 nTotalCount = static_cast< sal_uInt32 >( maXFList.GetSize() );
2499 sal_uInt32 nId;
2500 maXFIndexVec.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2501 maStyleIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2502 maCellIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2504 XclExpBuiltInMap::const_iterator aBuiltInEnd = maBuiltInMap.end();
2505 /* nMaxBuiltInXFId used to decide faster whether an XF record is
2506 user-defined. If the current XF ID is greater than this value,
2507 maBuiltInMap doesn't need to be searched. */
2508 sal_uInt32 nMaxBuiltInXFId = maBuiltInMap.empty() ? 0 : maBuiltInMap.rbegin()->first;
2510 // *** map all built-in XF records (cell and style) *** -------------------
2512 // do not change XF order -> std::map<> iterates elements in ascending order
2513 for( const auto& rEntry : maBuiltInMap )
2514 AppendXFIndex( rEntry.first );
2516 // *** insert all user-defined style XF records, without reduce *** -------
2518 sal_uInt32 nStyleXFCount = 0; // counts up to EXC_XF_MAXSTYLECOUNT limit
2520 for( nId = 0; nId < nTotalCount; ++nId )
2522 XclExpXFRef xXF = maXFList.GetRecord( nId );
2523 if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2525 if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
2527 // maximum count of styles not reached
2528 AppendXFIndex( nId );
2529 ++nStyleXFCount;
2531 else
2533 /* Maximum count of styles reached - do not append more
2534 pointers to XFs; use default style XF instead; do not break
2535 the loop to initialize all maXFIndexVec elements. */
2536 maXFIndexVec[ nId ] = EXC_XF_DEFAULTSTYLE;
2541 // *** insert all cell XF records *** -------------------------------------
2543 // start position to search for equal inserted XF records
2544 size_t nSearchStart = maSortedXFList.GetSize();
2546 // break the loop if XF limit reached - maXFIndexVec is already initialized with default index
2547 XclExpXFRef xDefCellXF = maXFList.GetRecord( EXC_XF_DEFAULTCELL );
2548 for( nId = 0; (nId < nTotalCount) && (maSortedXFList.GetSize() < EXC_XF_MAXCOUNT); ++nId )
2550 XclExpXFRef xXF = maXFList.GetRecord( nId );
2551 if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2553 // try to find an XF record equal to *xXF, which is already inserted
2554 sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
2556 // first try if it is equal to the default cell XF
2557 if( xDefCellXF->Equals( *xXF ) )
2559 nFoundIndex = EXC_XF_DEFAULTCELL;
2561 else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
2562 (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
2564 if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
2565 nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
2568 if( nFoundIndex != EXC_XF_NOTFOUND )
2569 // equal XF already in the list, use its resulting XF index
2570 maXFIndexVec[ nId ] = nFoundIndex;
2571 else
2572 AppendXFIndex( nId );
2576 sal_uInt16 nXmlStyleIndex = 0;
2577 sal_uInt16 nXmlCellIndex = 0;
2579 size_t nXFCount = maSortedXFList.GetSize();
2580 for( size_t i = 0; i < nXFCount; ++i )
2582 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2583 if( xXF->IsStyleXF() )
2584 maStyleIndexes[ i ] = nXmlStyleIndex++;
2585 else
2586 maCellIndexes[ i ] = nXmlCellIndex++;
2590 sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
2592 sal_uInt16 nXFIndex = EXC_XF_DEFAULTSTYLE;
2593 if( nXFId >= EXC_XFLIST_INDEXBASE )
2594 nXFIndex = static_cast< sal_uInt16 >( nXFId & ~EXC_XFLIST_INDEXBASE );
2595 else if( nXFId < maXFIndexVec.size() )
2596 nXFIndex = maXFIndexVec[ nXFId ];
2597 return nXFIndex;
2600 sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
2602 OSL_ENSURE( nXFIndex < maStyleIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2603 if( nXFIndex >= maStyleIndexes.size() )
2604 return 0; // should be caught/debugged via above assert; return "valid" index.
2605 return maStyleIndexes[ nXFIndex ];
2608 sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
2610 OSL_ENSURE( nXFIndex < maCellIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2611 if( nXFIndex >= maCellIndexes.size() )
2612 return 0; // should be caught/debugged via above assert; return "valid" index.
2613 return maCellIndexes[ nXFIndex ];
2616 void XclExpXFBuffer::Save( XclExpStream& rStrm )
2618 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2619 maSortedXFList.Save( rStrm );
2620 // save all STYLE records
2621 maStyleList.Save( rStrm );
2624 static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
2626 rCells = 0;
2627 rStyles = 0;
2628 size_t nXFCount = rXFList.GetSize();
2629 for( size_t i = 0; i < nXFCount; ++i )
2631 XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
2632 if( xXF->IsCellXF() )
2633 ++rCells;
2634 else if( xXF->IsStyleXF() )
2635 ++rStyles;
2639 void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
2641 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2643 rStyleSheet->startElement(XML_fills, XML_count, OString::number(maFills.size()));
2644 for( const auto& rFill : maFills )
2646 rFill.SaveXml( rStrm );
2648 rStyleSheet->endElement( XML_fills );
2650 rStyleSheet->startElement(XML_borders, XML_count, OString::number(maBorders.size()));
2651 for( const auto& rBorder : maBorders )
2653 rBorder.SaveXml( rStrm );
2655 rStyleSheet->endElement( XML_borders );
2657 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2658 sal_Int32 nCells, nStyles;
2659 lcl_GetCellCounts( maSortedXFList, nCells, nStyles );
2661 if( nStyles > 0 )
2663 rStyleSheet->startElement(XML_cellStyleXfs, XML_count, OString::number(nStyles));
2664 size_t nXFCount = maSortedXFList.GetSize();
2665 for( size_t i = 0; i < nXFCount; ++i )
2667 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2668 if( ! xXF->IsStyleXF() )
2669 continue;
2670 SaveXFXml( rStrm, *xXF );
2672 rStyleSheet->endElement( XML_cellStyleXfs );
2675 if( nCells > 0 )
2677 rStyleSheet->startElement(XML_cellXfs, XML_count, OString::number(nCells));
2678 size_t nXFCount = maSortedXFList.GetSize();
2679 for( size_t i = 0; i < nXFCount; ++i )
2681 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2682 if( ! xXF->IsCellXF() )
2683 continue;
2684 SaveXFXml( rStrm, *xXF );
2686 rStyleSheet->endElement( XML_cellXfs );
2689 // save all STYLE records
2690 rStyleSheet->startElement(XML_cellStyles, XML_count, OString::number(maStyleList.GetSize()));
2691 maStyleList.SaveXml( rStrm );
2692 rStyleSheet->endElement( XML_cellStyles );
2695 void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
2697 XclExpBorderList::iterator aBorderPos =
2698 std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) );
2699 OSL_ENSURE( aBorderPos != maBorders.end(), "XclExpXFBuffer::SaveXml - Invalid @borderId!" );
2700 XclExpFillList::iterator aFillPos =
2701 std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) );
2702 OSL_ENSURE( aFillPos != maFills.end(), "XclExpXFBuffer::SaveXml - Invalid @fillId!" );
2704 sal_Int32 nBorderId = 0, nFillId = 0;
2705 if( aBorderPos != maBorders.end() )
2706 nBorderId = std::distance( maBorders.begin(), aBorderPos );
2707 if( aFillPos != maFills.end() )
2708 nFillId = std::distance( maFills.begin(), aFillPos );
2710 rXF.SetXmlIds( nBorderId, nFillId );
2711 rXF.SaveXml( rStrm );
2714 sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
2715 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2717 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND && nForceXclFont == EXC_FONT_NOTFOUND)
2719 FindKey key1 { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, 0 };
2720 FindKey key2 { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, EXC_FONT_NOTFOUND };
2721 auto it1 = maXFFindMap.lower_bound(key1);
2722 if (it1 != maXFFindMap.end())
2724 auto it2 = maXFFindMap.upper_bound(key2);
2725 for (auto it = it1; it != it2; ++it)
2726 for (auto const & nPos : it->second)
2727 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2728 return nPos;
2731 else if (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND || nForceXclFont == EXC_FONT_NOTFOUND)
2733 FindKey key1 { /*mbCellXF*/true, &rPattern.GetItemSet(), 0, 0 };
2734 FindKey key2 { /*mbCellXF*/true, &rPattern.GetItemSet(), NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND };
2735 auto it1 = maXFFindMap.lower_bound(key1);
2736 if (it1 != maXFFindMap.end())
2738 auto it2 = maXFFindMap.upper_bound(key2);
2739 for (auto it = it1; it != it2; ++it)
2740 for (auto const & nPos : it->second)
2741 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2742 return nPos;
2745 else
2747 FindKey key { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, nForceXclFont };
2748 auto it = maXFFindMap.find(key);
2749 if (it == maXFFindMap.end())
2750 return EXC_XFID_NOTFOUND;
2751 for (auto const & nPos : it->second)
2752 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2753 return nPos;
2755 return EXC_XFID_NOTFOUND;
2758 sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
2760 const SfxItemSet* pItemSet = &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet();
2761 FindKey key1 { /*mbCellXF*/false, pItemSet, 0, 0 };
2762 FindKey key2 { /*mbCellXF*/false, pItemSet, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND };
2763 auto it1 = maXFFindMap.lower_bound(key1);
2764 auto it2 = maXFFindMap.upper_bound(key2);
2765 for (auto it = it1; it != it2; ++it)
2766 for (auto const & nPos : it->second)
2767 if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
2768 return nPos;
2769 return EXC_XFID_NOTFOUND;
2772 sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
2774 auto aIt = std::find_if(maBuiltInMap.begin(), maBuiltInMap.end(),
2775 [&nStyleId, nLevel](const XclExpBuiltInMap::value_type& rEntry) {
2776 return (rEntry.second.mnStyleId == nStyleId) && (rEntry.second.mnLevel == nLevel);
2778 if (aIt != maBuiltInMap.end())
2779 return aIt->first;
2780 return EXC_XFID_NOTFOUND;
2783 XclExpXFBuffer::FindKey XclExpXFBuffer::ToFindKey(XclExpXF const & rRec)
2785 return { rRec.IsCellXF(), rRec.GetItemSet(), rRec.GetScNumFmt(), rRec.GetXclFont() };
2788 sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
2789 sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
2791 const ScPatternAttr* pDefPattern = GetDoc().GetDefPattern();
2792 if( !pPattern )
2793 pPattern = pDefPattern;
2795 // special handling for default cell formatting
2796 if( (pPattern == pDefPattern) && !bForceLineBreak &&
2797 (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
2798 (nForceXclFont == EXC_FONT_NOTFOUND) )
2800 // Is it the first try to insert the default cell format?
2801 bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
2802 if( rbPredefined )
2804 // remove old entry in find-map
2805 auto & rPositions = maXFFindMap[ToFindKey(*maXFList.GetRecord(EXC_XF_DEFAULTCELL))];
2806 auto it = std::find(rPositions.begin(), rPositions.end(), EXC_XF_DEFAULTCELL);
2807 rPositions.erase(it);
2808 // replace default cell pattern
2809 XclExpXFRef xNewXF = new XclExpXF( GetRoot(), *pPattern, nScript );
2810 maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
2811 // and add new entry in find-map
2812 maXFFindMap[ToFindKey(*xNewXF)].push_back(EXC_XF_DEFAULTCELL);
2813 rbPredefined = false;
2815 return GetDefCellXFId();
2818 sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2819 if( nXFId == EXC_XFID_NOTFOUND )
2821 // not found - insert new cell XF
2822 if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
2824 auto pNewExp = new XclExpXF(
2825 GetRoot(), *pPattern, nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2826 maXFList.AppendNewRecord( pNewExp );
2827 // do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
2828 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
2829 maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
2831 else
2833 // list full - fall back to default cell XF
2834 nXFId = GetDefCellXFId();
2837 return nXFId;
2840 sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
2842 // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
2844 sal_uInt8 nStyleId, nLevel;
2845 if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
2847 // try to find the built-in XF record (if already created in InsertDefaultRecords())
2848 sal_uInt32 nXFId = FindBuiltInXF( nStyleId, nLevel );
2849 if( nXFId == EXC_XFID_NOTFOUND )
2851 // built-in style XF not yet created - do it now
2852 XclExpXFRef xXF = new XclExpXF( GetRoot(), rStyleSheet );
2853 nXFId = AppendBuiltInXFWithStyle( xXF, nStyleId, nLevel );
2854 // this new XF record is not predefined
2855 maBuiltInMap[ nXFId ].mbPredefined = false;
2857 else
2859 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::InsertStyleXF - built-in XF not found" );
2860 // XF record still predefined? -> Replace with real XF
2861 bool& rbPredefined = maBuiltInMap[ nXFId ].mbPredefined;
2862 if( rbPredefined )
2864 // remove old entry in find-map
2865 auto & rPositions = maXFFindMap[ToFindKey(*maXFList.GetRecord(nXFId))];
2866 auto it = std::find(rPositions.begin(), rPositions.end(), nXFId);
2867 rPositions.erase(it);
2868 // replace predefined built-in style (ReplaceRecord() deletes old record)
2869 XclExpXFRef pNewExp = new XclExpXF( GetRoot(), rStyleSheet );
2870 maXFList.ReplaceRecord( pNewExp, nXFId );
2871 // and add new entry in find-map
2872 maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
2873 rbPredefined = false;
2877 // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
2878 bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
2879 if( !rbHasStyleRec )
2881 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2882 rbHasStyleRec = true;
2885 return nXFId;
2888 // *** try to find the XF record of a user-defined style ***
2890 sal_uInt32 nXFId = FindXF( rStyleSheet );
2891 if( nXFId == EXC_XFID_NOTFOUND )
2893 // not found - insert new style XF and STYLE
2894 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2895 if( nXFId < EXC_XFLIST_HARDLIMIT )
2897 auto pNewExp = new XclExpXF( GetRoot(), rStyleSheet );
2898 maXFList.AppendNewRecord( pNewExp );
2899 // create the STYLE record
2900 if( !rStyleSheet.GetName().isEmpty() )
2901 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
2902 maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
2904 else
2905 // list full - fall back to default style XF
2906 nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2908 return nXFId;
2911 void XclExpXFBuffer::InsertUserStyles()
2913 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SfxStyleFamily::Para );
2914 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
2915 if( pStyleSheet->IsUserDefined() && !lclIsBuiltInStyle( pStyleSheet->GetName() ) )
2916 InsertStyleXF( *pStyleSheet );
2919 sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef const & xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2921 sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2922 maXFList.AppendRecord( xXF );
2923 maXFFindMap[ToFindKey(*xXF)].push_back(nXFId);
2924 XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
2925 rInfo.mnStyleId = nStyleId;
2926 rInfo.mnLevel = nLevel;
2927 rInfo.mbPredefined = true;
2928 return nXFId;
2931 sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef const & xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2933 sal_uInt32 nXFId = AppendBuiltInXF( xXF, nStyleId, nLevel );
2934 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2935 maBuiltInMap[ nXFId ].mbHasStyleRec = true; // mark existing STYLE record
2936 return nXFId;
2939 static XclExpCellArea lcl_GetPatternFill_None()
2941 XclExpCellArea aFill;
2942 aFill.mnPattern = EXC_PATT_NONE;
2943 return aFill;
2946 static XclExpCellArea lcl_GetPatternFill_Gray125()
2948 XclExpCellArea aFill;
2949 aFill.mnPattern = EXC_PATT_12_5_PERC;
2950 aFill.mnForeColor = 0;
2951 aFill.mnBackColor = 0;
2952 return aFill;
2955 void XclExpXFBuffer::InsertDefaultRecords()
2957 maFills.push_back( lcl_GetPatternFill_None() );
2958 maFills.push_back( lcl_GetPatternFill_Gray125() );
2960 // index 0: default style
2961 if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScResId( STR_STYLENAME_STANDARD ), SfxStyleFamily::Para ) )
2963 XclExpXFRef xDefStyle = new XclExpXF( GetRoot(), *pDefStyleSheet );
2964 sal_uInt32 nXFId = AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2965 // mark this XF as not predefined, prevents overwriting
2966 maBuiltInMap[ nXFId ].mbPredefined = false;
2968 else
2970 OSL_FAIL( "XclExpXFBuffer::InsertDefaultRecords - default style not found" );
2971 XclExpXFRef xDefStyle = new XclExpDefaultXF( GetRoot(), false );
2972 xDefStyle->SetAllUsedFlags( true );
2973 AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2976 // index 1-14: RowLevel and ColLevel styles (without STYLE records)
2977 XclExpDefaultXF aLevelStyle( GetRoot(), false );
2978 // RowLevel_1, ColLevel_1
2979 aLevelStyle.SetFont( 1 );
2980 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_ROWLEVEL, 0 );
2981 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_COLLEVEL, 0 );
2982 // RowLevel_2, ColLevel_2
2983 aLevelStyle.SetFont( 2 );
2984 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_ROWLEVEL, 1 );
2985 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_COLLEVEL, 1 );
2986 // RowLevel_3, ColLevel_3 ... RowLevel_7, ColLevel_7
2987 aLevelStyle.SetFont( 0 );
2988 for( sal_uInt8 nLevel = 2; nLevel < EXC_STYLE_LEVELCOUNT; ++nLevel )
2990 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_ROWLEVEL, nLevel );
2991 AppendBuiltInXF( new XclExpDefaultXF( aLevelStyle ), EXC_STYLE_COLLEVEL, nLevel );
2994 // index 15: default hard cell format, placeholder to be able to add more built-in styles
2995 maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
2996 maXFFindMap[ToFindKey(*maXFList.GetRecord(maXFList.GetSize()-1))].push_back(maXFList.GetSize()-1);
2997 maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
2999 // index 16-20: other built-in styles
3000 XclExpDefaultXF aFormatStyle( GetRoot(), false );
3001 aFormatStyle.SetFont( 1 );
3002 aFormatStyle.SetNumFmt( 43 );
3003 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_COMMA );
3004 aFormatStyle.SetNumFmt( 41 );
3005 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_COMMA_0 );
3006 aFormatStyle.SetNumFmt( 44 );
3007 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_CURRENCY );
3008 aFormatStyle.SetNumFmt( 42 );
3009 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_CURRENCY_0 );
3010 aFormatStyle.SetNumFmt( 9 );
3011 AppendBuiltInXFWithStyle( new XclExpDefaultXF( aFormatStyle ), EXC_STYLE_PERCENT );
3013 // other built-in style XF records (i.e. Hyperlink styles) are created on demand
3015 /* Insert the real default hard cell format -> 0 is document default pattern.
3016 Do it here (and not already above) to really have all built-in styles. */
3017 Insert( nullptr, GetDefApiScript() );
3020 void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
3022 OSL_ENSURE( nXFId < maXFIndexVec.size(), "XclExpXFBuffer::AppendXFIndex - XF ID out of range" );
3023 maXFIndexVec[ nXFId ] = static_cast< sal_uInt16 >( maSortedXFList.GetSize() );
3024 XclExpXFRef xXF = maXFList.GetRecord( nXFId );
3025 AddBorderAndFill( *xXF );
3026 maSortedXFList.AppendRecord( xXF );
3027 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::AppendXFIndex - XF not found" );
3030 void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
3032 if( std::none_of( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) )
3034 maBorders.push_back( rXF.GetBorderData() );
3037 if( std::none_of( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) )
3039 maFills.push_back( rXF.GetAreaData() );
3043 XclExpDxfs::XclExpDxfs( const XclExpRoot& rRoot )
3044 : XclExpRoot( rRoot ),
3045 mpKeywordTable( new NfKeywordTable )
3047 // Special number formatter for conversion.
3048 SvNumberFormatterPtr xFormatter(new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ));
3049 xFormatter->FillKeywordTableForExcel( *mpKeywordTable );
3051 SCTAB nTables = rRoot.GetDoc().GetTableCount();
3052 sal_Int32 nDxfId = 0;
3053 for(SCTAB nTab = 0; nTab < nTables; ++nTab)
3055 // Color filters
3056 std::vector<ScDBData*> pDBData = rRoot.GetDoc().GetDBCollection()->GetAllDBsFromTab(nTab);
3057 for (auto& pData : pDBData)
3059 ScRange aRange;
3060 pData->GetArea(aRange);
3061 for (auto nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); nCol++)
3063 ScFilterEntries aFilterEntries;
3064 rRoot.GetDoc().GetFilterEntriesArea(nCol, aRange.aStart.Row(),
3065 aRange.aEnd.Row(), nTab, true, aFilterEntries);
3067 // Excel has all filter values stored as foreground colors
3068 // Does not matter it is text color or cell background color
3069 for (auto& rColor : aFilterEntries.getBackgroundColors())
3071 if (!maColorToDxfId.emplace(rColor, nDxfId).second)
3072 continue;
3074 std::unique_ptr<XclExpCellArea> pExpCellArea(new XclExpCellArea(rColor, 0));
3075 maDxf.push_back(std::make_unique<XclExpDxf>(rRoot, std::move(pExpCellArea)));
3076 nDxfId++;
3078 for (auto& rColor : aFilterEntries.getTextColors())
3080 if (!maColorToDxfId.emplace(rColor, nDxfId).second)
3081 continue;
3083 std::unique_ptr<XclExpCellArea> pExpCellArea(new XclExpCellArea(rColor, 0));
3084 maDxf.push_back(std::make_unique<XclExpDxf>(rRoot, std::move(pExpCellArea)));
3085 nDxfId++;
3090 // Conditional formatting
3091 ScConditionalFormatList* pList = rRoot.GetDoc().GetCondFormList(nTab);
3092 if (pList)
3094 for (const auto& rxItem : *pList)
3096 size_t nEntryCount = rxItem->size();
3097 for (size_t nFormatEntry = 0; nFormatEntry < nEntryCount; ++nFormatEntry)
3099 const ScFormatEntry* pFormatEntry = rxItem->GetEntry(nFormatEntry);
3100 if (!pFormatEntry
3101 || (pFormatEntry->GetType() != ScFormatEntry::Type::Condition
3102 && pFormatEntry->GetType() != ScFormatEntry::Type::Date
3103 && pFormatEntry->GetType() != ScFormatEntry::Type::ExtCondition))
3104 continue;
3106 OUString aStyleName;
3107 if (pFormatEntry->GetType() == ScFormatEntry::Type::Condition
3108 || pFormatEntry->GetType() == ScFormatEntry::Type::ExtCondition)
3110 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
3111 aStyleName= pEntry->GetStyle();
3113 else
3115 const ScCondDateFormatEntry* pEntry = static_cast<const ScCondDateFormatEntry*>(pFormatEntry);
3116 aStyleName = pEntry->GetStyleName();
3119 if (maStyleNameToDxfId.emplace(aStyleName, nDxfId).second)
3121 SfxStyleSheetBase* pStyle = rRoot.GetDoc().GetStyleSheetPool()->Find(aStyleName, SfxStyleFamily::Para);
3122 if(!pStyle)
3123 continue;
3125 SfxItemSet& rSet = pStyle->GetItemSet();
3127 std::unique_ptr<XclExpCellBorder> pBorder(new XclExpCellBorder);
3128 if (!pBorder->FillFromItemSet( rSet, GetPalette(), GetBiff()) )
3130 pBorder.reset();
3133 std::unique_ptr<XclExpCellAlign> pAlign(new XclExpCellAlign);
3134 if (!pAlign->FillFromItemSet(rRoot, rSet, false, GetBiff()))
3136 pAlign.reset();
3139 std::unique_ptr<XclExpCellProt> pCellProt(new XclExpCellProt);
3140 if (!pCellProt->FillFromItemSet( rSet ))
3142 pCellProt.reset();
3145 std::unique_ptr<XclExpColor> pColor(new XclExpColor);
3146 if(!pColor->FillFromItemSet( rSet ))
3148 pColor.reset();
3151 std::unique_ptr<XclExpDxfFont> pFont(new XclExpDxfFont(rRoot, rSet));
3153 std::unique_ptr<XclExpNumFmt> pNumFormat;
3154 const SfxPoolItem *pPoolItem = nullptr;
3155 if( rSet.GetItemState( ATTR_VALUE_FORMAT, true, &pPoolItem ) == SfxItemState::SET )
3157 sal_uInt32 nScNumFmt = static_cast< const SfxUInt32Item* >(pPoolItem)->GetValue();
3158 sal_Int32 nXclNumFmt = GetRoot().GetNumFmtBuffer().Insert(nScNumFmt);
3159 pNumFormat.reset(new XclExpNumFmt( nScNumFmt, nXclNumFmt, GetNumberFormatCode( *this, nScNumFmt, xFormatter.get(), mpKeywordTable.get() )));
3162 maDxf.push_back(std::make_unique<XclExpDxf>( rRoot, std::move(pAlign), std::move(pBorder),
3163 std::move(pFont), std::move(pNumFormat), std::move(pCellProt), std::move(pColor) ));
3164 ++nDxfId;
3173 sal_Int32 XclExpDxfs::GetDxfId( const OUString& rStyleName ) const
3175 std::map<OUString, sal_Int32>::const_iterator itr = maStyleNameToDxfId.find(rStyleName);
3176 if(itr!= maStyleNameToDxfId.end())
3177 return itr->second;
3178 return -1;
3181 sal_Int32 XclExpDxfs::GetDxfByColor(Color aColor) const
3183 std::map<Color, sal_Int32>::const_iterator itr = maColorToDxfId.find(aColor);
3184 if (itr != maColorToDxfId.end())
3185 return itr->second;
3186 return -1;
3189 void XclExpDxfs::AddColor(Color aColor)
3191 maColorToDxfId.emplace(aColor, maDxf.size());
3193 std::unique_ptr<XclExpCellArea> pExpCellArea(new XclExpCellArea(aColor, 0));
3194 maDxf.push_back(std::make_unique<XclExpDxf>(GetRoot(), std::move(pExpCellArea)));
3197 void XclExpDxfs::SaveXml( XclExpXmlStream& rStrm )
3199 if(maDxf.empty())
3200 return;
3202 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3203 rStyleSheet->startElement(XML_dxfs, XML_count, OString::number(maDxf.size()));
3205 for ( auto& rxDxf : maDxf )
3207 rxDxf->SaveXml( rStrm );
3210 rStyleSheet->endElement( XML_dxfs );
3213 XclExpDxf::XclExpDxf( const XclExpRoot& rRoot, std::unique_ptr<XclExpCellAlign> pAlign, std::unique_ptr<XclExpCellBorder> pBorder,
3214 std::unique_ptr<XclExpDxfFont> pFont, std::unique_ptr<XclExpNumFmt> pNumberFmt, std::unique_ptr<XclExpCellProt> pProt,
3215 std::unique_ptr<XclExpColor> pColor)
3216 : XclExpRoot( rRoot ),
3217 mpAlign(std::move(pAlign)),
3218 mpBorder(std::move(pBorder)),
3219 mpFont(std::move(pFont)),
3220 mpNumberFmt(std::move(pNumberFmt)),
3221 mpProt(std::move(pProt)),
3222 mpColor(std::move(pColor))
3226 XclExpDxf::XclExpDxf(const XclExpRoot& rRoot, std::unique_ptr<XclExpCellArea> pCellArea)
3227 : XclExpRoot(rRoot)
3228 , mpCellArea(std::move(pCellArea))
3232 XclExpDxf::~XclExpDxf()
3236 void XclExpDxf::SaveXml( XclExpXmlStream& rStrm )
3238 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3239 rStyleSheet->startElement(XML_dxf);
3241 if (mpFont)
3242 mpFont->SaveXml(rStrm);
3243 if (mpNumberFmt)
3244 mpNumberFmt->SaveXml(rStrm);
3245 if (mpColor)
3246 mpColor->SaveXml(rStrm);
3247 if (mpAlign)
3248 mpAlign->SaveXml(rStrm);
3249 if (mpBorder)
3250 mpBorder->SaveXml(rStrm);
3251 if (mpProt)
3252 mpProt->SaveXml(rStrm);
3253 if (mpCellArea)
3254 mpCellArea->SaveXml(rStrm);
3255 rStyleSheet->endElement( XML_dxf );
3258 void XclExpDxf::SaveXmlExt( XclExpXmlStream& rStrm )
3260 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3261 rStyleSheet->startElementNS( XML_x14, XML_dxf );
3263 if (mpFont)
3264 mpFont->SaveXml(rStrm);
3265 if (mpNumberFmt)
3266 mpNumberFmt->SaveXml(rStrm);
3267 if (mpColor)
3268 mpColor->SaveXml(rStrm);
3269 if (mpAlign)
3270 mpAlign->SaveXml(rStrm);
3271 if (mpBorder)
3272 mpBorder->SaveXml(rStrm);
3273 if (mpProt)
3274 mpProt->SaveXml(rStrm);
3275 rStyleSheet->endElementNS( XML_x14, XML_dxf );
3279 XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
3280 : XclExpRoot( rRoot )
3284 void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
3286 sax_fastparser::FSHelperPtr aStyleSheet = rStrm.CreateOutputStream(
3287 "xl/styles.xml",
3288 u"styles.xml",
3289 rStrm.GetCurrentStream()->getOutputStream(),
3290 "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3291 oox::getRelationship(Relationship::STYLES));
3292 rStrm.PushStream( aStyleSheet );
3294 aStyleSheet->startElement(XML_styleSheet, XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)));
3296 CreateRecord( EXC_ID_FORMATLIST )->SaveXml( rStrm );
3297 CreateRecord( EXC_ID_FONTLIST )->SaveXml( rStrm );
3298 CreateRecord( EXC_ID_XFLIST )->SaveXml( rStrm );
3299 CreateRecord( EXC_ID_DXFS )->SaveXml( rStrm );
3300 CreateRecord( EXC_ID_PALETTE )->SaveXml( rStrm );
3302 aStyleSheet->endElement( XML_styleSheet );
3304 rStrm.PopStream();
3307 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */