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