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