diff options
Diffstat (limited to 'sc/source/filter/oox/stylesbuffer.cxx')
-rw-r--r-- | sc/source/filter/oox/stylesbuffer.cxx | 3064 |
1 files changed, 3064 insertions, 0 deletions
diff --git a/sc/source/filter/oox/stylesbuffer.cxx b/sc/source/filter/oox/stylesbuffer.cxx new file mode 100644 index 000000000..fd4401446 --- /dev/null +++ b/sc/source/filter/oox/stylesbuffer.cxx @@ -0,0 +1,3064 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stylesbuffer.hxx> + +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/awt/FontFamily.hpp> +#include <com/sun/star/awt/FontPitch.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontType.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/awt/XFont2.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/table/BorderLineStyle.hpp> +#include <com/sun/star/table/CellVertJustify2.hpp> +#include <com/sun/star/table/CellJustifyMethod.hpp> +#include <editeng/justifyitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/borderline.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/lineitem.hxx> +#include <editeng/brushitem.hxx> +#include <svx/rotmodit.hxx> +#include <tools/fontenum.hxx> +#include <tools/UnitConversion.hxx> +#include <vcl/unohelp.hxx> +#include <rtl/tencinfo.h> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <oox/core/filterbase.hxx> +#include <oox/helper/attributelist.hxx> +#include <oox/helper/binaryinputstream.hxx> +#include <oox/helper/containerhelper.hxx> +#include <oox/helper/propertymap.hxx> +#include <oox/helper/propertyset.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/properties.hxx> +#include <oox/token/tokens.hxx> +#include <themebuffer.hxx> +#include <unitconverter.hxx> +#include <document.hxx> +#include <stlpool.hxx> +#include <docpool.hxx> +#include <ftools.hxx> +#include <scitems.hxx> +#include <attrib.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <documentimport.hxx> +#include <patattr.hxx> +#include <stlsheet.hxx> +#include <biffhelper.hxx> + +namespace oox::xls { + +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; + + +namespace { + +// OOXML constants ------------------------------------------------------------ + +// OOXML predefined color indexes (also used in BIFF3-BIFF8) +const sal_Int32 OOX_COLOR_USEROFFSET = 0; /// First user defined color in palette (OOXML/BIFF12). + +// OOXML font family (also used in BIFF) +const sal_Int32 OOX_FONTFAMILY_NONE = 0; +const sal_Int32 OOX_FONTFAMILY_ROMAN = 1; +const sal_Int32 OOX_FONTFAMILY_SWISS = 2; +const sal_Int32 OOX_FONTFAMILY_MODERN = 3; +const sal_Int32 OOX_FONTFAMILY_SCRIPT = 4; +const sal_Int32 OOX_FONTFAMILY_DECORATIVE = 5; + +// OOXML cell text direction (also used in BIFF) +const sal_Int32 OOX_XF_TEXTDIR_CONTEXT = 0; +const sal_Int32 OOX_XF_TEXTDIR_LTR = 1; +const sal_Int32 OOX_XF_TEXTDIR_RTL = 2; + +// OOXML cell rotation (also used in BIFF) +const sal_Int32 OOX_XF_ROTATION_NONE = 0; +const sal_Int32 OOX_XF_ROTATION_STACKED = 255; + +// OOXML cell indentation +const sal_Int32 OOX_XF_INDENT_NONE = 0; + +// OOXML built-in cell styles (also used in BIFF) +const sal_Int32 OOX_STYLE_NORMAL = 0; /// Default cell style. +const sal_Int32 OOX_STYLE_ROWLEVEL = 1; /// RowLevel_x cell style. +const sal_Int32 OOX_STYLE_COLLEVEL = 2; /// ColLevel_x cell style. + +// BIFF12 constants ----------------------------------------------------------- + +// BIFF12 color types +const sal_uInt8 BIFF12_COLOR_AUTO = 0; +const sal_uInt8 BIFF12_COLOR_INDEXED = 1; +const sal_uInt8 BIFF12_COLOR_RGB = 2; +const sal_uInt8 BIFF12_COLOR_THEME = 3; + +// BIFF12 diagonal borders +const sal_uInt8 BIFF12_BORDER_DIAG_TLBR = 0x01; /// Top-left to bottom-right. +const sal_uInt8 BIFF12_BORDER_DIAG_BLTR = 0x02; /// Bottom-left to top-right. + +// BIFF12 gradient fill +const sal_Int32 BIFF12_FILL_GRADIENT = 40; + +// BIFF12 XF flags +const sal_uInt32 BIFF12_XF_WRAPTEXT = 0x00400000; +const sal_uInt32 BIFF12_XF_JUSTLASTLINE = 0x00800000; +const sal_uInt32 BIFF12_XF_SHRINK = 0x01000000; +const sal_uInt32 BIFF12_XF_LOCKED = 0x10000000; +const sal_uInt32 BIFF12_XF_HIDDEN = 0x20000000; + +// BIFF12 XF attribute used flags +const sal_uInt16 BIFF12_XF_NUMFMT_USED = 0x0001; +const sal_uInt16 BIFF12_XF_FONT_USED = 0x0002; +const sal_uInt16 BIFF12_XF_ALIGN_USED = 0x0004; +const sal_uInt16 BIFF12_XF_BORDER_USED = 0x0008; +const sal_uInt16 BIFF12_XF_AREA_USED = 0x0010; +const sal_uInt16 BIFF12_XF_PROT_USED = 0x0020; + +// BIFF12 DXF constants +const sal_uInt16 BIFF12_DXF_FILL_PATTERN = 0; +const sal_uInt16 BIFF12_DXF_FILL_FGCOLOR = 1; +const sal_uInt16 BIFF12_DXF_FILL_BGCOLOR = 2; +const sal_uInt16 BIFF12_DXF_FILL_GRADIENT = 3; +const sal_uInt16 BIFF12_DXF_FILL_STOP = 4; +const sal_uInt16 BIFF12_DXF_FONT_COLOR = 5; +const sal_uInt16 BIFF12_DXF_BORDER_TOP = 6; +const sal_uInt16 BIFF12_DXF_BORDER_BOTTOM = 7; +const sal_uInt16 BIFF12_DXF_BORDER_LEFT = 8; +const sal_uInt16 BIFF12_DXF_BORDER_RIGHT = 9; +const sal_uInt16 BIFF12_DXF_FONT_NAME = 24; +const sal_uInt16 BIFF12_DXF_FONT_WEIGHT = 25; +const sal_uInt16 BIFF12_DXF_FONT_UNDERLINE = 26; +const sal_uInt16 BIFF12_DXF_FONT_ESCAPEMENT = 27; +const sal_uInt16 BIFF12_DXF_FONT_ITALIC = 28; +const sal_uInt16 BIFF12_DXF_FONT_STRIKE = 29; +const sal_uInt16 BIFF12_DXF_FONT_OUTLINE = 30; +const sal_uInt16 BIFF12_DXF_FONT_SHADOW = 31; +const sal_uInt16 BIFF12_DXF_FONT_HEIGHT = 36; +const sal_uInt16 BIFF12_DXF_FONT_SCHEME = 37; +const sal_uInt16 BIFF12_DXF_NUMFMT_CODE = 38; +const sal_uInt16 BIFF12_DXF_NUMFMT_ID = 41; + +// BIFF12 CELLSTYLE flags +const sal_uInt16 BIFF12_CELLSTYLE_BUILTIN = 0x0001; +const sal_uInt16 BIFF12_CELLSTYLE_HIDDEN = 0x0002; +const sal_uInt16 BIFF12_CELLSTYLE_CUSTOM = 0x0004; + +// BIFF constants ------------------------------------------------------------- + +// BIFF font flags, also used in BIFF12 +const sal_uInt16 BIFF_FONTFLAG_ITALIC = 0x0002; +const sal_uInt16 BIFF_FONTFLAG_STRIKEOUT = 0x0008; +const sal_uInt16 BIFF_FONTFLAG_OUTLINE = 0x0010; +const sal_uInt16 BIFF_FONTFLAG_SHADOW = 0x0020; + +// BIFF font weight +const sal_uInt16 BIFF_FONTWEIGHT_BOLD = 450; + +// BIFF font underline, also used in BIFF12 +const sal_uInt8 BIFF_FONTUNDERL_NONE = 0; +const sal_uInt8 BIFF_FONTUNDERL_SINGLE = 1; +const sal_uInt8 BIFF_FONTUNDERL_DOUBLE = 2; +const sal_uInt8 BIFF_FONTUNDERL_SINGLE_ACC = 33; +const sal_uInt8 BIFF_FONTUNDERL_DOUBLE_ACC = 34; + +::Color lclReadRgbColor( BinaryInputStream& rStrm ) +{ + sal_uInt8 nR, nG, nB, nA; + nR = rStrm.readuChar(); + nG = rStrm.readuChar(); + nB = rStrm.readuChar(); + nA = rStrm.readuChar(); + sal_Int32 nValue = nA; + nValue <<= 8; + nValue |= nR; + nValue <<= 8; + nValue |= nG; + nValue <<= 8; + nValue |= nB; + return ::Color(ColorTransparency, nValue); +} + +} // namespace + +ExcelGraphicHelper::ExcelGraphicHelper( const WorkbookHelper& rHelper ) : + GraphicHelper( rHelper.getBaseFilter().getComponentContext(), rHelper.getBaseFilter().getTargetFrame(), rHelper.getBaseFilter().getStorage() ), + WorkbookHelper( rHelper ) +{ +} + +::Color ExcelGraphicHelper::getSchemeColor( sal_Int32 nToken ) const +{ + return getTheme().getColorByToken( nToken ); +} + +::Color ExcelGraphicHelper::getPaletteColor( sal_Int32 nPaletteIdx ) const +{ + return getStyles().getPaletteColor( nPaletteIdx ); +} + +void Color::setAuto() +{ + clearTransformations(); + setSchemeClr( XML_phClr ); +} + +void Color::setRgb( ::Color nRgbValue, double fTint ) +{ + clearTransformations(); + setSrgbClr( sal_uInt32(nRgbValue) & 0xFFFFFF ); + if( fTint != 0.0 ) addExcelTintTransformation( fTint ); +} + +void Color::setTheme( sal_Int32 nThemeIdx, double fTint ) +{ + clearTransformations(); + static const sal_Int32 spnColorTokens[] = { + XML_lt1, XML_dk1, XML_lt2, XML_dk2, XML_accent1, XML_accent2, + XML_accent3, XML_accent4, XML_accent5, XML_accent6, XML_hlink, XML_folHlink }; + setSchemeClr( STATIC_ARRAY_SELECT( spnColorTokens, nThemeIdx, XML_TOKEN_INVALID ) ); + if( fTint != 0.0 ) addExcelTintTransformation( fTint ); +} + +void Color::setIndexed( sal_Int32 nPaletteIdx, double fTint ) +{ + clearTransformations(); + setPaletteClr( nPaletteIdx ); + if( fTint != 0.0 ) addExcelTintTransformation( fTint ); +} + +void Color::importColor( const AttributeList& rAttribs ) +{ + // tdf#113271 The order of import color is very important in case of more than one color attributes was provided. + // This order (theme -> rgb -> indexed -> auto) is not documented and was gathered experimentally based on MS Excel 2013. + if( rAttribs.hasAttribute( XML_theme ) ) + setTheme( rAttribs.getInteger( XML_theme, -1 ), rAttribs.getDouble( XML_tint, 0.0 ) ); + else if( rAttribs.hasAttribute( XML_rgb ) ) + setRgb( ::Color(ColorTransparency, rAttribs.getIntegerHex( XML_rgb, sal_Int32(API_RGB_TRANSPARENT) ) ), rAttribs.getDouble( XML_tint, 0.0 ) ); + else if( rAttribs.hasAttribute( XML_indexed ) ) + setIndexed( rAttribs.getInteger( XML_indexed, -1 ), rAttribs.getDouble( XML_tint, 0.0 ) ); + else if( rAttribs.getBool( XML_auto, false ) ) + setAuto(); + else + { + OSL_FAIL( "Color::importColor - unknown color type" ); + setAuto(); + } +} + +void Color::importColor( SequenceInputStream& rStrm ) +{ + sal_uInt8 nFlags, nIndex; + sal_Int16 nTint; + nFlags = rStrm.readuChar(); + nIndex = rStrm.readuChar(); + nTint = rStrm.readInt16(); + + // scale tint from signed 16-bit to double range -1.0 ... 1.0 + double fTint = nTint; + if( nTint < 0 ) + fTint /= -SAL_MIN_INT16; + else if( nTint > 0 ) + fTint /= SAL_MAX_INT16; + + switch( extractValue< sal_uInt8 >( nFlags, 1, 7 ) ) + { + case BIFF12_COLOR_AUTO: + setAuto(); + rStrm.skip( 4 ); + break; + case BIFF12_COLOR_INDEXED: + setIndexed( nIndex, fTint ); + rStrm.skip( 4 ); + break; + case BIFF12_COLOR_RGB: + setRgb( lclReadRgbColor( rStrm ), fTint ); + break; + case BIFF12_COLOR_THEME: + setTheme( nIndex, fTint ); + rStrm.skip( 4 ); + break; + default: + OSL_FAIL( "Color::importColor - unknown color type" ); + setAuto(); + rStrm.skip( 4 ); + } +} + +void Color::importColorId( SequenceInputStream& rStrm ) +{ + setIndexed( rStrm.readInt32() ); +} + +SequenceInputStream& operator>>( SequenceInputStream& rStrm, Color& orColor ) +{ + orColor.importColor( rStrm ); + return rStrm; +} + +namespace { + +/** Standard EGA colors, bright. */ +#define PALETTE_EGA_COLORS_LIGHT \ + ::Color(0x000000), ::Color(0xFFFFFF), ::Color(0xFF0000), ::Color(0x00FF00), ::Color(0x0000FF), ::Color(0xFFFF00), ::Color(0xFF00FF), ::Color(0x00FFFF) +/** Standard EGA colors), dark. */ +#define PALETTE_EGA_COLORS_DARK \ + ::Color(0x800000), ::Color(0x008000), ::Color(0x000080), ::Color(0x808000), ::Color(0x800080), ::Color(0x008080), ::Color(0xC0C0C0), ::Color(0x808080) + +/** Default color table for BIFF8/BIFF12/OOXML. */ +const ::Color spnDefColors8[] = +{ +/* 0 */ PALETTE_EGA_COLORS_LIGHT, +/* 8 */ PALETTE_EGA_COLORS_LIGHT, +/* 16 */ PALETTE_EGA_COLORS_DARK, +/* 24 */ ::Color(0x9999FF), ::Color(0x993366), ::Color(0xFFFFCC), ::Color(0xCCFFFF), ::Color(0x660066), ::Color(0xFF8080), ::Color(0x0066CC), ::Color(0xCCCCFF), +/* 32 */ ::Color(0x000080), ::Color(0xFF00FF), ::Color(0xFFFF00), ::Color(0x00FFFF), ::Color(0x800080), ::Color(0x800000), ::Color(0x008080), ::Color(0x0000FF), +/* 40 */ ::Color(0x00CCFF), ::Color(0xCCFFFF), ::Color(0xCCFFCC), ::Color(0xFFFF99), ::Color(0x99CCFF), ::Color(0xFF99CC), ::Color(0xCC99FF), ::Color(0xFFCC99), +/* 48 */ ::Color(0x3366FF), ::Color(0x33CCCC), ::Color(0x99CC00), ::Color(0xFFCC00), ::Color(0xFF9900), ::Color(0xFF6600), ::Color(0x666699), ::Color(0x969696), +/* 56 */ ::Color(0x003366), ::Color(0x339966), ::Color(0x003300), ::Color(0x333300), ::Color(0x993300), ::Color(0x993366), ::Color(0x333399), ::Color(0x333333) +}; + +#undef PALETTE_EGA_COLORS_LIGHT +#undef PALETTE_EGA_COLORS_DARK + +} // namespace + +ColorPalette::ColorPalette( const WorkbookHelper& rHelper ) + : WorkbookHelper(rHelper) + , mnAppendIndex(0) +{ + // default colors + maColors.insert( maColors.begin(), spnDefColors8, spnDefColors8 + SAL_N_ELEMENTS(spnDefColors8) ); + mnAppendIndex = OOX_COLOR_USEROFFSET; +} + +void ColorPalette::importPaletteColor( const AttributeList& rAttribs ) +{ + appendColor( ::Color(ColorTransparency, rAttribs.getIntegerHex( XML_rgb, sal_Int32(API_RGB_WHITE) ) ) ); +} + +void ColorPalette::importPaletteColor( SequenceInputStream& rStrm ) +{ + ::Color nRgb = lclReadRgbColor( rStrm ); + appendColor( nRgb ); +} + +::Color ColorPalette::getColor( sal_Int32 nPaletteIdx ) const +{ + ::Color nColor = API_RGB_TRANSPARENT; + if( const ::Color* pnPaletteColor = ContainerHelper::getVectorElement( maColors, nPaletteIdx ) ) + { + nColor = *pnPaletteColor; + } + else switch( nPaletteIdx ) + { + case OOX_COLOR_WINDOWTEXT3: + case OOX_COLOR_WINDOWTEXT: + case OOX_COLOR_CHWINDOWTEXT: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_windowText ); break; + case OOX_COLOR_WINDOWBACK3: + case OOX_COLOR_WINDOWBACK: + case OOX_COLOR_CHWINDOWBACK: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_window ); break; + case OOX_COLOR_BUTTONBACK: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_btnFace ); break; + case OOX_COLOR_CHBORDERAUTO: nColor = API_RGB_BLACK; /* really always black? */ break; + case OOX_COLOR_NOTEBACK: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_infoBk ); break; + case OOX_COLOR_NOTETEXT: nColor = getBaseFilter().getGraphicHelper().getSystemColor( XML_infoText ); break; + case OOX_COLOR_FONTAUTO: nColor = API_RGB_TRANSPARENT; break; + default: OSL_FAIL( "ColorPalette::getColor - unknown color index" ); + } + return nColor; +} + +void ColorPalette::appendColor( ::Color nRGBValue ) +{ + if( mnAppendIndex < maColors.size() ) + maColors[ mnAppendIndex ] = nRGBValue; + else + maColors.push_back( nRGBValue ); + ++mnAppendIndex; +} + +namespace { + +void lclSetFontName( ApiScriptFontName& rFontName, const FontDescriptor& rFontDesc, bool bHasGlyphs ) +{ + if( bHasGlyphs ) + { + rFontName.maName = rFontDesc.Name; + rFontName.mnFamily = rFontDesc.Family; + // API font descriptor contains rtl_TextEncoding constants + rFontName.mnTextEnc = rFontDesc.CharSet; + } + else + { + rFontName = ApiScriptFontName(); + } +} + +} // namespace + +FontModel::FontModel() : + mnScheme( XML_none ), + mnFamily( OOX_FONTFAMILY_NONE ), + mnCharSet( WINDOWS_CHARSET_DEFAULT ), + mfHeight( 0.0 ), + mnUnderline( XML_none ), + mnEscapement( XML_baseline ), + mbBold( false ), + mbItalic( false ), + mbStrikeout( false ), + mbOutline( false ), + mbShadow( false ) +{ +} + +void FontModel::setBiff12Scheme( sal_uInt8 nScheme ) +{ + static const sal_Int32 spnSchemes[] = { XML_none, XML_major, XML_minor }; + mnScheme = STATIC_ARRAY_SELECT( spnSchemes, nScheme, XML_none ); +} + +void FontModel::setBiffHeight( sal_uInt16 nHeight ) +{ + mfHeight = nHeight / 20.0; // convert twips to points +} + +void FontModel::setBiffWeight( sal_uInt16 nWeight ) +{ + mbBold = nWeight >= BIFF_FONTWEIGHT_BOLD; +} + +void FontModel::setBiffUnderline( sal_uInt16 nUnderline ) +{ + switch( nUnderline ) + { + case BIFF_FONTUNDERL_NONE: mnUnderline = XML_none; break; + case BIFF_FONTUNDERL_SINGLE: mnUnderline = XML_single; break; + case BIFF_FONTUNDERL_DOUBLE: mnUnderline = XML_double; break; + case BIFF_FONTUNDERL_SINGLE_ACC: mnUnderline = XML_singleAccounting; break; + case BIFF_FONTUNDERL_DOUBLE_ACC: mnUnderline = XML_doubleAccounting; break; + default: mnUnderline = XML_none; + } +} + +void FontModel::setBiffEscapement( sal_uInt16 nEscapement ) +{ + static const sal_Int32 spnEscapes[] = { XML_baseline, XML_superscript, XML_subscript }; + mnEscapement = STATIC_ARRAY_SELECT( spnEscapes, nEscapement, XML_baseline ); +} + +ApiFontUsedFlags::ApiFontUsedFlags( bool bAllUsed ) : + mbNameUsed( bAllUsed ), + mbColorUsed( bAllUsed ), + mbSchemeUsed( bAllUsed ), + mbHeightUsed( bAllUsed ), + mbUnderlineUsed( bAllUsed ), + mbEscapementUsed( bAllUsed ), + mbWeightUsed( bAllUsed ), + mbPostureUsed( bAllUsed ), + mbStrikeoutUsed( bAllUsed ), + mbOutlineUsed( bAllUsed ), + mbShadowUsed( bAllUsed ) +{ +} + +ApiScriptFontName::ApiScriptFontName() : + mnFamily( css::awt::FontFamily::DONTKNOW ), + mnTextEnc( RTL_TEXTENCODING_DONTKNOW ) +{ +} + +ApiFontData::ApiFontData() : + maDesc( + "Calibri", + 220, // height 11 points + 0, + OUString(), + css::awt::FontFamily::DONTKNOW, + RTL_TEXTENCODING_DONTKNOW, + css::awt::FontPitch::DONTKNOW, + 100.0, + css::awt::FontWeight::NORMAL, + css::awt::FontSlant_NONE, + css::awt::FontUnderline::NONE, + css::awt::FontStrikeout::NONE, + 0.0, + false, + false, + css::awt::FontType::DONTKNOW ), + mnColor( API_RGB_TRANSPARENT ), + mnEscapement( API_ESCAPE_NONE ), + mnEscapeHeight( API_ESCAPEHEIGHT_NONE ), + mbOutline( false ), + mbShadow( false ) +{ + maLatinFont.maName = maDesc.Name; +} + +Font::Font( const WorkbookHelper& rHelper, bool bDxf ) : + WorkbookHelper( rHelper ), + maModel( rHelper.getTheme().getDefaultFontModel() ), + maUsedFlags( !bDxf ), + mbDxf( bDxf ) +{ +} + +Font::Font( const WorkbookHelper& rHelper, const FontModel& rModel ) : + WorkbookHelper( rHelper ), + maModel( rModel ), + maUsedFlags( true ), + mbDxf( false ) +{ +} + +void Font::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + const FontModel& rDefModel = getTheme().getDefaultFontModel(); + switch( nElement ) + { + case XLS_TOKEN( name ): // when in <font> element + case XLS_TOKEN( rFont ): // when in <rPr> element + if( rAttribs.hasAttribute( XML_val ) ) + { + maModel.maName = rAttribs.getXString( XML_val, OUString() ); + maUsedFlags.mbNameUsed = true; + } + break; + case XLS_TOKEN( scheme ): + maModel.mnScheme = rAttribs.getToken( XML_val, rDefModel.mnScheme ); + break; + case XLS_TOKEN( family ): + maModel.mnFamily = rAttribs.getInteger( XML_val, rDefModel.mnFamily ); + break; + case XLS_TOKEN( charset ): + maModel.mnCharSet = rAttribs.getInteger( XML_val, rDefModel.mnCharSet ); + break; + case XLS_TOKEN( sz ): + maModel.mfHeight = rAttribs.getDouble( XML_val, rDefModel.mfHeight ); + maUsedFlags.mbHeightUsed = true; + break; + case XLS_TOKEN( color ): + maModel.maColor.importColor( rAttribs ); + maUsedFlags.mbColorUsed = true; + break; + case XLS_TOKEN( u ): + maModel.mnUnderline = rAttribs.getToken( XML_val, XML_single ); + maUsedFlags.mbUnderlineUsed = true; + break; + case XLS_TOKEN( vertAlign ): + maModel.mnEscapement = rAttribs.getToken( XML_val, XML_baseline ); + maUsedFlags.mbEscapementUsed = true; + break; + case XLS_TOKEN( b ): + maModel.mbBold = rAttribs.getBool( XML_val, true ); + maUsedFlags.mbWeightUsed = true; + break; + case XLS_TOKEN( i ): + maModel.mbItalic = rAttribs.getBool( XML_val, true ); + maUsedFlags.mbPostureUsed = true; + break; + case XLS_TOKEN( strike ): + maModel.mbStrikeout = rAttribs.getBool( XML_val, true ); + maUsedFlags.mbStrikeoutUsed = true; + break; + case XLS_TOKEN( outline ): + maModel.mbOutline = rAttribs.getBool( XML_val, true ); + maUsedFlags.mbOutlineUsed = true; + break; + case XLS_TOKEN( shadow ): + maModel.mbShadow = rAttribs.getBool( XML_val, true ); + maUsedFlags.mbShadowUsed = true; + break; + } +} + +void Font::importFont( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( mbDxf, "sc", "Font::importFont - unexpected conditional formatting flag" ); + + sal_uInt16 nHeight, nFlags, nWeight, nEscapement; + sal_uInt8 nUnderline, nFamily, nCharSet, nScheme; + nHeight = rStrm.readuInt16(); + nFlags = rStrm.readuInt16(); + nWeight = rStrm.readuInt16(); + nEscapement = rStrm.readuInt16(); + nUnderline = rStrm.readuChar(); + nFamily = rStrm.readuChar(); + nCharSet = rStrm.readuChar(); + rStrm.skip( 1 ); + rStrm >> maModel.maColor; + nScheme = rStrm.readuChar(); + rStrm >> maModel.maName; + + // equal constants in all BIFFs for weight, underline, and escapement + maModel.setBiff12Scheme( nScheme ); + maModel.setBiffHeight( nHeight ); + maModel.setBiffWeight( nWeight ); + maModel.setBiffUnderline( nUnderline ); + maModel.setBiffEscapement( nEscapement ); + maModel.mnFamily = nFamily; + maModel.mnCharSet = nCharSet; + // equal flags in all BIFFs + maModel.mbItalic = getFlag( nFlags, BIFF_FONTFLAG_ITALIC ); + maModel.mbStrikeout = getFlag( nFlags, BIFF_FONTFLAG_STRIKEOUT ); + maModel.mbOutline = getFlag( nFlags, BIFF_FONTFLAG_OUTLINE ); + maModel.mbShadow = getFlag( nFlags, BIFF_FONTFLAG_SHADOW ); +} + +void Font::importDxfName( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfName - missing conditional formatting flag" ); + maModel.maName = BiffHelper::readString( rStrm, false ); + maUsedFlags.mbColorUsed = true; +} + +void Font::importDxfColor( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfColor - missing conditional formatting flag" ); + rStrm >> maModel.maColor; + maUsedFlags.mbColorUsed = true; +} + +void Font::importDxfScheme( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfScheme - missing conditional formatting flag" ); + maModel.setBiff12Scheme( rStrm.readuInt8() ); + maUsedFlags.mbSchemeUsed = true; +} + +void Font::importDxfHeight( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfHeight - missing conditional formatting flag" ); + maModel.setBiffHeight( rStrm.readuInt16() ); + maUsedFlags.mbHeightUsed = true; +} + +void Font::importDxfWeight( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfWeight - missing conditional formatting flag" ); + maModel.setBiffWeight( rStrm.readuInt16() ); + maUsedFlags.mbWeightUsed = true; +} + +void Font::importDxfUnderline( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfUnderline - missing conditional formatting flag" ); + maModel.setBiffUnderline( rStrm.readuInt16() ); + maUsedFlags.mbUnderlineUsed = true; +} + +void Font::importDxfEscapement( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfEscapement - missing conditional formatting flag" ); + maModel.setBiffEscapement( rStrm.readuInt16() ); + maUsedFlags.mbEscapementUsed = true; +} + +void Font::importDxfFlag( sal_Int32 nElement, SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Font::importDxfFlag - missing conditional formatting flag" ); + bool bFlag = rStrm.readuInt8() != 0; + switch( nElement ) + { + case XML_i: + maModel.mbItalic = bFlag; + maUsedFlags.mbPostureUsed = true; + break; + case XML_strike: + maModel.mbStrikeout = bFlag; + maUsedFlags.mbStrikeoutUsed = true; + break; + case XML_outline: + maModel.mbOutline = bFlag; + maUsedFlags.mbOutlineUsed = true; + break; + case XML_shadow: + maModel.mbShadow = bFlag; + maUsedFlags.mbShadowUsed = true; + break; + default: + OSL_FAIL( "Font::importDxfFlag - unexpected element identifier" ); + } +} + +void Font::finalizeImport() +{ + // font name + maApiData.maDesc.Name = maModel.maName; + + // font family + switch( maModel.mnFamily ) + { + case OOX_FONTFAMILY_NONE: maApiData.maDesc.Family = css::awt::FontFamily::DONTKNOW; break; + case OOX_FONTFAMILY_ROMAN: maApiData.maDesc.Family = css::awt::FontFamily::ROMAN; break; + case OOX_FONTFAMILY_SWISS: maApiData.maDesc.Family = css::awt::FontFamily::SWISS; break; + case OOX_FONTFAMILY_MODERN: maApiData.maDesc.Family = css::awt::FontFamily::MODERN; break; + case OOX_FONTFAMILY_SCRIPT: maApiData.maDesc.Family = css::awt::FontFamily::SCRIPT; break; + case OOX_FONTFAMILY_DECORATIVE: maApiData.maDesc.Family = css::awt::FontFamily::DECORATIVE; break; + } + + // character set (API font descriptor uses rtl_TextEncoding in member CharSet!) + if( (0 <= maModel.mnCharSet) && (maModel.mnCharSet <= SAL_MAX_UINT8) ) + maApiData.maDesc.CharSet = static_cast< sal_Int16 >( + rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maModel.mnCharSet ) ) ); + + // color, height, weight, slant, strikeout, outline, shadow + maApiData.mnColor = maModel.maColor.getColor( getBaseFilter().getGraphicHelper() ); + maApiData.maDesc.Height = static_cast< sal_Int16 >( maModel.mfHeight * 20.0 ); + maApiData.maDesc.Weight = maModel.mbBold ? css::awt::FontWeight::BOLD : css::awt::FontWeight::NORMAL; + maApiData.maDesc.Slant = maModel.mbItalic ? css::awt::FontSlant_ITALIC : css::awt::FontSlant_NONE; + maApiData.maDesc.Strikeout = maModel.mbStrikeout ? css::awt::FontStrikeout::SINGLE : css::awt::FontStrikeout::NONE; + maApiData.mbOutline = maModel.mbOutline; + maApiData.mbShadow = maModel.mbShadow; + + // underline + switch( maModel.mnUnderline ) + { + case XML_double: maApiData.maDesc.Underline = css::awt::FontUnderline::DOUBLE; break; + case XML_doubleAccounting: maApiData.maDesc.Underline = css::awt::FontUnderline::DOUBLE; break; + case XML_none: maApiData.maDesc.Underline = css::awt::FontUnderline::NONE; break; + case XML_single: maApiData.maDesc.Underline = css::awt::FontUnderline::SINGLE; break; + case XML_singleAccounting: maApiData.maDesc.Underline = css::awt::FontUnderline::SINGLE; break; + } + + // escapement + switch( maModel.mnEscapement ) + { + case XML_baseline: + maApiData.mnEscapement = API_ESCAPE_NONE; + maApiData.mnEscapeHeight = API_ESCAPEHEIGHT_NONE; + break; + case XML_superscript: + maApiData.mnEscapement = API_ESCAPE_SUPERSCRIPT; + maApiData.mnEscapeHeight = API_ESCAPEHEIGHT_DEFAULT; + break; + case XML_subscript: + maApiData.mnEscapement = API_ESCAPE_SUBSCRIPT; + maApiData.mnEscapeHeight = API_ESCAPEHEIGHT_DEFAULT; + break; + } + + // supported script types + if( !maUsedFlags.mbNameUsed ) + return; + + PropertySet aDocProps( getDocument() ); + Reference< XDevice > xDevice( aDocProps.getAnyProperty( PROP_ReferenceDevice ), UNO_QUERY ); + if( !xDevice.is() ) + return; + + Reference< XFont2 > xFont( xDevice->getFont( maApiData.maDesc ), UNO_QUERY ); + if( !xFont.is() ) + return; + + // #91658# CJK fonts + bool bHasAsian = + xFont->hasGlyphs( OUString( u'\x3041' ) ) || // 3040-309F: Hiragana + xFont->hasGlyphs( OUString( u'\x30A1' ) ) || // 30A0-30FF: Katakana + xFont->hasGlyphs( OUString( u'\x3111' ) ) || // 3100-312F: Bopomofo + xFont->hasGlyphs( OUString( u'\x3131' ) ) || // 3130-318F: Hangul Compatibility Jamo + xFont->hasGlyphs( OUString( u'\x3301' ) ) || // 3300-33FF: CJK Compatibility + xFont->hasGlyphs( OUString( u'\x3401' ) ) || // 3400-4DBF: CJK Unified Ideographs Extension A + xFont->hasGlyphs( OUString( u'\x4E01' ) ) || // 4E00-9FFF: CJK Unified Ideographs + xFont->hasGlyphs( OUString( u'\x7E01' ) ) || // 4E00-9FFF: CJK Unified Ideographs + xFont->hasGlyphs( OUString( u'\xA001' ) ) || // A001-A48F: Yi Syllables + xFont->hasGlyphs( OUString( u'\xAC01' ) ) || // AC00-D7AF: Hangul Syllables + xFont->hasGlyphs( OUString( u'\xCC01' ) ) || // AC00-D7AF: Hangul Syllables + xFont->hasGlyphs( OUString( u'\xF901' ) ) || // F900-FAFF: CJK Compatibility Ideographs + xFont->hasGlyphs( OUString( u'\xFF71' ) ); // FF00-FFEF: Halfwidth/Fullwidth Forms + // #113783# CTL fonts + bool bHasCmplx = + xFont->hasGlyphs( OUString( u'\x05D1' ) ) || // 0590-05FF: Hebrew + xFont->hasGlyphs( OUString( u'\x0631' ) ) || // 0600-06FF: Arabic + xFont->hasGlyphs( OUString( u'\x0721' ) ) || // 0700-074F: Syriac + xFont->hasGlyphs( OUString( u'\x0911' ) ) || // 0900-0DFF: Indic scripts + xFont->hasGlyphs( OUString( u'\x0E01' ) ) || // 0E00-0E7F: Thai + xFont->hasGlyphs( OUString( u'\xFB21' ) ) || // FB1D-FB4F: Hebrew Presentation Forms + xFont->hasGlyphs( OUString( u'\xFB51' ) ) || // FB50-FDFF: Arabic Presentation Forms-A + xFont->hasGlyphs( OUString( u'\xFE71' ) ); // FE70-FEFF: Arabic Presentation Forms-B + // Western fonts + bool bHasLatin = + (!bHasAsian && !bHasCmplx) || + xFont->hasGlyphs( OUString( 'A' ) ); + + lclSetFontName( maApiData.maLatinFont, maApiData.maDesc, bHasLatin ); + lclSetFontName( maApiData.maAsianFont, maApiData.maDesc, bHasAsian ); + lclSetFontName( maApiData.maCmplxFont, maApiData.maDesc, bHasCmplx ); +} + +bool Font::needsRichTextFormat() const +{ + return maApiData.mnEscapement != API_ESCAPE_NONE; +} + +static ::FontFamily lcl_getFontFamily( sal_Int32 nFamily ) +{ + ::FontFamily eScFamily = FAMILY_DONTKNOW; + switch( nFamily ) + { + case css::awt::FontFamily::DONTKNOW: + eScFamily = FAMILY_DONTKNOW; + break; + case css::awt::FontFamily::ROMAN: + eScFamily = FAMILY_ROMAN; + break; + case css::awt::FontFamily::SWISS: + eScFamily = FAMILY_SWISS; + break; + case css::awt::FontFamily::MODERN: + eScFamily = FAMILY_MODERN; + break; + case css::awt::FontFamily::SCRIPT: + eScFamily = FAMILY_SCRIPT; + break; + case css::awt::FontFamily::DECORATIVE: + eScFamily = FAMILY_DECORATIVE; + break; + } + return eScFamily; +} + +void Font::fillToItemSet( SfxItemSet& rItemSet, bool bEditEngineText, bool bSkipPoolDefs ) const +{ + if ( maUsedFlags.mbNameUsed ) + { + if( !maApiData.maLatinFont.maName.isEmpty() ) + { + rtl_TextEncoding eFontEnc = maApiData.maLatinFont.mnTextEnc; + // taken from binary importer + rtl_TextEncoding eTempTextEnc = (bEditEngineText && (eFontEnc == getTextEncoding())) ? + ScfTools::GetSystemTextEncoding() : eFontEnc; + + SvxFontItem aFontItem( lcl_getFontFamily( maApiData.maLatinFont.mnFamily ), maApiData.maLatinFont.maName, OUString(), + PITCH_DONTKNOW, eTempTextEnc, ATTR_FONT ); + ScfTools::PutItem( rItemSet, aFontItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_FONTINFO) : ATTR_FONT, bSkipPoolDefs ); + } + if( !maApiData.maAsianFont.maName.isEmpty() ) + { + rtl_TextEncoding eFontEnc = maApiData.maAsianFont.mnTextEnc; + // taken from binary importer + rtl_TextEncoding eTempTextEnc = (bEditEngineText && (eFontEnc == getTextEncoding())) ? + ScfTools::GetSystemTextEncoding() : eFontEnc; + SvxFontItem aFontItem( lcl_getFontFamily( maApiData.maAsianFont.mnFamily ), maApiData.maAsianFont.maName, OUString(), + PITCH_DONTKNOW, eTempTextEnc, ATTR_FONT ); + ScfTools::PutItem( rItemSet, aFontItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_FONTINFO_CJK) : ATTR_CJK_FONT, bSkipPoolDefs ); + } + if( !maApiData.maCmplxFont.maName.isEmpty() ) + { + rtl_TextEncoding eFontEnc = maApiData.maCmplxFont.mnTextEnc; + // taken from binary importer + rtl_TextEncoding eTempTextEnc = (bEditEngineText && (eFontEnc == getTextEncoding())) ? + ScfTools::GetSystemTextEncoding() : eFontEnc; + SvxFontItem aFontItem( lcl_getFontFamily( maApiData.maCmplxFont.mnFamily ), maApiData.maCmplxFont.maName, OUString(), + PITCH_DONTKNOW, eTempTextEnc, ATTR_FONT ); + ScfTools::PutItem( rItemSet, aFontItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_FONTINFO_CTL) : ATTR_CTL_FONT, bSkipPoolDefs ); + } + } + // font height + if( maUsedFlags.mbHeightUsed ) + { + sal_Int32 nHeight = maApiData.maDesc.Height; + // do we use XclFontItemType::HeaderFooter ( or is it just relevant for the binary filter ) + if( bEditEngineText/* && (eType != XclFontItemType::HeaderFooter) */) // do not convert header/footer height + nHeight = convertTwipToMm100(nHeight); + SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT ); + ScfTools::PutItem( rItemSet, aHeightItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_FONTHEIGHT) : ATTR_FONT_HEIGHT, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aHeightItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_FONTHEIGHT_CJK) : ATTR_CJK_FONT_HEIGHT, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aHeightItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_FONTHEIGHT_CTL) : ATTR_CTL_FONT_HEIGHT, bSkipPoolDefs ); + } + // font weight + if( maUsedFlags.mbWeightUsed ) + { + ::FontWeight fWeight = vcl::unohelper::ConvertFontWeight( maApiData.maDesc.Weight ); + SvxWeightItem aWeightItem( fWeight, ATTR_FONT_WEIGHT ); + ScfTools::PutItem( rItemSet, aWeightItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_WEIGHT) : ATTR_FONT_WEIGHT, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aWeightItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_WEIGHT_CTL) : ATTR_CTL_FONT_WEIGHT, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aWeightItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_WEIGHT_CJK) : ATTR_CJK_FONT_WEIGHT, bSkipPoolDefs ); + } + // font posture + if( maUsedFlags.mbPostureUsed ) + { + SvxPostureItem aPostItem( ( maApiData.maDesc.Slant == css::awt::FontSlant_ITALIC ) ? ITALIC_NORMAL : ITALIC_NONE, ATTR_FONT_POSTURE); + ScfTools::PutItem( rItemSet, aPostItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_ITALIC) : ATTR_FONT_POSTURE, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aPostItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_ITALIC_CJK) : ATTR_CJK_FONT_POSTURE, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aPostItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_ITALIC_CTL) : ATTR_CTL_FONT_POSTURE, bSkipPoolDefs ); + } + // character color + if( maUsedFlags.mbColorUsed ) + { + ScfTools::PutItem( rItemSet,SvxColorItem( maApiData.mnColor, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_COLOR) : ATTR_FONT_COLOR), bSkipPoolDefs ); + } + // underline style + if( maUsedFlags.mbUnderlineUsed ) + { + FontLineStyle eScUnderl; + if ( maApiData.maDesc.Underline == css::awt::FontUnderline::DOUBLE ) + eScUnderl = LINESTYLE_DOUBLE; + else if ( maApiData.maDesc.Underline == css::awt::FontUnderline::SINGLE ) + eScUnderl = LINESTYLE_SINGLE; + else + eScUnderl = LINESTYLE_NONE; + SvxUnderlineItem aUnderlItem( eScUnderl, ATTR_FONT_UNDERLINE ); + ScfTools::PutItem( rItemSet, aUnderlItem, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_UNDERLINE) : ATTR_FONT_UNDERLINE, bSkipPoolDefs ); + } + // strike out style + if( maUsedFlags.mbStrikeoutUsed ) + { + ScfTools::PutItem( rItemSet, SvxCrossedOutItem( maModel.mbStrikeout ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_STRIKEOUT) : ATTR_FONT_CROSSEDOUT ), bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_STRIKEOUT) : ATTR_FONT_CROSSEDOUT, bSkipPoolDefs ); + } + + // outline style + if( maUsedFlags.mbOutlineUsed ) + { + ScfTools::PutItem( rItemSet, SvxContourItem( maApiData.mbOutline, ATTR_FONT_CONTOUR ), bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_OUTLINE) : ATTR_FONT_CONTOUR, bSkipPoolDefs ); + } + + // shadow style + if( maUsedFlags.mbShadowUsed ) + { + ScfTools::PutItem( rItemSet, SvxShadowedItem( maApiData.mbShadow, ATTR_FONT_SHADOWED ), bEditEngineText ? static_cast<sal_uInt16>(EE_CHAR_SHADOW) : ATTR_FONT_SHADOWED, bSkipPoolDefs ); + } + if( !maUsedFlags.mbEscapementUsed ) + return; + + SvxEscapement eScEscapem = SvxEscapement::Off; + if ( maApiData.mnEscapement == API_ESCAPE_SUPERSCRIPT ) + eScEscapem = SvxEscapement::Superscript; + else if ( maApiData.mnEscapement == API_ESCAPE_SUBSCRIPT ) + eScEscapem = SvxEscapement::Subscript; + if( bEditEngineText ) + { + // #TODO handle EscapementHeight + rItemSet.Put( SvxEscapementItem( eScEscapem, EE_CHAR_ESCAPEMENT ) ); + } +} + +void Font::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + // font name properties + if( maUsedFlags.mbNameUsed ) + { + if( !maApiData.maLatinFont.maName.isEmpty() ) + { + rPropMap.setProperty( PROP_CharFontName, maApiData.maLatinFont.maName); + rPropMap.setProperty( PROP_CharFontFamily, maApiData.maLatinFont.mnFamily); + rPropMap.setProperty( PROP_CharFontCharSet, maApiData.maLatinFont.mnTextEnc); + } + if( !maApiData.maAsianFont.maName.isEmpty() ) + { + rPropMap.setProperty( PROP_CharFontNameAsian, maApiData.maAsianFont.maName); + rPropMap.setProperty( PROP_CharFontFamilyAsian, maApiData.maAsianFont.mnFamily); + rPropMap.setProperty( PROP_CharFontCharSetAsian, maApiData.maAsianFont.mnTextEnc); + } + if( !maApiData.maCmplxFont.maName.isEmpty() ) + { + rPropMap.setProperty( PROP_CharFontNameComplex, maApiData.maCmplxFont.maName); + rPropMap.setProperty( PROP_CharFontFamilyComplex, maApiData.maCmplxFont.mnFamily); + rPropMap.setProperty( PROP_CharFontCharSetComplex, maApiData.maCmplxFont.mnTextEnc); + } + } + // font height + if( maUsedFlags.mbHeightUsed ) + { + float fHeight = static_cast< float >( maApiData.maDesc.Height / 20.0 ); // twips to points + rPropMap.setProperty( PROP_CharHeight, fHeight); + rPropMap.setProperty( PROP_CharHeightAsian, fHeight); + rPropMap.setProperty( PROP_CharHeightComplex, fHeight); + } + // font weight + if( maUsedFlags.mbWeightUsed ) + { + float fWeight = maApiData.maDesc.Weight; + rPropMap.setProperty( PROP_CharWeight, fWeight); + rPropMap.setProperty( PROP_CharWeightAsian, fWeight); + rPropMap.setProperty( PROP_CharWeightComplex, fWeight); + } + // font posture + if( maUsedFlags.mbPostureUsed ) + { + rPropMap.setProperty( PROP_CharPosture, maApiData.maDesc.Slant); + rPropMap.setProperty( PROP_CharPostureAsian, maApiData.maDesc.Slant); + rPropMap.setProperty( PROP_CharPostureComplex, maApiData.maDesc.Slant); + } + // character color + if( maUsedFlags.mbColorUsed ) + rPropMap.setProperty( PROP_CharColor, maApiData.mnColor); + // underline style + if( maUsedFlags.mbUnderlineUsed ) + rPropMap.setProperty( PROP_CharUnderline, maApiData.maDesc.Underline); + // strike out style + if( maUsedFlags.mbStrikeoutUsed ) + rPropMap.setProperty( PROP_CharStrikeout, maApiData.maDesc.Strikeout); + // outline style + if( maUsedFlags.mbOutlineUsed ) + rPropMap.setProperty( PROP_CharContoured, maApiData.mbOutline); + // shadow style + if( maUsedFlags.mbShadowUsed ) + rPropMap.setProperty( PROP_CharShadowed, maApiData.mbShadow); + // escapement + if( maUsedFlags.mbEscapementUsed ) + { + rPropMap.setProperty( PROP_CharEscapement, maApiData.mnEscapement); + rPropMap.setProperty( PROP_CharEscapementHeight, maApiData.mnEscapeHeight); + } +} + +void Font::writeToPropertySet( PropertySet& rPropSet ) const +{ + PropertyMap aPropMap; + writeToPropertyMap( aPropMap ); + rPropSet.setProperties( aPropMap ); +} + +AlignmentModel::AlignmentModel() : + mnHorAlign( XML_general ), + mnVerAlign( XML_bottom ), + mnTextDir( OOX_XF_TEXTDIR_CONTEXT ), + mnRotation( OOX_XF_ROTATION_NONE ), + mnIndent( OOX_XF_INDENT_NONE ), + mbWrapText( false ), + mbShrink( false ), + mbJustLastLine( false ) +{ +} + +void AlignmentModel::setBiffHorAlign( sal_uInt8 nHorAlign ) +{ + static const sal_Int32 spnHorAligns[] = { + XML_general, XML_left, XML_center, XML_right, + XML_fill, XML_justify, XML_centerContinuous, XML_distributed }; + mnHorAlign = STATIC_ARRAY_SELECT( spnHorAligns, nHorAlign, XML_general ); +} + +void AlignmentModel::setBiffVerAlign( sal_uInt8 nVerAlign ) +{ + static const sal_Int32 spnVerAligns[] = { + XML_top, XML_center, XML_bottom, XML_justify, XML_distributed }; + mnVerAlign = STATIC_ARRAY_SELECT( spnVerAligns, nVerAlign, XML_bottom ); +} + +ApiAlignmentData::ApiAlignmentData() : + meHorJustify( css::table::CellHoriJustify_STANDARD ), + mnHorJustifyMethod( css::table::CellJustifyMethod::AUTO ), + mnVerJustify( css::table::CellVertJustify2::STANDARD ), + mnVerJustifyMethod( css::table::CellJustifyMethod::AUTO ), + meOrientation( css::table::CellOrientation_STANDARD ), + mnRotation( 0 ), + mnWritingMode( css::text::WritingMode2::PAGE ), + mnIndent( 0 ), + mbWrapText( false ), + mbShrink( false ) +{ +} + +bool operator==( const ApiAlignmentData& rLeft, const ApiAlignmentData& rRight ) +{ + return + (rLeft.meHorJustify == rRight.meHorJustify) && + (rLeft.mnHorJustifyMethod == rRight.mnHorJustifyMethod) && + (rLeft.mnVerJustify == rRight.mnVerJustify) && + (rLeft.mnVerJustifyMethod == rRight.mnVerJustifyMethod) && + (rLeft.meOrientation == rRight.meOrientation) && + (rLeft.mnRotation == rRight.mnRotation) && + (rLeft.mnWritingMode == rRight.mnWritingMode) && + (rLeft.mnIndent == rRight.mnIndent) && + (rLeft.mbWrapText == rRight.mbWrapText) && + (rLeft.mbShrink == rRight.mbShrink); +} + +Alignment::Alignment( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ) +{ +} + +void Alignment::importAlignment( const AttributeList& rAttribs ) +{ + maModel.mnVerAlign = rAttribs.getToken( XML_vertical, XML_bottom ); + maModel.mnTextDir = rAttribs.getInteger( XML_readingOrder, OOX_XF_TEXTDIR_CONTEXT ); + maModel.mnRotation = rAttribs.getInteger( XML_textRotation, OOX_XF_ROTATION_NONE ); + sal_Int32 nDefaultHorAlign = XML_general; + if (maModel.mnRotation != OOX_XF_ROTATION_NONE) + { + if (maModel.mnRotation < 90 || maModel.mnRotation == 180) + { + nDefaultHorAlign = XML_left; + } + else + { + nDefaultHorAlign = XML_right; + } + } + maModel.mnHorAlign = rAttribs.getToken( XML_horizontal, nDefaultHorAlign ); + maModel.mnIndent = rAttribs.getInteger( XML_indent, OOX_XF_INDENT_NONE ); + maModel.mbWrapText = rAttribs.getBool( XML_wrapText, false ); + maModel.mbShrink = rAttribs.getBool( XML_shrinkToFit, false ); + maModel.mbJustLastLine = rAttribs.getBool( XML_justifyLastLine, false ); +} + +void Alignment::setBiff12Data( sal_uInt32 nFlags ) +{ + maModel.setBiffHorAlign( extractValue< sal_uInt8 >( nFlags, 16, 3 ) ); + maModel.setBiffVerAlign( extractValue< sal_uInt8 >( nFlags, 19, 3 ) ); + maModel.mnTextDir = extractValue< sal_Int32 >( nFlags, 26, 2 ); + maModel.mnRotation = extractValue< sal_Int32 >( nFlags, 0, 8 ); + maModel.mnIndent = extractValue< sal_uInt8 >( nFlags, 8, 8 ); + maModel.mbWrapText = getFlag( nFlags, BIFF12_XF_WRAPTEXT ); + maModel.mbShrink = getFlag( nFlags, BIFF12_XF_SHRINK ); + maModel.mbJustLastLine = getFlag( nFlags, BIFF12_XF_JUSTLASTLINE ); +} + +void Alignment::finalizeImport() +{ + // horizontal alignment + switch( maModel.mnHorAlign ) + { + case XML_center: maApiData.meHorJustify = css::table::CellHoriJustify_CENTER; break; + case XML_centerContinuous: maApiData.meHorJustify = css::table::CellHoriJustify_CENTER; break; + case XML_distributed: maApiData.meHorJustify = css::table::CellHoriJustify_BLOCK; break; + case XML_fill: maApiData.meHorJustify = css::table::CellHoriJustify_REPEAT; break; + case XML_general: maApiData.meHorJustify = css::table::CellHoriJustify_STANDARD; break; + case XML_justify: maApiData.meHorJustify = css::table::CellHoriJustify_BLOCK; break; + case XML_left: maApiData.meHorJustify = css::table::CellHoriJustify_LEFT; break; + case XML_right: maApiData.meHorJustify = css::table::CellHoriJustify_RIGHT; break; + } + + if (maModel.mnHorAlign == XML_distributed) + maApiData.mnHorJustifyMethod = css::table::CellJustifyMethod::DISTRIBUTE; + + // vertical alignment + switch( maModel.mnVerAlign ) + { + case XML_bottom: maApiData.mnVerJustify = css::table::CellVertJustify2::BOTTOM; break; + case XML_center: maApiData.mnVerJustify = css::table::CellVertJustify2::CENTER; break; + case XML_distributed: maApiData.mnVerJustify = css::table::CellVertJustify2::BLOCK; break; + case XML_justify: maApiData.mnVerJustify = css::table::CellVertJustify2::BLOCK; break; + case XML_top: maApiData.mnVerJustify = css::table::CellVertJustify2::TOP; break; + } + + if (maModel.mnVerAlign == XML_distributed) + maApiData.mnVerJustifyMethod = css::table::CellJustifyMethod::DISTRIBUTE; + + /* indentation: expressed as number of blocks of 3 space characters in + OOXML. */ + UnitConverter& rUnitConverter = getUnitConverter(); + // Note: indents are stored in twips + sal_Int32 nIndent = rUnitConverter.scaleValue( 3.0 * maModel.mnIndent, Unit::Space, Unit::Twip); + if( (0 <= nIndent) && (nIndent <= SAL_MAX_INT16) ) + maApiData.mnIndent = static_cast< sal_Int16 >( nIndent ); + + // complex text direction + switch( maModel.mnTextDir ) + { + case OOX_XF_TEXTDIR_CONTEXT: maApiData.mnWritingMode = css::text::WritingMode2::PAGE; break; + case OOX_XF_TEXTDIR_LTR: maApiData.mnWritingMode = css::text::WritingMode2::LR_TB; break; + case OOX_XF_TEXTDIR_RTL: maApiData.mnWritingMode = css::text::WritingMode2::RL_TB; break; + } + + // rotation: 0-90 means 0 to 90 degrees ccw, 91-180 means 1 to 90 degrees cw, 255 means stacked + sal_Int32 nOoxRot = maModel.mnRotation; + maApiData.mnRotation = Degree100(((0 <= nOoxRot) && (nOoxRot <= 90)) ? + (100 * nOoxRot) : + (((91 <= nOoxRot) && (nOoxRot <= 180)) ? (100 * (450 - nOoxRot)) : 0)); + + // "Orientation" property used for character stacking + maApiData.meOrientation = (nOoxRot == OOX_XF_ROTATION_STACKED) ? + css::table::CellOrientation_STACKED : css::table::CellOrientation_STANDARD; + + // alignment flags (#i84960 automatic line break, if vertically justified/distributed) + maApiData.mbWrapText = maModel.mbWrapText || (maModel.mnVerAlign == XML_distributed) || (maModel.mnVerAlign == XML_justify); + maApiData.mbShrink = maModel.mbShrink; + +} + +::SvxCellVerJustify Alignment::GetScVerAlign() const +{ + ::SvxCellVerJustify nVert = ::SvxCellVerJustify::Standard; + switch ( maApiData.mnVerJustify ) + { + case css::table::CellVertJustify2::BOTTOM: + nVert = ::SvxCellVerJustify::Bottom; + break; + case css::table::CellVertJustify2::CENTER: + nVert = ::SvxCellVerJustify::Center; + break; + case css::table::CellVertJustify2::TOP: + nVert = ::SvxCellVerJustify::Top; + break; + case css::table::CellVertJustify2::BLOCK: + nVert = ::SvxCellVerJustify::Block; + break; + case css::table::CellVertJustify2::STANDARD: + default: + nVert = ::SvxCellVerJustify::Standard; + break; + } + return nVert; +} + +::SvxCellHorJustify Alignment::GetScHorAlign() const +{ + ::SvxCellHorJustify nHori = ::SvxCellHorJustify::Standard; + switch( maApiData.meHorJustify ) + { + case css::table::CellHoriJustify_LEFT: + nHori = ::SvxCellHorJustify::Left; + break; + case css::table::CellHoriJustify_CENTER: + nHori = ::SvxCellHorJustify::Center; + break; + case css::table::CellHoriJustify_RIGHT: + nHori = ::SvxCellHorJustify::Right; + break; + case css::table::CellHoriJustify_BLOCK: + nHori = ::SvxCellHorJustify::Block; + break; + case css::table::CellHoriJustify_REPEAT: + nHori = ::SvxCellHorJustify::Repeat; + break; + case css::table::CellHoriJustify_STANDARD: + default: + nHori = ::SvxCellHorJustify::Standard; + break; + } + return nHori; +} + +SvxFrameDirection Alignment::GetScFrameDir() const +{ + SvxFrameDirection eFrameDir = SvxFrameDirection::Environment; + switch( maApiData.mnWritingMode ) + { + case css::text::WritingMode2::PAGE: + eFrameDir = SvxFrameDirection::Environment; + break; + case css::text::WritingMode2::LR_TB: + eFrameDir = SvxFrameDirection::Horizontal_LR_TB; + break; + case css::text::WritingMode2::RL_TB: + eFrameDir = SvxFrameDirection::Horizontal_RL_TB; + break; + default: + OSL_FAIL( "GetScFrameDir - unknown CTL text direction" ); + } + return eFrameDir; +} + +void Alignment::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const +{ + // horizontal alignment + ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( ( maApiData.mnHorJustifyMethod == css::table::CellJustifyMethod::DISTRIBUTE ) ? ::SvxCellJustifyMethod::Distribute : ::SvxCellJustifyMethod::Auto, ATTR_HOR_JUSTIFY_METHOD ), bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs ); + // vertical alignment + ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( ( maApiData.mnVerJustifyMethod == css::table::CellJustifyMethod::DISTRIBUTE ) ? ::SvxCellJustifyMethod::Distribute : ::SvxCellJustifyMethod::Auto, ATTR_VER_JUSTIFY_METHOD ), bSkipPoolDefs ); + + // CTL text direction + ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs ); + // set an angle in the range from -90 to 90 degrees + ScfTools::PutItem( rItemSet, ScRotateValueItem( maApiData.mnRotation ), bSkipPoolDefs ); + // Orientation + ScfTools::PutItem( rItemSet, ScVerticalStackCell( maApiData.meOrientation == css::table::CellOrientation_STACKED ), bSkipPoolDefs ); + // indent + ScfTools::PutItem( rItemSet, ScIndentItem( maApiData.mnIndent ), bSkipPoolDefs ); + // line wrap + ScfTools::PutItem( rItemSet, ScLineBreakCell( maApiData.mbWrapText ), bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, ScShrinkToFitCell( maApiData.mbShrink ), bSkipPoolDefs ); +} + +ProtectionModel::ProtectionModel() : + mbLocked( true ), // default in Excel and Calc + mbHidden( false ) +{ +} + +ApiProtectionData::ApiProtectionData() : + maCellProt( true, false, false, false ) +{ +} + +bool operator==( const ApiProtectionData& rLeft, const ApiProtectionData& rRight ) +{ + return + (rLeft.maCellProt.IsLocked == rRight.maCellProt.IsLocked) && + (rLeft.maCellProt.IsFormulaHidden == rRight.maCellProt.IsFormulaHidden) && + (rLeft.maCellProt.IsHidden == rRight.maCellProt.IsHidden) && + (rLeft.maCellProt.IsPrintHidden == rRight.maCellProt.IsPrintHidden); +} + +Protection::Protection( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ) +{ +} + +void Protection::importProtection( const AttributeList& rAttribs ) +{ + maModel.mbLocked = rAttribs.getBool( XML_locked, true ); + maModel.mbHidden = rAttribs.getBool( XML_hidden, false ); +} + +void Protection::setBiff12Data( sal_uInt32 nFlags ) +{ + maModel.mbLocked = getFlag( nFlags, BIFF12_XF_LOCKED ); + maModel.mbHidden = getFlag( nFlags, BIFF12_XF_HIDDEN ); +} + +void Protection::finalizeImport() +{ + maApiData.maCellProt.IsLocked = maModel.mbLocked; + maApiData.maCellProt.IsFormulaHidden = maModel.mbHidden; +} + +void Protection::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const +{ + ScfTools::PutItem( rItemSet, ScProtectionAttr( maApiData.maCellProt.IsLocked, maApiData.maCellProt.IsFormulaHidden ), bSkipPoolDefs ); +} + +namespace { + +bool lcl_isBorder(const css::table::BorderLine& rBorder) +{ + return (rBorder.InnerLineWidth > 0) || (rBorder.OuterLineWidth > 0); +} + +} + +BorderLineModel::BorderLineModel( bool bDxf ) : + mnStyle( XML_none ), + mbUsed( !bDxf ) +{ + maColor.setIndexed( OOX_COLOR_WINDOWTEXT ); +} + +void BorderLineModel::setBiffStyle( sal_Int32 nLineStyle ) +{ + static const sal_Int32 spnStyleIds[] = { + XML_none, XML_thin, XML_medium, XML_dashed, + XML_dotted, XML_thick, XML_double, XML_hair, + XML_mediumDashed, XML_dashDot, XML_mediumDashDot, XML_dashDotDot, + XML_mediumDashDotDot, XML_slantDashDot }; + mnStyle = STATIC_ARRAY_SELECT( spnStyleIds, nLineStyle, XML_none ); +} + +BorderModel::BorderModel( bool bDxf ) : + maLeft( bDxf ), + maRight( bDxf ), + maTop( bDxf ), + maBottom( bDxf ), + maDiagonal( bDxf ), + mbDiagTLtoBR( false ), + mbDiagBLtoTR( false ) +{ +} + +ApiBorderData::ApiBorderData() : + mbBorderUsed( false ), + mbDiagUsed( false ) +{ +} + +bool ApiBorderData::hasAnyOuterBorder() const +{ + return + ( lcl_isBorder( maTop ) && maTop.OuterLineWidth > 0 ) || + ( lcl_isBorder( maBottom ) && maBottom.OuterLineWidth > 0 ) || + ( lcl_isBorder( maLeft ) && maLeft.OuterLineWidth > 0 ) || + ( lcl_isBorder( maRight ) && maRight.OuterLineWidth > 0 ); +} + +namespace { + +void lclSetBorderLineWidth( BorderLine& rBorderLine, + sal_Int16 nOuter, sal_Int16 nDist = API_LINE_NONE, sal_Int16 nInner = API_LINE_NONE ) +{ + rBorderLine.OuterLineWidth = nOuter; + rBorderLine.LineDistance = nDist; + rBorderLine.InnerLineWidth = nInner; +} + +} // namespace + +Border::Border( const WorkbookHelper& rHelper, bool bDxf ) : + WorkbookHelper( rHelper ), + maModel( bDxf ), + mbDxf( bDxf ) +{ +} + +void Border::importBorder( const AttributeList& rAttribs ) +{ + maModel.mbDiagTLtoBR = rAttribs.getBool( XML_diagonalDown, false ); + maModel.mbDiagBLtoTR = rAttribs.getBool( XML_diagonalUp, false ); +} + +void Border::importStyle( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( BorderLineModel* pBorderLine = getBorderLine( nElement ) ) + { + pBorderLine->mnStyle = rAttribs.getToken( XML_style, XML_none ); + pBorderLine->mbUsed = true; + } +} + +void Border::importColor( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( BorderLineModel* pBorderLine = getBorderLine( nElement ) ) + pBorderLine->maColor.importColor( rAttribs ); +} + +void Border::importBorder( SequenceInputStream& rStrm ) +{ + sal_uInt8 nFlags = rStrm.readuInt8(); + maModel.mbDiagTLtoBR = getFlag( nFlags, BIFF12_BORDER_DIAG_TLBR ); + maModel.mbDiagBLtoTR = getFlag( nFlags, BIFF12_BORDER_DIAG_BLTR ); + maModel.maTop.setBiffStyle( rStrm.readuInt16() ); + rStrm >> maModel.maTop.maColor; + maModel.maBottom.setBiffStyle( rStrm.readuInt16() ); + rStrm >> maModel.maBottom.maColor; + maModel.maLeft.setBiffStyle( rStrm.readuInt16() ); + rStrm >> maModel.maLeft.maColor; + maModel.maRight.setBiffStyle( rStrm.readuInt16() ); + rStrm >> maModel.maRight.maColor; + maModel.maDiagonal.setBiffStyle( rStrm.readuInt16() ); + rStrm >> maModel.maDiagonal.maColor; +} + +void Border::importDxfBorder( sal_Int32 nElement, SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Border::importDxfBorder - missing conditional formatting flag" ); + if( BorderLineModel* pBorderLine = getBorderLine( nElement ) ) + { + sal_uInt16 nStyle; + rStrm >> pBorderLine->maColor; + nStyle = rStrm.readuInt16(); + pBorderLine->setBiffStyle( nStyle ); + pBorderLine->mbUsed = true; + } +} + +void Border::finalizeImport( bool bRTL ) +{ + if ( bRTL ) + { + BorderLineModel aTmp = maModel.maLeft; + maModel.maLeft = maModel.maRight; + maModel.maRight = aTmp; + } + maApiData.mbBorderUsed = maModel.maLeft.mbUsed || maModel.maRight.mbUsed || maModel.maTop.mbUsed || maModel.maBottom.mbUsed; + maApiData.mbDiagUsed = maModel.maDiagonal.mbUsed; + + convertBorderLine( maApiData.maLeft, maModel.maLeft ); + convertBorderLine( maApiData.maRight, maModel.maRight ); + convertBorderLine( maApiData.maTop, maModel.maTop ); + convertBorderLine( maApiData.maBottom, maModel.maBottom ); + + if( maModel.mbDiagTLtoBR ) + convertBorderLine( maApiData.maTLtoBR, maModel.maDiagonal ); + if( maModel.mbDiagBLtoTR ) + convertBorderLine( maApiData.maBLtoTR, maModel.maDiagonal ); +} + +void Border::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const +{ + if( maApiData.mbBorderUsed ) + { + SvxBoxItem aBoxItem( ATTR_BORDER ); + ::editeng::SvxBorderLine aLine; + + if (SvxBoxItem::LineToSvxLine(maApiData.maLeft, aLine, false)) + { + aBoxItem.SetLine( &aLine, SvxBoxItemLine::LEFT ); + } + if (SvxBoxItem::LineToSvxLine(maApiData.maRight, aLine, false)) + { + aBoxItem.SetLine( &aLine, SvxBoxItemLine::RIGHT ); + } + if (SvxBoxItem::LineToSvxLine(maApiData.maTop, aLine, false)) + { + aBoxItem.SetLine( &aLine, SvxBoxItemLine::TOP ); + } + if (SvxBoxItem::LineToSvxLine(maApiData.maBottom, aLine, false)) + { + aBoxItem.SetLine( &aLine, SvxBoxItemLine::BOTTOM ); + } + ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs ); + } + if ( !maApiData.mbDiagUsed ) + return; + + SvxLineItem aTLBRItem( ATTR_BORDER_TLBR ); + SvxLineItem aBLTRItem( ATTR_BORDER_BLTR ); + ::editeng::SvxBorderLine aLine; + if (SvxBoxItem::LineToSvxLine(maApiData.maTLtoBR, aLine, false)) + { + aTLBRItem.SetLine( &aLine ); + } + if (SvxBoxItem::LineToSvxLine(maApiData.maBLtoTR, aLine, false)) + { + aBLTRItem.SetLine( &aLine ); + } + ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs ); + ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs ); +} + +BorderLineModel* Border::getBorderLine( sal_Int32 nElement ) +{ + switch( nElement ) + { + case XLS_TOKEN( left ): return &maModel.maLeft; + case XLS_TOKEN( start ): return &maModel.maLeft; + case XLS_TOKEN( right ): return &maModel.maRight; + case XLS_TOKEN( end ): return &maModel.maRight; + case XLS_TOKEN( top ): return &maModel.maTop; + case XLS_TOKEN( bottom ): return &maModel.maBottom; + case XLS_TOKEN( diagonal ): return &maModel.maDiagonal; + } + return nullptr; +} + +bool Border::convertBorderLine( BorderLine2& rBorderLine, const BorderLineModel& rModel ) +{ + // Document: sc/qa/unit/data/README.cellborders + + rBorderLine.Color = sal_Int32(rModel.maColor.getColor( getBaseFilter().getGraphicHelper(), API_RGB_BLACK )); + switch( rModel.mnStyle ) + { + case XML_dashDot: + lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); + rBorderLine.LineStyle = BorderLineStyle::DASH_DOT; + break; + case XML_dashDotDot: + lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); + rBorderLine.LineStyle = BorderLineStyle::DASH_DOT_DOT; + break; + case XML_dashed: + lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); + rBorderLine.LineStyle = BorderLineStyle::FINE_DASHED; + break; + case XML_dotted: + lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); + rBorderLine.LineStyle = BorderLineStyle::DOTTED; + break; + case XML_double: + lclSetBorderLineWidth( rBorderLine, 10, 15, 10 ); + rBorderLine.LineStyle = BorderLineStyle::DOUBLE_THIN; + break; + case XML_hair: lclSetBorderLineWidth( rBorderLine, API_LINE_HAIR ); break; + case XML_medium: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; + case XML_mediumDashDot: + lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); + rBorderLine.LineStyle = BorderLineStyle::DASH_DOT; + break; + case XML_mediumDashDotDot: + lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); + rBorderLine.LineStyle = BorderLineStyle::DASH_DOT_DOT; + break; + case XML_mediumDashed: + lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); + rBorderLine.LineStyle = BorderLineStyle::DASHED; + break; + case XML_none: lclSetBorderLineWidth( rBorderLine, API_LINE_NONE ); break; + case XML_slantDashDot: + lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); + rBorderLine.LineStyle = BorderLineStyle::FINE_DASHED; + break; + case XML_thick: lclSetBorderLineWidth( rBorderLine, API_LINE_THICK ); break; + case XML_thin: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; + default: lclSetBorderLineWidth( rBorderLine, API_LINE_NONE ); break; + } + return rModel.mbUsed; +} + +PatternFillModel::PatternFillModel( bool bDxf ) : + mnPattern( XML_none ), + mbPattColorUsed( !bDxf ), + mbFillColorUsed( !bDxf ), + mbPatternUsed( !bDxf ) +{ + maPatternColor.setIndexed( OOX_COLOR_WINDOWTEXT ); + maFilterPatternColor.setIndexed( OOX_COLOR_WINDOWTEXT ); + maFillColor.setIndexed( OOX_COLOR_WINDOWBACK ); +} + +void PatternFillModel::setBiffPattern( sal_Int32 nPattern ) +{ + static const sal_Int32 spnPatternIds[] = { + XML_none, XML_solid, XML_mediumGray, XML_darkGray, + XML_lightGray, XML_darkHorizontal, XML_darkVertical, XML_darkDown, + XML_darkUp, XML_darkGrid, XML_darkTrellis, XML_lightHorizontal, + XML_lightVertical, XML_lightDown, XML_lightUp, XML_lightGrid, + XML_lightTrellis, XML_gray125, XML_gray0625 }; + mnPattern = STATIC_ARRAY_SELECT( spnPatternIds, nPattern, XML_none ); +} + +GradientFillModel::GradientFillModel() : + mnType( XML_linear ), + mfAngle( 0.0 ), + mfLeft( 0.0 ), + mfRight( 0.0 ), + mfTop( 0.0 ), + mfBottom( 0.0 ) +{ +} + +void GradientFillModel::readGradient( SequenceInputStream& rStrm ) +{ + sal_Int32 nType; + nType = rStrm.readInt32(); + mfAngle = rStrm.readDouble(); + mfLeft = rStrm.readDouble(); + mfRight = rStrm.readDouble(); + mfTop = rStrm.readDouble(); + mfBottom = rStrm.readDouble(); + static const sal_Int32 spnTypes[] = { XML_linear, XML_path }; + mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID ); +} + +void GradientFillModel::readGradientStop( SequenceInputStream& rStrm, bool bDxf ) +{ + Color aColor; + double fPosition; + if( bDxf ) + { + rStrm.skip( 2 ); + fPosition = rStrm.readDouble(); + rStrm >> aColor; + } + else + { + rStrm >> aColor; + fPosition = rStrm.readDouble(); + } + if( !rStrm.isEof() && (fPosition >= 0.0) ) + maColors[ fPosition ] = aColor; +} + +ApiSolidFillData::ApiSolidFillData() : + mnColor( API_RGB_TRANSPARENT ), + mnFilterColor( API_RGB_TRANSPARENT ), + mbTransparent( true ), + mbUsed( false ) +{ +} + +namespace { + +sal_Int32 lclGetMixedColorComp( sal_Int32 nPatt, sal_Int32 nFill, sal_Int32 nAlpha ) +{ + return ((nPatt - nFill) * nAlpha) / 0x80 + nFill; +} + +::Color lclGetMixedColor( ::Color nPattColor, ::Color nFillColor, sal_Int32 nAlpha ) +{ + return ::Color( + lclGetMixedColorComp( nPattColor.GetRed(), nFillColor.GetRed(), nAlpha ), + lclGetMixedColorComp( nPattColor.GetGreen(), nFillColor.GetGreen(), nAlpha ), + lclGetMixedColorComp( nPattColor.GetBlue(), nFillColor.GetBlue(), nAlpha ) ); +} + +} // namespace + +Fill::Fill( const WorkbookHelper& rHelper, bool bDxf ) : + WorkbookHelper( rHelper ), + mbDxf( bDxf ) +{ +} + +void Fill::importPatternFill( const AttributeList& rAttribs ) +{ + mxPatternModel = std::make_shared<PatternFillModel>( mbDxf ); + mxPatternModel->mnPattern = rAttribs.getToken( XML_patternType, XML_none ); + if( mbDxf ) + mxPatternModel->mbPatternUsed = rAttribs.hasAttribute( XML_patternType ); +} + +void Fill::importFgColor( const AttributeList& rAttribs ) +{ + OSL_ENSURE( mxPatternModel, "Fill::importFgColor - missing pattern data" ); + if( mxPatternModel ) + { + mxPatternModel->maPatternColor.importColor( rAttribs ); + mxPatternModel->mbPattColorUsed = true; + } +} + +void Fill::importBgColor( const AttributeList& rAttribs ) +{ + OSL_ENSURE( mxPatternModel, "Fill::importBgColor - missing pattern data" ); + if( mxPatternModel ) + { + mxPatternModel->maFillColor.importColor( rAttribs ); + mxPatternModel->mbFillColorUsed = true; + } +} + +void Fill::importGradientFill( const AttributeList& rAttribs ) +{ + mxGradientModel = std::make_shared<GradientFillModel>(); + mxGradientModel->mnType = rAttribs.getToken( XML_type, XML_linear ); + mxGradientModel->mfAngle = rAttribs.getDouble( XML_degree, 0.0 ); + mxGradientModel->mfLeft = rAttribs.getDouble( XML_left, 0.0 ); + mxGradientModel->mfRight = rAttribs.getDouble( XML_right, 0.0 ); + mxGradientModel->mfTop = rAttribs.getDouble( XML_top, 0.0 ); + mxGradientModel->mfBottom = rAttribs.getDouble( XML_bottom, 0.0 ); +} + +void Fill::importColor( const AttributeList& rAttribs, double fPosition ) +{ + OSL_ENSURE( mxGradientModel, "Fill::importColor - missing gradient data" ); + if( mxGradientModel && (fPosition >= 0.0) ) + mxGradientModel->maColors[ fPosition ].importColor( rAttribs ); +} + +void Fill::importFill( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( mbDxf, "sc", "Fill::importFill - unexpected conditional formatting flag" ); + sal_Int32 nPattern = rStrm.readInt32(); + if( nPattern == BIFF12_FILL_GRADIENT ) + { + mxGradientModel = std::make_shared<GradientFillModel>(); + sal_Int32 nStopCount; + rStrm.skip( 16 ); + mxGradientModel->readGradient( rStrm ); + nStopCount = rStrm.readInt32(); + for( sal_Int32 nStop = 0; (nStop < nStopCount) && !rStrm.isEof(); ++nStop ) + mxGradientModel->readGradientStop( rStrm, false ); + } + else + { + mxPatternModel = std::make_shared<PatternFillModel>( mbDxf ); + mxPatternModel->setBiffPattern( nPattern ); + rStrm >> mxPatternModel->maPatternColor >> mxPatternModel->maFillColor; + } +} + +void Fill::importDxfPattern( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Fill::importDxfPattern - missing conditional formatting flag" ); + if( !mxPatternModel ) + mxPatternModel = std::make_shared<PatternFillModel>( mbDxf ); + mxPatternModel->setBiffPattern( rStrm.readuInt8() ); + mxPatternModel->mbPatternUsed = true; +} + +void Fill::importDxfFgColor( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Fill::importDxfFgColor - missing conditional formatting flag" ); + if( !mxPatternModel ) + mxPatternModel = std::make_shared<PatternFillModel>( mbDxf ); + mxPatternModel->maPatternColor.importColor( rStrm ); + mxPatternModel->mbPattColorUsed = true; +} + +void Fill::importDxfBgColor( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Fill::importDxfBgColor - missing conditional formatting flag" ); + if( !mxPatternModel ) + mxPatternModel = std::make_shared<PatternFillModel>( mbDxf ); + mxPatternModel->maFillColor.importColor( rStrm ); + mxPatternModel->mbFillColorUsed = true; +} + +void Fill::importDxfGradient( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Fill::importDxfGradient - missing conditional formatting flag" ); + if( !mxGradientModel ) + mxGradientModel = std::make_shared<GradientFillModel>(); + mxGradientModel->readGradient( rStrm ); +} + +void Fill::importDxfStop( SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Fill::importDxfStop - missing conditional formatting flag" ); + if( !mxGradientModel ) + mxGradientModel = std::make_shared<GradientFillModel>(); + mxGradientModel->readGradientStop( rStrm, true ); +} + +void Fill::finalizeImport() +{ + const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper(); + + if( mxPatternModel ) + { + // finalize the OOXML data struct + PatternFillModel& rModel = *mxPatternModel; + if( mbDxf ) + { + if( rModel.mbFillColorUsed && (!rModel.mbPatternUsed || (rModel.mnPattern == XML_solid)) ) + { + rModel.maFilterPatternColor = rModel.maPatternColor; + rModel.maPatternColor = rModel.maFillColor; + rModel.mnPattern = XML_solid; + rModel.mbPattColorUsed = rModel.mbPatternUsed = true; + } + else if( + !rModel.mbFillColorUsed && !rModel.mbPattColorUsed && + rModel.mbPatternUsed && rModel.mnPattern == XML_solid ) + { + rModel.mbPatternUsed = false; + } + else + rModel.maFilterPatternColor = rModel.maPatternColor; + } + + // convert to API fill settings + maApiData.mbUsed = rModel.mbPatternUsed; + if( rModel.mnPattern == XML_none ) + { + maApiData.mnColor = API_RGB_TRANSPARENT; + maApiData.mbTransparent = true; + } + else + { + sal_Int32 nAlpha = 0x80; + switch( rModel.mnPattern ) + { + case XML_darkDown: nAlpha = 0x40; break; + case XML_darkGray: nAlpha = 0x60; break; + case XML_darkGrid: nAlpha = 0x40; break; + case XML_darkHorizontal: nAlpha = 0x40; break; + case XML_darkTrellis: nAlpha = 0x60; break; + case XML_darkUp: nAlpha = 0x40; break; + case XML_darkVertical: nAlpha = 0x40; break; + case XML_gray0625: nAlpha = 0x08; break; + case XML_gray125: nAlpha = 0x10; break; + case XML_lightDown: nAlpha = 0x20; break; + case XML_lightGray: nAlpha = 0x20; break; + case XML_lightGrid: nAlpha = 0x38; break; + case XML_lightHorizontal: nAlpha = 0x20; break; + case XML_lightTrellis: nAlpha = 0x30; break; + case XML_lightUp: nAlpha = 0x20; break; + case XML_lightVertical: nAlpha = 0x20; break; + case XML_mediumGray: nAlpha = 0x40; break; + case XML_solid: nAlpha = 0x80; break; + } + + ::Color nWinTextColor = rGraphicHelper.getSystemColor( XML_windowText ); + ::Color nWinColor = rGraphicHelper.getSystemColor( XML_window ); + + if (!rModel.mbPattColorUsed) + { + rModel.maPatternColor.setAuto(); + rModel.maFilterPatternColor.setAuto(); + } + ::Color nPattColor = rModel.maPatternColor.getColor( rGraphicHelper, nWinTextColor ); + ::Color nFiltPattColor = rModel.maFilterPatternColor.getColor( rGraphicHelper, nWinTextColor ); + + if( !rModel.mbFillColorUsed ) + rModel.maFillColor.setAuto(); + ::Color nFillColor = rModel.maFillColor.getColor( rGraphicHelper, nWinColor ); + + maApiData.mnColor = lclGetMixedColor( nPattColor, nFillColor, nAlpha ); + maApiData.mnFilterColor = lclGetMixedColor( nFiltPattColor, nFillColor, nAlpha ); + maApiData.mbTransparent = false; + } + } + else if( mxGradientModel && !mxGradientModel->maColors.empty() ) + { + GradientFillModel& rModel = *mxGradientModel; + maApiData.mbUsed = true; // no support for differential attributes + GradientFillModel::ColorMap::const_iterator aIt = rModel.maColors.begin(); + OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" ); + maApiData.mnColor = aIt->second.getColor( rGraphicHelper, API_RGB_WHITE ); + if( ++aIt != rModel.maColors.end() ) + { + OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" ); + ::Color nEndColor = aIt->second.getColor( rGraphicHelper, API_RGB_WHITE ); + maApiData.mnColor = lclGetMixedColor( maApiData.mnColor, nEndColor, 0x40 ); + maApiData.mbTransparent = false; + } + } +} + +void Fill::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const +{ + if( !maApiData.mbUsed ) + return; + + SvxBrushItem aBrushItem( ATTR_BACKGROUND ); + if ( maApiData.mbTransparent ) + { + aBrushItem.SetColor( COL_TRANSPARENT ); + aBrushItem.SetFiltColor( COL_TRANSPARENT ); + } + else + { + aBrushItem.SetColor( maApiData.mnColor ); + aBrushItem.SetFiltColor( maApiData.mnFilterColor ); + } + ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs ); +} + +XfModel::XfModel() : + mnStyleXfId( -1 ), + mnFontId( -1 ), + mnNumFmtId( -1 ), + mnBorderId( -1 ), + mnFillId( -1 ), + mbCellXf( true ), + mbFontUsed( false ), + mbNumFmtUsed( false ), + mbAlignUsed( false ), + mbProtUsed( false ), + mbBorderUsed( false ), + mbAreaUsed( false ) +{ +} + +Xf::AttrList::AttrList(const ScPatternAttr* pDefPattern): + mbLatinNumFmtOnly(true), + mpDefPattern(pDefPattern) +{} + +Xf::Xf( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + mnScNumFmt(0), + maAlignment( rHelper ), + maProtection( rHelper ), + meRotationRef( css::table::CellVertJustify2::STANDARD ), + mpStyleSheet( nullptr ) +{ +} + +void Xf::importXf( const AttributeList& rAttribs, bool bCellXf ) +{ + maModel.mbCellXf = bCellXf; + // tdf#70565 Set proper default value to "0" of xfId attribute + // When xfId is not exist during .xlsx import + // it must have values set to "0". + // This doesn't impact spreadsheets created with MS Excel, + // as xfId attribute is always created during export to .xlsx + // Not setting "0" value is causing wrong .xlsx import by LibreOffice, + // for spreadsheets created by external applications (ex. SAP BI). + bool bApplyDefault; + if ( maModel.mbCellXf ) + { + const sal_Int32 xfId = rAttribs.getInteger( XML_xfId, -1 ); + // No xfId => no cellStyleXfs that could overwrite this on change, thus + // has to be applied. + bApplyDefault = (xfId < 0); + maModel.mnStyleXfId = std::max<sal_Int32>(0, xfId); + } + else + { + maModel.mnStyleXfId = rAttribs.getInteger( XML_xfId, -1 ); + bApplyDefault = true; + } + maModel.mnFontId = rAttribs.getInteger( XML_fontId, -1 ); + maModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, -1 ); + maModel.mnBorderId = rAttribs.getInteger( XML_borderId, -1 ); + maModel.mnFillId = rAttribs.getInteger( XML_fillId, -1 ); + + // Default value of the apply*** attributes is dependent on context: + // true in cellStyleXfs element, false in cellXfs element... + // But it's not as easy as it sounds, for docs see + // https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/59922f8b-0edc-4e93-a822-9f22254aec46 + // and apparently in reality cellStyleXfs xf and cellXfs xf are not merged + // at all, see + // https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/bcf98682-e8d3-44b8-b8f8-0bf696878ba1 + // "b. The standard states that both the cell style xf records and cell xf + // records must be read to understand the full set of formatting applied to + // a cell." + // "In Office, only the cell xf record defines the formatting applied to a cell." + + // So for reading documents this is all crap and effectively xf records + // apply their explicit properties by default unless denied. + // bApplyDefault==false only for cellXf xf with xfId. + + // For cellXf xf, mbAlignUsed and mbProtUsed will be set when actually + // importing the element. + maModel.mbAlignUsed = rAttribs.getBool( XML_applyAlignment, bApplyDefault); + maModel.mbProtUsed = rAttribs.getBool( XML_applyProtection, bApplyDefault); + + maModel.mbFontUsed = rAttribs.getBool( XML_applyFont, bApplyDefault || maModel.mnFontId > 0); + maModel.mbNumFmtUsed = rAttribs.getBool( XML_applyNumberFormat, bApplyDefault || maModel.mnNumFmtId > 0); + maModel.mbBorderUsed = rAttribs.getBool( XML_applyBorder, bApplyDefault || maModel.mnBorderId > 0); + maModel.mbAreaUsed = rAttribs.getBool( XML_applyFill, bApplyDefault || maModel.mnFillId > 0); +} + +void Xf::importAlignment( const AttributeList& rAttribs ) +{ + maAlignment.importAlignment( rAttribs ); + if (maModel.mbCellXf) + maModel.mbAlignUsed = true; +} + +void Xf::importProtection( const AttributeList& rAttribs ) +{ + maProtection.importProtection( rAttribs ); + if (maModel.mbCellXf) + maModel.mbProtUsed = true; +} + +void Xf::importXf( SequenceInputStream& rStrm, bool bCellXf ) +{ + maModel.mbCellXf = bCellXf; + maModel.mnStyleXfId = rStrm.readuInt16(); + maModel.mnNumFmtId = rStrm.readuInt16(); + maModel.mnFontId = rStrm.readuInt16(); + maModel.mnFillId = rStrm.readuInt16(); + maModel.mnBorderId = rStrm.readuInt16(); + sal_uInt32 nFlags = rStrm.readuInt32(); + maAlignment.setBiff12Data( nFlags ); + maProtection.setBiff12Data( nFlags ); + // used flags, see comments in Xf::setBiffUsedFlags() + sal_uInt16 nUsedFlags = rStrm.readuInt16(); + maModel.mbFontUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_FONT_USED ); + maModel.mbNumFmtUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_NUMFMT_USED ); + maModel.mbAlignUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_ALIGN_USED ); + maModel.mbProtUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_PROT_USED ); + maModel.mbBorderUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_BORDER_USED ); + maModel.mbAreaUsed = maModel.mbCellXf == getFlag( nUsedFlags, BIFF12_XF_AREA_USED ); +} + +void Xf::finalizeImport() +{ + // alignment and protection + maAlignment.finalizeImport(); + maProtection.finalizeImport(); +} + +FontRef Xf::getFont() const +{ + return getStyles().getFont( maModel.mnFontId ); +} + +void Xf::applyPatternToAttrList( AttrList& rAttrs, SCROW nRow1, SCROW nRow2, sal_Int32 nNumFmtId ) +{ + createPattern(); + ScPatternAttr& rPat = *mpPattern; + ScDocumentImport& rDocImport = getDocImport(); + ScDocument& rDoc = getScDocument(); + if ( isCellXf() ) + { + StylesBuffer& rStyles = getStyles(); + rStyles.createCellStyle( maModel.mnStyleXfId ); + + mpStyleSheet = rStyles.getCellStyleSheet( maModel.mnStyleXfId ); + if ( mpStyleSheet ) + { + //rDoc.ApplySelectionStyle( static_cast<ScStyleSheet&>(*mpStyleSheet), rMarkData ); + rPat.SetStyleSheet(mpStyleSheet, false); + } + else + { + ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool(); + if (pStylePool) + { + ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( + pStylePool->Find( + ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para)); + + if (pStyleSheet) + rPat.SetStyleSheet( pStyleSheet, false ); + } + } + } + if ( nNumFmtId >= 0 ) + { + ScPatternAttr aNumPat(rDoc.GetPool()); + mnScNumFmt = getStyles().writeNumFmtToItemSet( aNumPat.GetItemSet(), nNumFmtId, false ); + rPat.GetItemSet().Put(aNumPat.GetItemSet()); + } + + if (!rDocImport.isLatinScript(mnScNumFmt)) + rAttrs.mbLatinNumFmtOnly = false; + + if (!rPat.GetStyleName()) + return; + + // Check for a gap between the last entry and this one. + bool bHasGap = false; + if (rAttrs.maAttrs.empty() && nRow1 > 0) + // First attribute range doesn't start at row 0. + bHasGap = true; + + if (!rAttrs.maAttrs.empty() && rAttrs.maAttrs.back().nEndRow + 1 < nRow1) + bHasGap = true; + + if (bHasGap) + { + // Fill this gap with the default pattern. + ScAttrEntry aEntry; + aEntry.nEndRow = nRow1 - 1; + aEntry.pPattern = &rDoc.GetPool()->Put(*rAttrs.mpDefPattern); + rAttrs.maAttrs.push_back(aEntry); + + // Check if the default pattern is 'General'. + if (!rDocImport.isLatinScript(*aEntry.pPattern)) + rAttrs.mbLatinNumFmtOnly = false; + } + + ScAttrEntry aEntry; + aEntry.nEndRow = nRow2; + aEntry.pPattern = &rDoc.GetPool()->Put(rPat); + rAttrs.maAttrs.push_back(aEntry); + + if (!rDocImport.isLatinScript(*aEntry.pPattern)) + rAttrs.mbLatinNumFmtOnly = false; +} + +void Xf::writeToDoc( ScDocumentImport& rDoc, const ScRange& rRange ) +{ + const StylesBuffer& rStyles = getStyles(); + + if (isCellXf()) + { + // Cell style name. + OUString aStyleName = rStyles.createCellStyle(maModel.mnStyleXfId); + + ScStyleSheet* pStyleSheet = + static_cast<ScStyleSheet*>( + rDoc.getDoc().GetStyleSheetPool()->Find(aStyleName, SfxStyleFamily::Para)); + + if (pStyleSheet) + { + rDoc.getDoc().ApplyStyleAreaTab( + rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab(), + *pStyleSheet); + } + } + + const ScPatternAttr& rAttr = createPattern(); + rDoc.getDoc().ApplyPatternAreaTab( + rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab(), rAttr); +} + +const ::ScPatternAttr& +Xf::createPattern( bool bSkipPoolDefs ) +{ + if( mpPattern ) + return *mpPattern; + mpPattern.reset( new ::ScPatternAttr( getScDocument().GetPool() ) ); + SfxItemSet& rItemSet = mpPattern->GetItemSet(); + /* Enables the used flags, if the formatting attributes differ from the + style XF. In cell XFs Excel uses the cell attributes, if they differ + from the parent style XF (even if the used flag is switched off). + #109899# ...or if the respective flag is not set in parent style XF. + */ + StylesBuffer& rStyles = getStyles(); + + const Xf* pStyleXf = isCellXf() ? rStyles.getStyleXf( maModel.mnStyleXfId ).get() : nullptr; + if( pStyleXf && !mpStyleSheet ) + { + rStyles.createCellStyle( maModel.mnStyleXfId ); + mpStyleSheet = rStyles.getCellStyleSheet( maModel.mnStyleXfId ); + OSL_ENSURE( mpStyleSheet, "Xf::createPattern - no parentStyle created" ); + + const XfModel& rStyleData = pStyleXf->maModel; + if( !maModel.mbFontUsed ) + maModel.mbFontUsed = !rStyleData.mbFontUsed || (maModel.mnFontId != rStyleData.mnFontId); + if( !maModel.mbNumFmtUsed ) + maModel.mbNumFmtUsed = !rStyleData.mbNumFmtUsed || (maModel.mnNumFmtId != rStyleData.mnNumFmtId); + if( !maModel.mbAlignUsed ) + maModel.mbAlignUsed = !rStyleData.mbAlignUsed || !(maAlignment.getApiData() == pStyleXf->maAlignment.getApiData()); + if( !maModel.mbProtUsed ) + maModel.mbProtUsed = !rStyleData.mbProtUsed || !(maProtection.getApiData() == pStyleXf->maProtection.getApiData()); + if( !maModel.mbBorderUsed ) + maModel.mbBorderUsed = !rStyleData.mbBorderUsed || !StylesBuffer::equalBorders( maModel.mnBorderId, rStyleData.mnBorderId ); + if( !maModel.mbAreaUsed ) + maModel.mbAreaUsed = !rStyleData.mbAreaUsed || !StylesBuffer::equalFills( maModel.mnFillId, rStyleData.mnFillId ); + } + // cell protection + if( maModel.mbProtUsed ) + { + maProtection.fillToItemSet( rItemSet, bSkipPoolDefs ); + } + + // font + if( maModel.mbFontUsed ) + { + rStyles.writeFontToItemSet( rItemSet, maModel.mnFontId, bSkipPoolDefs ); + } + + // value format + if( maModel.mbNumFmtUsed ) + { + mnScNumFmt = rStyles.writeNumFmtToItemSet( rItemSet, maModel.mnNumFmtId, bSkipPoolDefs ); + } + // alignment + if( maModel.mbAlignUsed ) + { + maAlignment.fillToItemSet( rItemSet, bSkipPoolDefs ); + } + + // border + if( maModel.mbBorderUsed ) + { + rStyles.writeBorderToItemSet( rItemSet, maModel.mnBorderId, bSkipPoolDefs ); + } + + // area + if( maModel.mbAreaUsed ) + { + rStyles.writeFillToItemSet( rItemSet, maModel.mnFillId, bSkipPoolDefs ); + } + + /* #i38709# Decide which rotation reference mode to use. If any outer + border line of the cell is set (either explicitly or via cell style), + and the cell contents are rotated, set rotation reference to bottom of + cell. This causes the borders to be painted rotated with the text. */ + if( const Alignment* pAlignment = maModel.mbAlignUsed ? &maAlignment : (pStyleXf ? &pStyleXf->maAlignment : nullptr) ) + { + SvxRotateMode eRotateMode = SVX_ROTATE_MODE_STANDARD; + sal_Int32 nBorderId = maModel.mbBorderUsed ? maModel.mnBorderId : (pStyleXf ? pStyleXf->maModel.mnBorderId : -1); + if( const Border* pBorder = rStyles.getBorder( nBorderId ).get() ) + { + if( (pAlignment->getApiData().mnRotation) && pBorder->getApiData().hasAnyOuterBorder() ) + { + meRotationRef = css::table::CellVertJustify2::BOTTOM; + eRotateMode = SVX_ROTATE_MODE_BOTTOM; + } + } + ScfTools::PutItem( rItemSet, SvxRotateModeItem( eRotateMode, ATTR_ROTATE_MODE ), bSkipPoolDefs ); + } + + return *mpPattern; +} + +Dxf::Dxf( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ) +{ +} + +FontRef const & Dxf::createFont( bool bAlwaysNew ) +{ + if( bAlwaysNew || !mxFont ) + mxFont = std::make_shared<Font>( *this, true ); + return mxFont; +} + +BorderRef const & Dxf::createBorder( bool bAlwaysNew ) +{ + if( bAlwaysNew || !mxBorder ) + mxBorder = std::make_shared<Border>( *this, true ); + return mxBorder; +} + +FillRef const & Dxf::createFill( bool bAlwaysNew ) +{ + if( bAlwaysNew || !mxFill ) + mxFill = std::make_shared<Fill>( *this, true ); + return mxFill; +} + +void Dxf::importNumFmt( const AttributeList& rAttribs ) +{ + // don't propagate number formats defined in Dxf entries + // they can have the same id ( but different format codes ) as those + // defined globally earlier. We discard the id defined in XML_numFmtId + // and generate one ourselves ( this assumes that the normal numberformat + // import has already taken place ) + sal_Int32 nNumFmtId = getStyles().nextFreeNumFmtId(); + OUString aFmtCode = rAttribs.getXString( XML_formatCode, OUString() ); + mxNumFmt = getStyles().createNumFmt( nNumFmtId, aFmtCode ); +} + +void Dxf::importDxf( SequenceInputStream& rStrm ) +{ + sal_Int32 nNumFmtId = -1; + OUString aFmtCode; + sal_uInt16 nRecCount; + rStrm.skip( 4 ); // flags + nRecCount = rStrm.readuInt16(); + for( sal_uInt16 nRec = 0; !rStrm.isEof() && (nRec < nRecCount); ++nRec ) + { + sal_uInt16 nSubRecId, nSubRecSize; + sal_Int64 nRecEnd = rStrm.tell(); + nSubRecId = rStrm.readuInt16(); + nSubRecSize = rStrm.readuInt16(); + nRecEnd += nSubRecSize; + switch( nSubRecId ) + { + case BIFF12_DXF_FILL_PATTERN: createFill( false )->importDxfPattern( rStrm ); break; + case BIFF12_DXF_FILL_FGCOLOR: createFill( false )->importDxfFgColor( rStrm ); break; + case BIFF12_DXF_FILL_BGCOLOR: createFill( false )->importDxfBgColor( rStrm ); break; + case BIFF12_DXF_FILL_GRADIENT: createFill( false )->importDxfGradient( rStrm ); break; + case BIFF12_DXF_FILL_STOP: createFill( false )->importDxfStop( rStrm ); break; + case BIFF12_DXF_FONT_COLOR: createFont( false )->importDxfColor( rStrm ); break; + case BIFF12_DXF_BORDER_TOP: createBorder( false )->importDxfBorder( XLS_TOKEN( top ), rStrm ); break; + case BIFF12_DXF_BORDER_BOTTOM: createBorder( false )->importDxfBorder( XLS_TOKEN( bottom ), rStrm ); break; + case BIFF12_DXF_BORDER_LEFT: createBorder( false )->importDxfBorder( XLS_TOKEN( left ), rStrm ); break; + case BIFF12_DXF_BORDER_RIGHT: createBorder( false )->importDxfBorder( XLS_TOKEN( right ), rStrm ); break; + case BIFF12_DXF_FONT_NAME: createFont( false )->importDxfName( rStrm ); break; + case BIFF12_DXF_FONT_WEIGHT: createFont( false )->importDxfWeight( rStrm ); break; + case BIFF12_DXF_FONT_UNDERLINE: createFont( false )->importDxfUnderline( rStrm ); break; + case BIFF12_DXF_FONT_ESCAPEMENT: createFont( false )->importDxfEscapement( rStrm ); break; + case BIFF12_DXF_FONT_ITALIC: createFont( false )->importDxfFlag( XML_i, rStrm ); break; + case BIFF12_DXF_FONT_STRIKE: createFont( false )->importDxfFlag( XML_strike, rStrm ); break; + case BIFF12_DXF_FONT_OUTLINE: createFont( false )->importDxfFlag( XML_outline, rStrm ); break; + case BIFF12_DXF_FONT_SHADOW: createFont( false )->importDxfFlag( XML_shadow, rStrm ); break; + case BIFF12_DXF_FONT_HEIGHT: createFont( false )->importDxfHeight( rStrm ); break; + case BIFF12_DXF_FONT_SCHEME: createFont( false )->importDxfScheme( rStrm ); break; + case BIFF12_DXF_NUMFMT_CODE: aFmtCode = BiffHelper::readString( rStrm, false ); break; + case BIFF12_DXF_NUMFMT_ID: nNumFmtId = rStrm.readuInt16(); break; + } + rStrm.seek( nRecEnd ); + } + OSL_ENSURE( !rStrm.isEof() && (rStrm.getRemaining() == 0), "Dxf::importDxf - unexpected remaining data" ); + mxNumFmt = getStyles().createNumFmt( nNumFmtId, aFmtCode ); +} + +void Dxf::finalizeImport() +{ + if( mxFont ) + mxFont->finalizeImport(); + bool bRTL = false; + // number format already finalized by the number formats buffer + if( mxAlignment ) + { + mxAlignment->finalizeImport(); + // how do we detect RTL when text dir is OOX_XF_CONTEXT? ( seems you + // would need access to the cell content, which we don't here ) + if ( mxAlignment->getModel().mnTextDir == OOX_XF_TEXTDIR_RTL ) + bRTL = true; + } + if( mxProtection ) + mxProtection->finalizeImport(); + if( mxBorder ) + { + mxBorder->finalizeImport( bRTL ); + } + if( mxFill ) + mxFill->finalizeImport(); +} + +void Dxf::fillToItemSet( SfxItemSet& rSet ) const +{ + if (mxFont) + mxFont->fillToItemSet(rSet, false); + if (mxNumFmt) + mxNumFmt->fillToItemSet(rSet); + if (mxAlignment) + mxAlignment->fillToItemSet(rSet); + if (mxProtection) + mxProtection->fillToItemSet(rSet); + if (mxBorder) + mxBorder->fillToItemSet(rSet); + if (mxFill) + mxFill->fillToItemSet(rSet); +} + +namespace { + +const char* const sppcStyleNames[] = +{ + "Normal", + "RowLevel_", // outline level will be appended + "ColLevel_", // outline level will be appended + "Comma", + "Currency", + "Percent", + "Comma [0]", // new in BIFF4 + "Currency [0]", + "Hyperlink", // new in BIFF8 + "Followed Hyperlink", + "Note", // new in OOX + "Warning Text", + nullptr, + nullptr, + nullptr, + "Title", + "Heading 1", + "Heading 2", + "Heading 3", + "Heading 4", + "Input", + "Output", + "Calculation", + "Check Cell", + "Linked Cell", + "Total", + "Good", + "Bad", + "Neutral", + "Accent1", + "20% - Accent1", + "40% - Accent1", + "60% - Accent1", + "Accent2", + "20% - Accent2", + "40% - Accent2", + "60% - Accent2", + "Accent3", + "20% - Accent3", + "40% - Accent3", + "60% - Accent3", + "Accent4", + "20% - Accent4", + "40% - Accent4", + "60% - Accent4", + "Accent5", + "20% - Accent5", + "40% - Accent5", + "60% - Accent5", + "Accent6", + "20% - Accent6", + "40% - Accent6", + "60% - Accent6", + "Explanatory Text" +}; +const sal_Int32 snStyleNamesCount = static_cast< sal_Int32 >( SAL_N_ELEMENTS( sppcStyleNames ) ); + +OUString lclGetBuiltinStyleName( sal_Int32 nBuiltinId, std::u16string_view rName, sal_Int32 nLevel = 0 ) +{ + OSL_ENSURE( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount), "lclGetBuiltinStyleName - unknown built-in style" ); + OUStringBuffer aStyleName("Excel Built-in "); + if( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount) && (sppcStyleNames[ nBuiltinId ] != nullptr) ) + aStyleName.appendAscii( sppcStyleNames[ nBuiltinId ] ); + else if( !rName.empty() ) + aStyleName.append( rName ); + else + aStyleName.append( nBuiltinId ); + if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) ) + aStyleName.append( nLevel ); + return aStyleName.makeStringAndClear(); +} + +OUString lclCreateStyleName( const CellStyleModel& rModel ) +{ + return rModel.mbBuiltin ? lclGetBuiltinStyleName( rModel.mnBuiltinId, rModel.maName, rModel.mnLevel ) : rModel.maName; +} + +} // namespace + +CellStyleModel::CellStyleModel() : + mnXfId( -1 ), + mnBuiltinId( -1 ), + mnLevel( 0 ), + mbBuiltin( false ), + mbCustom( false ), + mbHidden( false ) +{ +} + +bool CellStyleModel::isBuiltin() const +{ + return mbBuiltin && (mnBuiltinId >= 0); +} + +bool CellStyleModel::isDefaultStyle() const +{ + return mbBuiltin && (mnBuiltinId == OOX_STYLE_NORMAL); +} + +CellStyle::CellStyle( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + mbCreated( false ), + mpStyleSheet( nullptr ) +{ +} + +void CellStyle::importCellStyle( const AttributeList& rAttribs ) +{ + maModel.maName = rAttribs.getXString( XML_name, OUString() ); + maModel.mnXfId = rAttribs.getInteger( XML_xfId, -1 ); + maModel.mnBuiltinId = rAttribs.getInteger( XML_builtinId, -1 ); + maModel.mnLevel = rAttribs.getInteger( XML_iLevel, 0 ); + maModel.mbBuiltin = rAttribs.hasAttribute( XML_builtinId ); + maModel.mbCustom = rAttribs.getBool( XML_customBuiltin, false ); + maModel.mbHidden = rAttribs.getBool( XML_hidden, false ); +} + +void CellStyle::importCellStyle( SequenceInputStream& rStrm ) +{ + sal_uInt16 nFlags; + maModel.mnXfId = rStrm.readInt32(); + nFlags = rStrm.readuInt16(); + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); + rStrm >> maModel.maName; + maModel.mbBuiltin = getFlag( nFlags, BIFF12_CELLSTYLE_BUILTIN ); + maModel.mbCustom = getFlag( nFlags, BIFF12_CELLSTYLE_CUSTOM ); + maModel.mbHidden = getFlag( nFlags, BIFF12_CELLSTYLE_HIDDEN ); +} + +void CellStyle::createCellStyle() +{ + + // #i1624# #i1768# ignore unnamed user styles + bool bDefStyle = maModel.isDefaultStyle(); + if( !mbCreated ) + { + if ( bDefStyle && maFinalName.isEmpty() ) + maFinalName = ScResId( STR_STYLENAME_STANDARD ); + mbCreated = maFinalName.isEmpty(); + } + + if( mbCreated || mpStyleSheet ) + return; + + bool bCreatePattern = false; + Xf* pXF = getStyles().getStyleXf( maModel.mnXfId ).get(); + ::ScDocument& rDoc = getScDocument(); + + if( bDefStyle ) + { + // use existing "Default" style sheet + mpStyleSheet = static_cast< ScStyleSheet* >( rDoc.GetStyleSheetPool()->Find( + ScResId( STR_STYLENAME_STANDARD ), SfxStyleFamily::Para ) ); + OSL_ENSURE( mpStyleSheet, "CellStyle::createStyle - Default style not found" ); + bCreatePattern = true; + } + else + { + mpStyleSheet = static_cast< ScStyleSheet* >( rDoc.GetStyleSheetPool()->Find( maFinalName, SfxStyleFamily::Para ) ); + if( !mpStyleSheet ) + { + mpStyleSheet = &static_cast< ScStyleSheet& >( rDoc.GetStyleSheetPool()->Make( maFinalName, SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined ) ); + bCreatePattern = true; + } + } + + // bDefStyle==true omits default pool items in CreatePattern() + if( bCreatePattern && mpStyleSheet && pXF ) + mpStyleSheet->GetItemSet().Put( pXF->createPattern( bDefStyle ).GetItemSet() ); +} + +void CellStyle::finalizeImport( const OUString& rFinalName ) +{ + maFinalName = rFinalName; + if( !maModel.isBuiltin() || maModel.mbCustom ) + createCellStyle(); +} + +CellStyleBuffer::CellStyleBuffer( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ) +{ +} + +CellStyleRef CellStyleBuffer::importCellStyle( const AttributeList& rAttribs ) +{ + CellStyleRef xCellStyle = std::make_shared<CellStyle>( *this ); + xCellStyle->importCellStyle( rAttribs ); + insertCellStyle( xCellStyle ); + return xCellStyle; +} + +CellStyleRef CellStyleBuffer::importCellStyle( SequenceInputStream& rStrm ) +{ + CellStyleRef xCellStyle = std::make_shared<CellStyle>( *this ); + xCellStyle->importCellStyle( rStrm ); + insertCellStyle( xCellStyle ); + return xCellStyle; +} + +void CellStyleBuffer::finalizeImport() +{ + // calculate final names of all styles + typedef RefMap< OUString, CellStyle, IgnoreCaseCompare > CellStyleNameMap; + CellStyleNameMap aCellStyles; + CellStyleVector aConflictNameStyles; + + /* First, reserve style names that are built-in in Calc. This causes that + imported cell styles get different unused names and thus do not try to + overwrite these built-in styles. */ + try + { + // unfortunately, com.sun.star.style.StyleFamily does not implement XEnumerationAccess... + Reference< XIndexAccess > xStyleFamilyIA( getCellStyleFamily(), UNO_QUERY_THROW ); + for( sal_Int32 nIndex = 0, nCount = xStyleFamilyIA->getCount(); nIndex < nCount; ++nIndex ) + { + Reference< XStyle > xStyle( xStyleFamilyIA->getByIndex( nIndex ), UNO_QUERY_THROW ); + if( !xStyle->isUserDefined() ) + { + // create an empty entry by using ::std::map<>::operator[] + aCellStyles[ xStyle->getName() ]; + } + } + } + catch( Exception& ) + { + } + + /* Calculate names of built-in styles. Store styles with reserved names + in the aConflictNameStyles list. */ + for( const auto& rxStyle : maBuiltinStyles ) + { + const CellStyleModel& rModel = rxStyle->getModel(); + if (rModel.isDefaultStyle()) + continue; + + OUString aStyleName = lclCreateStyleName( rModel ); + /* If a builtin style entry already exists, + we just stick with the last definition and ignore + the preceding ones. */ + aCellStyles[ aStyleName ] = rxStyle; + } + + /* Calculate names of user defined styles. Store styles with reserved + names in the aConflictNameStyles list. */ + for( const auto& rxStyle : maUserStyles ) + { + const CellStyleModel& rModel = rxStyle->getModel(); + OUString aStyleName = lclCreateStyleName( rModel ); + // #i1624# #i1768# ignore unnamed user styles + if( aStyleName.getLength() > 0 ) + { + if( aCellStyles.find( aStyleName ) != aCellStyles.end() ) + aConflictNameStyles.push_back( rxStyle ); + else + aCellStyles[ aStyleName ] = rxStyle; + } + } + + // find unused names for all styles with conflicting names + // having the index counter outside the loop prevents performance problems with opening some pathological documents (tdf#62095) + sal_Int32 nIndex = 0; + for( const auto& rxStyle : aConflictNameStyles ) + { + const CellStyleModel& rModel = rxStyle->getModel(); + OUString aStyleName = lclCreateStyleName( rModel ); + OUString aUnusedName; + do + { + aUnusedName = aStyleName + OUStringChar(' ') + OUString::number( ++nIndex ); + } + while( !aCellStyles.try_emplace( aUnusedName, rxStyle ).second ); + } + + // set final names and create user-defined and modified built-in cell styles + aCellStyles.forEachMemWithKey( &CellStyle::finalizeImport ); +} + +sal_Int32 CellStyleBuffer::getDefaultXfId() const +{ + return mxDefStyle ? mxDefStyle->getModel().mnXfId : -1; +} + +OUString CellStyleBuffer::getDefaultStyleName() const +{ + return createCellStyle( mxDefStyle ); +} + +OUString CellStyleBuffer::createCellStyle( sal_Int32 nXfId ) const +{ + return createCellStyle( maStylesByXf.get( nXfId ) ); +} + +::ScStyleSheet* CellStyleBuffer::getCellStyleSheet( sal_Int32 nXfId ) const +{ + return getCellStyleSheet( maStylesByXf.get( nXfId ) ); +} + +// private -------------------------------------------------------------------- + +void CellStyleBuffer::insertCellStyle( CellStyleRef const & xCellStyle ) +{ + const CellStyleModel& rModel = xCellStyle->getModel(); + if( rModel.mnXfId < 0 ) + return; + + // insert into the built-in map or user defined map + (rModel.isBuiltin() ? maBuiltinStyles : maUserStyles).push_back( xCellStyle ); + + // insert into the XF identifier map + OSL_ENSURE( maStylesByXf.count( rModel.mnXfId ) == 0, "CellStyleBuffer::insertCellStyle - multiple styles with equal XF identifier" ); + maStylesByXf[ rModel.mnXfId ] = xCellStyle; + + // remember default cell style + if( rModel.isDefaultStyle() ) + mxDefStyle = xCellStyle; +} + +::ScStyleSheet* CellStyleBuffer::getCellStyleSheet( const CellStyleRef& rxCellStyle ) +{ + ::ScStyleSheet* pStyleSheet = nullptr; + if ( rxCellStyle ) + pStyleSheet = rxCellStyle->getStyleSheet(); + return pStyleSheet; +} + +OUString CellStyleBuffer::createCellStyle( const CellStyleRef& rxCellStyle ) +{ + if( rxCellStyle ) + { + rxCellStyle->createCellStyle(); + const OUString& rStyleName = rxCellStyle->getFinalStyleName(); + if( !rStyleName.isEmpty() ) + return rStyleName; + } + // on error: fallback to default style + return lclGetBuiltinStyleName( OOX_STYLE_NORMAL, u"" ); +} + +AutoFormatModel::AutoFormatModel() : + mnAutoFormatId( 0 ), + mbApplyNumFmt( false ), + mbApplyFont( false ), + mbApplyAlignment( false ), + mbApplyBorder( false ), + mbApplyFill( false ), + mbApplyProtection( false ) +{ +} + +StylesBuffer::StylesBuffer( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + maPalette( rHelper ), + maNumFmts( rHelper ), + maCellStyles( rHelper ) +{ +} + +FontRef StylesBuffer::createFont() +{ + FontRef xFont = std::make_shared<Font>( *this, false ); + maFonts.push_back( xFont ); + return xFont; +} + +NumberFormatRef StylesBuffer::createNumFmt( sal_Int32 nNumFmtId, const OUString& rFmtCode ) +{ + return maNumFmts.createNumFmt( nNumFmtId, rFmtCode ); +} + +sal_Int32 StylesBuffer::nextFreeNumFmtId() +{ + return maNumFmts.nextFreeId(); +} + +BorderRef StylesBuffer::createBorder() +{ + BorderRef xBorder = std::make_shared<Border>( *this, false ); + maBorders.push_back( xBorder ); + return xBorder; +} + +FillRef StylesBuffer::createFill() +{ + FillRef xFill = std::make_shared<Fill>( *this, false ); + maFills.push_back( xFill ); + return xFill; +} + +XfRef StylesBuffer::createCellXf() +{ + XfRef xXf = std::make_shared<Xf>( *this ); + maCellXfs.push_back( xXf ); + return xXf; +} + +XfRef StylesBuffer::createStyleXf() +{ + XfRef xXf = std::make_shared<Xf>( *this ); + maStyleXfs.push_back( xXf ); + return xXf; +} + +DxfRef StylesBuffer::createDxf() +{ + DxfRef xDxf = std::make_shared<Dxf>( *this ); + maDxfs.push_back( xDxf ); + return xDxf; +} + +DxfRef StylesBuffer::createExtDxf() +{ + DxfRef xDxf = std::make_shared<Dxf>( *this ); + maExtDxfs.push_back( xDxf ); + return xDxf; +} + +void StylesBuffer::importPaletteColor( const AttributeList& rAttribs ) +{ + maPalette.importPaletteColor( rAttribs ); +} + +NumberFormatRef StylesBuffer::importNumFmt( const AttributeList& rAttribs ) +{ + return maNumFmts.importNumFmt( rAttribs ); +} + +CellStyleRef StylesBuffer::importCellStyle( const AttributeList& rAttribs ) +{ + return maCellStyles.importCellStyle( rAttribs ); +} + +void StylesBuffer::importPaletteColor( SequenceInputStream& rStrm ) +{ + maPalette.importPaletteColor( rStrm ); +} + +void StylesBuffer::importNumFmt( SequenceInputStream& rStrm ) +{ + maNumFmts.importNumFmt( rStrm ); +} + +void StylesBuffer::importCellStyle( SequenceInputStream& rStrm ) +{ + maCellStyles.importCellStyle( rStrm ); +} + +void StylesBuffer::finalizeImport() +{ + // fonts first, are needed to finalize unit converter and XFs below + maFonts.forEachMem( &Font::finalizeImport ); + // finalize unit coefficients after default font is known + getUnitConverter().finalizeImport(); + // number formats + maNumFmts.finalizeImport(); + // borders and fills + // is there a document wide RTL setting that we + // would/could need to pass to finalizeImport here ? + maBorders.forEachMem( &Border::finalizeImport, false ); + maFills.forEachMem( &Fill::finalizeImport ); + // style XFs and cell XFs + maStyleXfs.forEachMem( &Xf::finalizeImport ); + maCellXfs.forEachMem( &Xf::finalizeImport ); + // built-in and user defined cell styles + maCellStyles.finalizeImport(); + // differential formatting (for conditional formatting) + maDxfs.forEachMem( &Dxf::finalizeImport ); +} + +::Color StylesBuffer::getPaletteColor( sal_Int32 nPaletteIdx ) const +{ + return maPalette.getColor( nPaletteIdx ); +} + +FontRef StylesBuffer::getFont( sal_Int32 nFontId ) const +{ + return maFonts.get( nFontId ); +} + +BorderRef StylesBuffer::getBorder( sal_Int32 nBorderId ) const +{ + return maBorders.get( nBorderId ); +} + +XfRef StylesBuffer::getCellXf( sal_Int32 nXfId ) const +{ + return maCellXfs.get( nXfId ); +} + +XfRef StylesBuffer::getStyleXf( sal_Int32 nXfId ) const +{ + return maStyleXfs.get( nXfId ); +} + +FontRef StylesBuffer::getFontFromCellXf( sal_Int32 nXfId ) const +{ + FontRef xFont; + if( const Xf* pXf = getCellXf( nXfId ).get() ) + xFont = pXf->getFont(); + return xFont; +} + +FontRef StylesBuffer::getDefaultFont() const +{ + FontRef xDefFont; + if( const Xf* pXf = getStyleXf( maCellStyles.getDefaultXfId() ).get() ) + xDefFont = pXf->getFont(); + // no font from styles - try first loaded font (e.g. BIFF2) + if( !xDefFont ) + xDefFont = maFonts.get( 0 ); + OSL_ENSURE( xDefFont, "StylesBuffer::getDefaultFont - no default font found" ); + return xDefFont; +} + +const FontModel& StylesBuffer::getDefaultFontModel() const +{ + FontRef xDefFont = getDefaultFont(); + return xDefFont ? xDefFont->getModel() : getTheme().getDefaultFontModel(); +} + +bool StylesBuffer::equalBorders( sal_Int32 nBorderId1, sal_Int32 nBorderId2 ) +{ + // in OOXML, borders are assumed to be unique + return nBorderId1 == nBorderId2; +} + +bool StylesBuffer::equalFills( sal_Int32 nFillId1, sal_Int32 nFillId2 ) +{ + // in OOXML, fills are assumed to be unique + return nFillId1 == nFillId2; +} + +OUString StylesBuffer::getDefaultStyleName() const +{ + return maCellStyles.getDefaultStyleName(); +} + +OUString StylesBuffer::createCellStyle( sal_Int32 nXfId ) const +{ + return maCellStyles.createCellStyle( nXfId ); +} + +::ScStyleSheet* StylesBuffer::getCellStyleSheet( sal_Int32 nXfId ) const +{ + return maCellStyles.getCellStyleSheet( nXfId ); +} + +OUString StylesBuffer::createDxfStyle( sal_Int32 nDxfId ) const +{ + OUString& rStyleName = maDxfStyles[ nDxfId ]; + if (!rStyleName.isEmpty()) + return rStyleName; + + if (Dxf* pDxf = maDxfs.get(nDxfId).get()) + { + // FIXME: How can we know whether this dxf is for conditional formatting, + // not for color filter? Currently this style is created for each dxf + // (which might only be used by color filter) + rStyleName = "ConditionalStyle_" + OUString::number(nDxfId + 1); + + // Create a cell style. This may overwrite an existing style if + // one with the same name exists. + ScStyleSheet& rStyleSheet = ScfTools::MakeCellStyleSheet( + *getScDocument().GetStyleSheetPool(), rStyleName, true); + + rStyleSheet.ResetParent(); + SfxItemSet& rStyleItemSet = + rStyleSheet.GetItemSet(); + + pDxf->fillToItemSet(rStyleItemSet); + + } + + // on error: fallback to default style + if (rStyleName.isEmpty()) + rStyleName = maCellStyles.getDefaultStyleName(); + + return rStyleName; +} + +OUString StylesBuffer::createExtDxfStyle( sal_Int32 nDxfId ) const +{ + OUString rStyleName; + + if (Dxf* pDxf = maExtDxfs.get(nDxfId).get()) + { + rStyleName = "ExtConditionalStyle_" + OUString::number(nDxfId + 1); + + // Create a cell style. This may overwrite an existing style if + // one with the same name exists. + ScStyleSheet& rStyleSheet = ScfTools::MakeCellStyleSheet( + *getScDocument().GetStyleSheetPool(), rStyleName, true); + + rStyleSheet.ResetParent(); + SfxItemSet& rStyleItemSet = + rStyleSheet.GetItemSet(); + + pDxf->fillToItemSet(rStyleItemSet); + } + + // on error: fallback to default style + if (rStyleName.isEmpty()) + rStyleName = maCellStyles.getDefaultStyleName(); + + return rStyleName; +} + +void StylesBuffer::writeFontToItemSet( SfxItemSet& rItemSet, sal_Int32 nFontId, bool bSkipPoolDefs ) const +{ + if( Font* pFont = maFonts.get( nFontId ).get() ) + pFont->fillToItemSet( rItemSet, false, bSkipPoolDefs ); +} + +sal_uInt32 StylesBuffer::writeNumFmtToItemSet( SfxItemSet& rItemSet, sal_uInt32 nNumFmtId, bool bSkipPoolDefs ) const +{ + return maNumFmts.fillToItemSet( rItemSet, nNumFmtId, bSkipPoolDefs ); +} + +void StylesBuffer::writeBorderToItemSet( SfxItemSet& rItemSet, sal_Int32 nBorderId, bool bSkipPoolDefs ) const +{ + if( Border* pBorder = maBorders.get( nBorderId ).get() ) + pBorder->fillToItemSet( rItemSet, bSkipPoolDefs ); +} + +void StylesBuffer::writeFillToItemSet( SfxItemSet& rItemSet, sal_Int32 nFillId, bool bSkipPoolDefs ) const +{ + if( Fill* pFill = maFills.get( nFillId ).get() ) + pFill->fillToItemSet( rItemSet, bSkipPoolDefs ); +} + +bool operator==( const XfModel& rXfModel1, const XfModel& rXfModel2 ) +{ + return ( rXfModel1.mbCellXf == rXfModel2.mbCellXf && + rXfModel1.mnStyleXfId == rXfModel2.mnStyleXfId && + rXfModel1.mbFontUsed == rXfModel2.mbFontUsed && + rXfModel1.mnFontId == rXfModel2.mnFontId && + rXfModel1.mbNumFmtUsed == rXfModel2.mbNumFmtUsed && + rXfModel1.mnNumFmtId == rXfModel2.mnNumFmtId && + rXfModel1.mbAlignUsed == rXfModel2.mbAlignUsed && + rXfModel1.mbBorderUsed == rXfModel2.mbBorderUsed && + rXfModel1.mnBorderId == rXfModel2.mnBorderId && + rXfModel1.mbAreaUsed == rXfModel2.mbAreaUsed && + rXfModel1.mnFillId == rXfModel2.mnFillId && + rXfModel1.mbProtUsed == rXfModel2.mbProtUsed ); +} + +bool operator==( const Xf& rXf1, const Xf& rXf2 ) +{ + if ( rXf1.maModel == rXf2.maModel ) + { + if ( rXf1.maModel.mbAlignUsed ) + { + if ( !( rXf1.maAlignment.getApiData() == rXf2.maAlignment.getApiData() ) ) + return false; + } + if ( rXf1.maModel.mbProtUsed ) + { + if ( !( rXf1.maProtection.getApiData() == rXf2.maProtection.getApiData() ) ) + return false; + } + return true; + } + return false; +} + +void StylesBuffer::writeCellXfToDoc( + ScDocumentImport& rDoc, const ScRange& rRange, sal_Int32 nXfId ) const +{ + Xf* pXf = maCellXfs.get(nXfId).get(); + if (!pXf) + return; + + pXf->writeToDoc(rDoc, rRange); +} + +} // namespace oox + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |