diff options
Diffstat (limited to 'oox/source/xls/stylesbuffer.cxx')
-rw-r--r-- | oox/source/xls/stylesbuffer.cxx | 3447 |
1 files changed, 3447 insertions, 0 deletions
diff --git a/oox/source/xls/stylesbuffer.cxx b/oox/source/xls/stylesbuffer.cxx new file mode 100644 index 000000000000..5a149961c0e2 --- /dev/null +++ b/oox/source/xls/stylesbuffer.cxx @@ -0,0 +1,3447 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/xls/stylesbuffer.hxx" +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#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/style/XStyle.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/text/XText.hpp> +#include <rtl/tencinfo.h> +#include <rtl/ustrbuf.hxx> +#include "properties.hxx" +#include "oox/helper/attributelist.hxx" +#include "oox/helper/propertymap.hxx" +#include "oox/helper/propertyset.hxx" +#include "oox/helper/recordinputstream.hxx" +#include "oox/core/filterbase.hxx" +#include "oox/xls/biffinputstream.hxx" +#include "oox/xls/condformatbuffer.hxx" +#include "oox/xls/excelhandlers.hxx" +#include "oox/xls/themebuffer.hxx" +#include "oox/xls/unitconverter.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_SET_THROW; +using ::com::sun::star::container::XIndexAccess; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::container::XNamed; +using ::com::sun::star::awt::FontDescriptor; +using ::com::sun::star::awt::XDevice; +using ::com::sun::star::awt::XFont2; +using ::com::sun::star::table::BorderLine; +using ::com::sun::star::table::TableBorder; +using ::com::sun::star::text::XText; +using ::com::sun::star::style::XStyle; +using ::oox::core::FilterBase; + +namespace oox { +namespace xls { + +// ============================================================================ + +namespace { + +// OOXML constants ------------------------------------------------------------ + +// OOX predefined color indexes (also used in BIFF3-BIFF8) +const sal_Int32 OOX_COLOR_USEROFFSET = 0; /// First user defined color in palette (OOX). +const sal_Int32 BIFF_COLOR_USEROFFSET = 8; /// First user defined color in palette (BIFF). + +// OOX 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; + +// OOX 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; + +// OOX cell rotation (also used in BIFF) +const sal_Int32 OOX_XF_ROTATION_NONE = 0; +const sal_Int32 OOX_XF_ROTATION_90CCW = 90; +const sal_Int32 OOX_XF_ROTATION_90CW = 180; +const sal_Int32 OOX_XF_ROTATION_STACKED = 255; + +// OOX cell indentation +const sal_Int32 OOX_XF_INDENT_NONE = 0; + +// OOX 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. + +const sal_Int32 OOX_STYLE_LEVELCOUNT = 7; /// Number of outline level styles. + +// OOBIN constants ------------------------------------------------------------ + +// OOBIN color types +const sal_uInt8 OOBIN_COLOR_AUTO = 0; +const sal_uInt8 OOBIN_COLOR_INDEXED = 1; +const sal_uInt8 OOBIN_COLOR_RGB = 2; +const sal_uInt8 OOBIN_COLOR_THEME = 3; + +// OOBIN diagonal borders +const sal_uInt8 OOBIN_BORDER_DIAG_TLBR = 0x01; /// Top-left to bottom-right. +const sal_uInt8 OOBIN_BORDER_DIAG_BLTR = 0x02; /// Bottom-left to top-right. + +// OOBIN gradient fill +const sal_Int32 OOBIN_FILL_GRADIENT = 40; + +// OOBIN XF flags +const sal_uInt32 OOBIN_XF_WRAPTEXT = 0x00400000; +const sal_uInt32 OOBIN_XF_JUSTLASTLINE = 0x00800000; +const sal_uInt32 OOBIN_XF_SHRINK = 0x01000000; +const sal_uInt32 OOBIN_XF_LOCKED = 0x10000000; +const sal_uInt32 OOBIN_XF_HIDDEN = 0x20000000; + +// OOBIN XF attribute used flags +const sal_uInt16 OOBIN_XF_NUMFMT_USED = 0x0001; +const sal_uInt16 OOBIN_XF_FONT_USED = 0x0002; +const sal_uInt16 OOBIN_XF_ALIGN_USED = 0x0004; +const sal_uInt16 OOBIN_XF_BORDER_USED = 0x0008; +const sal_uInt16 OOBIN_XF_AREA_USED = 0x0010; +const sal_uInt16 OOBIN_XF_PROT_USED = 0x0020; + +// OOBIN DXF constants +const sal_uInt16 OOBIN_DXF_FILL_PATTERN = 0; +const sal_uInt16 OOBIN_DXF_FILL_FGCOLOR = 1; +const sal_uInt16 OOBIN_DXF_FILL_BGCOLOR = 2; +const sal_uInt16 OOBIN_DXF_FILL_GRADIENT = 3; +const sal_uInt16 OOBIN_DXF_FILL_STOP = 4; +const sal_uInt16 OOBIN_DXF_FONT_COLOR = 5; +const sal_uInt16 OOBIN_DXF_BORDER_TOP = 6; +const sal_uInt16 OOBIN_DXF_BORDER_BOTTOM = 7; +const sal_uInt16 OOBIN_DXF_BORDER_LEFT = 8; +const sal_uInt16 OOBIN_DXF_BORDER_RIGHT = 9; +const sal_uInt16 OOBIN_DXF_BORDER_DIAG = 10; +const sal_uInt16 OOBIN_DXF_BORDER_VERT = 11; +const sal_uInt16 OOBIN_DXF_BORDER_HOR = 12; +const sal_uInt16 OOBIN_DXF_BORDER_DIAGUP = 13; +const sal_uInt16 OOBIN_DXF_BORDER_DIAGDOWN = 14; +const sal_uInt16 OOBIN_DXF_FONT_NAME = 24; +const sal_uInt16 OOBIN_DXF_FONT_WEIGHT = 25; +const sal_uInt16 OOBIN_DXF_FONT_UNDERLINE = 26; +const sal_uInt16 OOBIN_DXF_FONT_ESCAPEMENT = 27; +const sal_uInt16 OOBIN_DXF_FONT_ITALIC = 28; +const sal_uInt16 OOBIN_DXF_FONT_STRIKE = 29; +const sal_uInt16 OOBIN_DXF_FONT_OUTLINE = 30; +const sal_uInt16 OOBIN_DXF_FONT_SHADOW = 31; +const sal_uInt16 OOBIN_DXF_FONT_CONDENSE = 32; +const sal_uInt16 OOBIN_DXF_FONT_EXTEND = 33; +const sal_uInt16 OOBIN_DXF_FONT_CHARSET = 34; +const sal_uInt16 OOBIN_DXF_FONT_FAMILY = 35; +const sal_uInt16 OOBIN_DXF_FONT_HEIGHT = 36; +const sal_uInt16 OOBIN_DXF_FONT_SCHEME = 37; +const sal_uInt16 OOBIN_DXF_NUMFMT_CODE = 38; +const sal_uInt16 OOBIN_DXF_NUMFMT_ID = 41; + +// OOBIN CELLSTYLE flags +const sal_uInt16 OOBIN_CELLSTYLE_BUILTIN = 0x0001; +const sal_uInt16 OOBIN_CELLSTYLE_HIDDEN = 0x0002; +const sal_uInt16 OOBIN_CELLSTYLE_CUSTOM = 0x0004; + +// OOBIN and BIFF constants --------------------------------------------------- + +// BIFF predefined color indexes +const sal_uInt16 BIFF2_COLOR_BLACK = 0; /// Black (text) in BIFF2. +const sal_uInt16 BIFF2_COLOR_WHITE = 1; /// White (background) in BIFF2. + +// BIFF font flags, also used in OOBIN +const sal_uInt16 BIFF_FONTFLAG_BOLD = 0x0001; +const sal_uInt16 BIFF_FONTFLAG_ITALIC = 0x0002; +const sal_uInt16 BIFF_FONTFLAG_UNDERLINE = 0x0004; +const sal_uInt16 BIFF_FONTFLAG_STRIKEOUT = 0x0008; +const sal_uInt16 BIFF_FONTFLAG_OUTLINE = 0x0010; +const sal_uInt16 BIFF_FONTFLAG_SHADOW = 0x0020; +const sal_uInt16 BIFF_FONTFLAG_CONDENSE = 0x0040; + +// BIFF font weight +const sal_uInt16 BIFF_FONTWEIGHT_BOLD = 450; + +// BIFF font underline, also used in OOBIN +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; + +// BIFF XF flags +const sal_uInt16 BIFF_XF_LOCKED = 0x0001; +const sal_uInt16 BIFF_XF_HIDDEN = 0x0002; +const sal_uInt16 BIFF_XF_STYLE = 0x0004; +const sal_uInt16 BIFF_XF_STYLEPARENT = 0x0FFF; /// Syles don't have a parent. +const sal_uInt16 BIFF_XF_WRAPTEXT = 0x0008; /// Automatic line break. +const sal_uInt16 BIFF_XF_JUSTLASTLINE = 0x0080; +const sal_uInt16 BIFF_XF_SHRINK = 0x0010; /// Shrink to fit into cell. +const sal_uInt16 BIFF_XF_MERGE = 0x0020; + +// BIFF XF attribute used flags +const sal_uInt8 BIFF_XF_NUMFMT_USED = 0x01; +const sal_uInt8 BIFF_XF_FONT_USED = 0x02; +const sal_uInt8 BIFF_XF_ALIGN_USED = 0x04; +const sal_uInt8 BIFF_XF_BORDER_USED = 0x08; +const sal_uInt8 BIFF_XF_AREA_USED = 0x10; +const sal_uInt8 BIFF_XF_PROT_USED = 0x20; + +// BIFF XF text orientation +const sal_uInt8 BIFF_XF_ORIENT_NONE = 0; +const sal_uInt8 BIFF_XF_ORIENT_STACKED = 1; /// Stacked top to bottom. +const sal_uInt8 BIFF_XF_ORIENT_90CCW = 2; /// 90 degr. counterclockwise. +const sal_uInt8 BIFF_XF_ORIENT_90CW = 3; /// 90 degr. clockwise. + +// BIFF XF line styles +const sal_uInt8 BIFF_LINE_NONE = 0; +const sal_uInt8 BIFF_LINE_THIN = 1; + +// BIFF XF patterns +const sal_uInt8 BIFF_PATT_NONE = 0; +const sal_uInt8 BIFF_PATT_125 = 17; + +// BIFF2 XF flags +const sal_uInt8 BIFF2_XF_VALFMT_MASK = 0x3F; +const sal_uInt8 BIFF2_XF_LOCKED = 0x40; +const sal_uInt8 BIFF2_XF_HIDDEN = 0x80; +const sal_uInt8 BIFF2_XF_LEFTLINE = 0x08; +const sal_uInt8 BIFF2_XF_RIGHTLINE = 0x10; +const sal_uInt8 BIFF2_XF_TOPLINE = 0x20; +const sal_uInt8 BIFF2_XF_BOTTOMLINE = 0x40; +const sal_uInt8 BIFF2_XF_BACKGROUND = 0x80; + +// BIFF8 diagonal borders +const sal_uInt32 BIFF_XF_DIAG_TLBR = 0x40000000; /// Top-left to bottom-right. +const sal_uInt32 BIFF_XF_DIAG_BLTR = 0x80000000; /// Bottom-left to top-right. + +// BIFF STYLE flags +const sal_uInt16 BIFF_STYLE_BUILTIN = 0x8000; +const sal_uInt16 BIFF_STYLE_XFMASK = 0x0FFF; + +// BIFF STYLEEXT flags +const sal_uInt8 BIFF_STYLEEXT_BUILTIN = 0x01; +const sal_uInt8 BIFF_STYLEEXT_HIDDEN = 0x02; +const sal_uInt8 BIFF_STYLEEXT_CUSTOM = 0x04; + +// BIFF conditional formatting +const sal_uInt32 BIFF_CFRULE_BORDER_LEFT = 0x00000400; +const sal_uInt32 BIFF_CFRULE_BORDER_RIGHT = 0x00000800; +const sal_uInt32 BIFF_CFRULE_BORDER_TOP = 0x00001000; +const sal_uInt32 BIFF_CFRULE_BORDER_BOTTOM = 0x00002000; +const sal_uInt32 BIFF_CFRULE_FILL_PATTERN = 0x00010000; +const sal_uInt32 BIFF_CFRULE_FILL_PATTCOLOR = 0x00020000; +const sal_uInt32 BIFF_CFRULE_FILL_FILLCOLOR = 0x00040000; +const sal_uInt32 BIFF_CFRULE_FONTBLOCK = 0x04000000; +const sal_uInt32 BIFF_CFRULE_ALIGNBLOCK = 0x08000000; +const sal_uInt32 BIFF_CFRULE_BORDERBLOCK = 0x10000000; +const sal_uInt32 BIFF_CFRULE_FILLBLOCK = 0x20000000; +const sal_uInt32 BIFF_CFRULE_PROTBLOCK = 0x40000000; + +const sal_uInt32 BIFF_CFRULE_FONT_STYLE = 0x00000002; /// Font posture or weight modified? +const sal_uInt32 BIFF_CFRULE_FONT_OUTLINE = 0x00000008; /// Font outline modified? +const sal_uInt32 BIFF_CFRULE_FONT_SHADOW = 0x00000010; /// Font shadow modified? +const sal_uInt32 BIFF_CFRULE_FONT_STRIKEOUT = 0x00000080; /// Font cancellation modified? +const sal_uInt32 BIFF_CFRULE_FONT_UNDERL = 0x00000001; /// Font underline type modified? +const sal_uInt32 BIFF_CFRULE_FONT_ESCAPEM = 0x00000001; /// Font escapement type modified? + +// ---------------------------------------------------------------------------- + +sal_Int32 lclReadRgbColor( BinaryInputStream& rStrm ) +{ + sal_uInt8 nR, nG, nB, nA; + rStrm >> nR >> nG >> nB >> nA; + sal_Int32 nValue = nA; + nValue <<= 8; + nValue |= nR; + nValue <<= 8; + nValue |= nG; + nValue <<= 8; + nValue |= nB; + return nValue; +} + +} // namespace + +// ============================================================================ + +ExcelGraphicHelper::ExcelGraphicHelper( const WorkbookHelper& rHelper ) : + GraphicHelper( rHelper.getGlobalFactory(), rHelper.getBaseFilter().getTargetFrame(), rHelper.getBaseFilter().getStorage() ), + WorkbookHelper( rHelper ) +{ +} + +sal_Int32 ExcelGraphicHelper::getSchemeColor( sal_Int32 nToken ) const +{ + if( getFilterType() == FILTER_OOX ) + return getTheme().getColorByToken( nToken ); + return GraphicHelper::getSchemeColor( nToken ); +} + +sal_Int32 ExcelGraphicHelper::getPaletteColor( sal_Int32 nPaletteIdx ) const +{ + return getStyles().getPaletteColor( nPaletteIdx ); +} + +// ============================================================================ + +void Color::setAuto() +{ + clearTransformations(); + setSchemeClr( XML_phClr ); +} + +void Color::setRgb( sal_Int32 nRgbValue, double fTint ) +{ + clearTransformations(); + setSrgbClr( 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 ) +{ + if( rAttribs.getBool( XML_auto, false ) ) + setAuto(); + else if( rAttribs.hasAttribute( XML_rgb ) ) + setRgb( rAttribs.getIntegerHex( XML_rgb, API_RGB_TRANSPARENT ), rAttribs.getDouble( XML_tint, 0.0 ) ); + else if( rAttribs.hasAttribute( XML_theme ) ) + setTheme( rAttribs.getInteger( XML_theme, -1 ), 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 + { + OSL_ENSURE( false, "Color::importColor - unknown color type" ); + setAuto(); + } +} + +void Color::importColor( RecordInputStream& rStrm ) +{ + sal_uInt8 nFlags, nIndex; + sal_Int16 nTint; + rStrm >> nFlags >> nIndex >> nTint; + + // 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 OOBIN_COLOR_AUTO: + setAuto(); + rStrm.skip( 4 ); + break; + case OOBIN_COLOR_INDEXED: + setIndexed( nIndex, fTint ); + rStrm.skip( 4 ); + break; + case OOBIN_COLOR_RGB: + setRgb( lclReadRgbColor( rStrm ), fTint ); + break; + case OOBIN_COLOR_THEME: + setTheme( nIndex, fTint ); + rStrm.skip( 4 ); + break; + default: + OSL_ENSURE( false, "Color::importColor - unknown color type" ); + setAuto(); + rStrm.skip( 4 ); + } +} + +void Color::importColorId( RecordInputStream& rStrm ) +{ + setIndexed( rStrm.readInt32() ); +} + +void Color::importColorRgb( RecordInputStream& rStrm ) +{ + setRgb( lclReadRgbColor( rStrm ) ); +} + +void Color::importColorId( BiffInputStream& rStrm, bool b16Bit ) +{ + setIndexed( b16Bit ? rStrm.readuInt16() : rStrm.readuInt8() ); +} + +void Color::importColorRgb( BiffInputStream& rStrm ) +{ + setRgb( lclReadRgbColor( rStrm ) ); +} + +RecordInputStream& operator>>( RecordInputStream& rStrm, Color& orColor ) +{ + orColor.importColor( rStrm ); + return rStrm; +} + +// ============================================================================ + +namespace { + +/** Standard EGA colors, bright. */ +#define PALETTE_EGA_COLORS_LIGHT \ + 0x000000, 0xFFFFFF, 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF +/** Standard EGA colors, dark. */ +#define PALETTE_EGA_COLORS_DARK \ + 0x800000, 0x008000, 0x000080, 0x808000, 0x800080, 0x008080, 0xC0C0C0, 0x808080 + +/** Default color table for BIFF2. */ +static const sal_Int32 spnDefColors2[] = +{ +/* 0 */ PALETTE_EGA_COLORS_LIGHT +}; + +/** Default color table for BIFF3/BIFF4. */ +static const sal_Int32 spnDefColors3[] = +{ +/* 0 */ PALETTE_EGA_COLORS_LIGHT, +/* 8 */ PALETTE_EGA_COLORS_LIGHT, +/* 16 */ PALETTE_EGA_COLORS_DARK +}; + +/** Default color table for BIFF5. */ +static const sal_Int32 spnDefColors5[] = +{ +/* 0 */ PALETTE_EGA_COLORS_LIGHT, +/* 8 */ PALETTE_EGA_COLORS_LIGHT, +/* 16 */ PALETTE_EGA_COLORS_DARK, +/* 24 */ 0x8080FF, 0x802060, 0xFFFFC0, 0xA0E0E0, 0x600080, 0xFF8080, 0x0080C0, 0xC0C0FF, +/* 32 */ 0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 0x0000FF, +/* 40 */ 0x00CFFF, 0x69FFFF, 0xE0FFE0, 0xFFFF80, 0xA6CAF0, 0xDD9CB3, 0xB38FEE, 0xE3E3E3, +/* 48 */ 0x2A6FF9, 0x3FB8CD, 0x488436, 0x958C41, 0x8E5E42, 0xA0627A, 0x624FAC, 0x969696, +/* 56 */ 0x1D2FBE, 0x286676, 0x004500, 0x453E01, 0x6A2813, 0x85396A, 0x4A3285, 0x424242 +}; + +/** Default color table for BIFF8/OOX. */ +static const sal_Int32 spnDefColors8[] = +{ +/* 0 */ PALETTE_EGA_COLORS_LIGHT, +/* 8 */ PALETTE_EGA_COLORS_LIGHT, +/* 16 */ PALETTE_EGA_COLORS_DARK, +/* 24 */ 0x9999FF, 0x993366, 0xFFFFCC, 0xCCFFFF, 0x660066, 0xFF8080, 0x0066CC, 0xCCCCFF, +/* 32 */ 0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 0x0000FF, +/* 40 */ 0x00CCFF, 0xCCFFFF, 0xCCFFCC, 0xFFFF99, 0x99CCFF, 0xFF99CC, 0xCC99FF, 0xFFCC99, +/* 48 */ 0x3366FF, 0x33CCCC, 0x99CC00, 0xFFCC00, 0xFF9900, 0xFF6600, 0x666699, 0x969696, +/* 56 */ 0x003366, 0x339966, 0x003300, 0x333300, 0x993300, 0x993366, 0x333399, 0x333333 +}; + +#undef PALETTE_EGA_COLORS_LIGHT +#undef PALETTE_EGA_COLORS_DARK + +} // namespace + +// ---------------------------------------------------------------------------- + +ColorPalette::ColorPalette( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ) +{ + // default colors + switch( getFilterType() ) + { + case FILTER_OOX: + maColors.insert( maColors.begin(), spnDefColors8, STATIC_ARRAY_END( spnDefColors8 ) ); + mnAppendIndex = OOX_COLOR_USEROFFSET; + break; + case FILTER_BIFF: + switch( getBiff() ) + { + case BIFF2: maColors.insert( maColors.begin(), spnDefColors2, STATIC_ARRAY_END( spnDefColors2 ) ); break; + case BIFF3: + case BIFF4: maColors.insert( maColors.begin(), spnDefColors3, STATIC_ARRAY_END( spnDefColors3 ) ); break; + case BIFF5: maColors.insert( maColors.begin(), spnDefColors5, STATIC_ARRAY_END( spnDefColors5 ) ); break; + case BIFF8: maColors.insert( maColors.begin(), spnDefColors8, STATIC_ARRAY_END( spnDefColors8 ) ); break; + case BIFF_UNKNOWN: break; + } + mnAppendIndex = BIFF_COLOR_USEROFFSET; + break; + case FILTER_UNKNOWN: break; + } +} + +void ColorPalette::importPaletteColor( const AttributeList& rAttribs ) +{ + appendColor( rAttribs.getIntegerHex( XML_rgb, API_RGB_WHITE ) ); +} + +void ColorPalette::importPaletteColor( RecordInputStream& rStrm ) +{ + sal_Int32 nRgb = lclReadRgbColor( rStrm ); + appendColor( nRgb & 0xFFFFFF ); +} + +void ColorPalette::importPalette( BiffInputStream& rStrm ) +{ + sal_uInt16 nCount; + rStrm >> nCount; + OSL_ENSURE( rStrm.getRemaining() == 4 * nCount, "ColorPalette::importPalette - wrong palette size" ); + + // fill palette from BIFF_COLOR_USEROFFSET + mnAppendIndex = BIFF_COLOR_USEROFFSET; + for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex ) + { + sal_Int32 nRgb = lclReadRgbColor( rStrm ); + appendColor( nRgb & 0xFFFFFF ); + } +} + +sal_Int32 ColorPalette::getColor( sal_Int32 nPaletteIdx ) const +{ + sal_Int32 nColor = API_RGB_TRANSPARENT; + if( const sal_Int32* 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_ENSURE( false, "ColorPalette::getColor - unknown color index" ); + } + return nColor; +} + +void ColorPalette::appendColor( sal_Int32 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::setBinScheme( 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( ::com::sun::star::awt::FontFamily::DONTKNOW ), + mnTextEnc( RTL_TEXTENCODING_DONTKNOW ) +{ +} + +// ---------------------------------------------------------------------------- + +ApiFontData::ApiFontData() : + maDesc( + CREATE_OUSTRING( "Calibri" ), + 220, // height 11 points + 0, + OUString(), + ::com::sun::star::awt::FontFamily::DONTKNOW, + RTL_TEXTENCODING_DONTKNOW, + ::com::sun::star::awt::FontPitch::DONTKNOW, + 100.0, + ::com::sun::star::awt::FontWeight::NORMAL, + ::com::sun::star::awt::FontSlant_NONE, + ::com::sun::star::awt::FontUnderline::NONE, + ::com::sun::star::awt::FontStrikeout::NONE, + 0.0, + sal_False, + sal_False, + ::com::sun::star::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( RecordInputStream& rStrm ) +{ + OSL_ENSURE( !mbDxf, "Font::importFont - unexpected conditional formatting flag" ); + + sal_uInt16 nHeight, nFlags, nWeight, nEscapement; + sal_uInt8 nUnderline, nFamily, nCharSet, nScheme; + rStrm >> nHeight >> nFlags >> nWeight >> nEscapement >> nUnderline >> nFamily >> nCharSet; + rStrm.skip( 1 ); + rStrm >> maModel.maColor >> nScheme >> maModel.maName; + + // equal constants in BIFF and OOBIN for weight, underline, and escapement + maModel.setBinScheme( nScheme ); + maModel.setBiffHeight( nHeight ); + maModel.setBiffWeight( nWeight ); + maModel.setBiffUnderline( nUnderline ); + maModel.setBiffEscapement( nEscapement ); + maModel.mnFamily = nFamily; + maModel.mnCharSet = nCharSet; + // equal flags in BIFF and OOBIN + 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( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfName - missing conditional formatting flag" ); + maModel.maName = rStrm.readString( false ); + maUsedFlags.mbColorUsed = true; +} + +void Font::importDxfColor( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfColor - missing conditional formatting flag" ); + rStrm >> maModel.maColor; + maUsedFlags.mbColorUsed = true; +} + +void Font::importDxfScheme( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfScheme - missing conditional formatting flag" ); + maModel.setBinScheme( rStrm.readuInt8() ); + maUsedFlags.mbSchemeUsed = true; +} + +void Font::importDxfHeight( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfHeight - missing conditional formatting flag" ); + maModel.setBiffHeight( rStrm.readuInt16() ); + maUsedFlags.mbHeightUsed = true; +} + +void Font::importDxfWeight( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfWeight - missing conditional formatting flag" ); + maModel.setBiffWeight( rStrm.readuInt16() ); + maUsedFlags.mbWeightUsed = true; +} + +void Font::importDxfUnderline( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfUnderline - missing conditional formatting flag" ); + maModel.setBiffUnderline( rStrm.readuInt16() ); + maUsedFlags.mbUnderlineUsed = true; +} + +void Font::importDxfEscapement( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importDxfEscapement - missing conditional formatting flag" ); + maModel.setBiffEscapement( rStrm.readuInt16() ); + maUsedFlags.mbEscapementUsed = true; +} + +void Font::importDxfFlag( sal_Int32 nElement, RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "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_ENSURE( false, "Font::importDxfFlag - unexpected element identifier" ); + } +} + +void Font::importFont( BiffInputStream& rStrm ) +{ + OSL_ENSURE( !mbDxf, "Font::importFont - unexpected conditional formatting flag" ); + switch( getBiff() ) + { + case BIFF2: + importFontData2( rStrm ); + importFontName2( rStrm ); + break; + case BIFF3: + case BIFF4: + importFontData2( rStrm ); + importFontColor( rStrm ); + importFontName2( rStrm ); + break; + case BIFF5: + importFontData2( rStrm ); + importFontColor( rStrm ); + importFontData5( rStrm ); + importFontName2( rStrm ); + break; + case BIFF8: + importFontData2( rStrm ); + importFontColor( rStrm ); + importFontData5( rStrm ); + importFontName8( rStrm ); + break; + case BIFF_UNKNOWN: break; + } +} + +void Font::importFontColor( BiffInputStream& rStrm ) +{ + OSL_ENSURE( !mbDxf, "Font::importFontColor - unexpected conditional formatting flag" ); + maModel.maColor.importColorId( rStrm ); +} + +void Font::importCfRule( BiffInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Font::importCfRule - missing conditional formatting flag" ); + + sal_Int32 nHeight, nColor; + sal_uInt32 nStyle, nFontFlags1, nFontFlags2, nFontFlags3; + sal_uInt16 nWeight, nEscapement; + sal_uInt8 nUnderline; + + OSL_ENSURE( rStrm.getRemaining() >= 118, "Font::importCfRule - missing record data" ); + sal_Int64 nRecPos = rStrm.tell(); + maModel.maName = rStrm.readUniStringBody( rStrm.readuInt8() ); + maUsedFlags.mbNameUsed = maModel.maName.getLength() > 0; + OSL_ENSURE( !rStrm.isEof() && (rStrm.tell() <= nRecPos + 64), "Font::importCfRule - font name too long" ); + rStrm.seek( nRecPos + 64 ); + rStrm >> nHeight >> nStyle >> nWeight >> nEscapement >> nUnderline; + rStrm.skip( 3 ); + rStrm >> nColor; + rStrm.skip( 4 ); + rStrm >> nFontFlags1 >> nFontFlags2 >> nFontFlags3; + rStrm.skip( 18 ); + + if( (maUsedFlags.mbColorUsed = (0 <= nColor) && (nColor <= 0x7FFF)) == true ) + maModel.maColor.setIndexed( nColor ); + if( (maUsedFlags.mbHeightUsed = (0 < nHeight) && (nHeight <= 0x7FFF)) == true ) + maModel.setBiffHeight( static_cast< sal_uInt16 >( nHeight ) ); + if( (maUsedFlags.mbUnderlineUsed = !getFlag( nFontFlags3, BIFF_CFRULE_FONT_UNDERL )) == true ) + maModel.setBiffUnderline( nUnderline ); + if( (maUsedFlags.mbEscapementUsed = !getFlag( nFontFlags2, BIFF_CFRULE_FONT_ESCAPEM )) == true ) + maModel.setBiffEscapement( nEscapement ); + if( (maUsedFlags.mbWeightUsed = maUsedFlags.mbPostureUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_STYLE )) == true ) + { + maModel.setBiffWeight( nWeight ); + maModel.mbItalic = getFlag( nStyle, BIFF_CFRULE_FONT_STYLE ); + } + if( (maUsedFlags.mbStrikeoutUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_STRIKEOUT )) == true ) + maModel.mbStrikeout = getFlag( nStyle, BIFF_CFRULE_FONT_STRIKEOUT ); + if( (maUsedFlags.mbOutlineUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_OUTLINE )) == true ) + maModel.mbOutline = getFlag( nStyle, BIFF_CFRULE_FONT_OUTLINE ); + if( (maUsedFlags.mbShadowUsed = !getFlag( nFontFlags1, BIFF_CFRULE_FONT_SHADOW )) == true ) + maModel.mbShadow = getFlag( nStyle, BIFF_CFRULE_FONT_SHADOW ); +} + +rtl_TextEncoding Font::getFontEncoding() const +{ + // #i63105# cells use text encoding from FONT record character set + // #i67768# BIFF2-BIFF4 FONT records do not contain character set + // #i71033# do not use maApiData, this function is used before finalizeImport() + rtl_TextEncoding eFontEnc = RTL_TEXTENCODING_DONTKNOW; + if( (0 <= maModel.mnCharSet) && (maModel.mnCharSet <= SAL_MAX_UINT8) ) + eFontEnc = rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maModel.mnCharSet ) ); + return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? getTextEncoding() : eFontEnc; +} + +void Font::finalizeImport() +{ + namespace cssawt = ::com::sun::star::awt; + + // font name + maApiData.maDesc.Name = maModel.maName; + + // font family + switch( maModel.mnFamily ) + { + case OOX_FONTFAMILY_NONE: maApiData.maDesc.Family = cssawt::FontFamily::DONTKNOW; break; + case OOX_FONTFAMILY_ROMAN: maApiData.maDesc.Family = cssawt::FontFamily::ROMAN; break; + case OOX_FONTFAMILY_SWISS: maApiData.maDesc.Family = cssawt::FontFamily::SWISS; break; + case OOX_FONTFAMILY_MODERN: maApiData.maDesc.Family = cssawt::FontFamily::MODERN; break; + case OOX_FONTFAMILY_SCRIPT: maApiData.maDesc.Family = cssawt::FontFamily::SCRIPT; break; + case OOX_FONTFAMILY_DECORATIVE: maApiData.maDesc.Family = cssawt::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 ? cssawt::FontWeight::BOLD : cssawt::FontWeight::NORMAL; + maApiData.maDesc.Slant = maModel.mbItalic ? cssawt::FontSlant_ITALIC : cssawt::FontSlant_NONE; + maApiData.maDesc.Strikeout = maModel.mbStrikeout ? cssawt::FontStrikeout::SINGLE : cssawt::FontStrikeout::NONE; + maApiData.mbOutline = maModel.mbOutline; + maApiData.mbShadow = maModel.mbShadow; + + // underline + switch( maModel.mnUnderline ) + { + case XML_double: maApiData.maDesc.Underline = cssawt::FontUnderline::DOUBLE; break; + case XML_doubleAccounting: maApiData.maDesc.Underline = cssawt::FontUnderline::DOUBLE; break; + case XML_none: maApiData.maDesc.Underline = cssawt::FontUnderline::NONE; break; + case XML_single: maApiData.maDesc.Underline = cssawt::FontUnderline::SINGLE; break; + case XML_singleAccounting: maApiData.maDesc.Underline = cssawt::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 ) + { + Reference< XDevice > xDevice = getReferenceDevice(); + if( xDevice.is() ) + { + Reference< XFont2 > xFont( xDevice->getFont( maApiData.maDesc ), UNO_QUERY ); + if( xFont.is() ) + { + // #91658# CJK fonts + bool bHasAsian = + xFont->hasGlyphs( OUString( sal_Unicode( 0x3041 ) ) ) || // 3040-309F: Hiragana + xFont->hasGlyphs( OUString( sal_Unicode( 0x30A1 ) ) ) || // 30A0-30FF: Katakana + xFont->hasGlyphs( OUString( sal_Unicode( 0x3111 ) ) ) || // 3100-312F: Bopomofo + xFont->hasGlyphs( OUString( sal_Unicode( 0x3131 ) ) ) || // 3130-318F: Hangul Compatibility Jamo + xFont->hasGlyphs( OUString( sal_Unicode( 0x3301 ) ) ) || // 3300-33FF: CJK Compatibility + xFont->hasGlyphs( OUString( sal_Unicode( 0x3401 ) ) ) || // 3400-4DBF: CJK Unified Ideographs Extension A + xFont->hasGlyphs( OUString( sal_Unicode( 0x4E01 ) ) ) || // 4E00-9FAF: CJK Unified Ideographs + xFont->hasGlyphs( OUString( sal_Unicode( 0x7E01 ) ) ) || // 4E00-9FAF: CJK unified ideographs + xFont->hasGlyphs( OUString( sal_Unicode( 0xA001 ) ) ) || // A001-A48F: Yi Syllables + xFont->hasGlyphs( OUString( sal_Unicode( 0xAC01 ) ) ) || // AC00-D7AF: Hangul Syllables + xFont->hasGlyphs( OUString( sal_Unicode( 0xCC01 ) ) ) || // AC00-D7AF: Hangul Syllables + xFont->hasGlyphs( OUString( sal_Unicode( 0xF901 ) ) ) || // F900-FAFF: CJK Compatibility Ideographs + xFont->hasGlyphs( OUString( sal_Unicode( 0xFF71 ) ) ); // FF00-FFEF: Halfwidth/Fullwidth Forms + // #113783# CTL fonts + bool bHasCmplx = + xFont->hasGlyphs( OUString( sal_Unicode( 0x05D1 ) ) ) || // 0590-05FF: Hebrew + xFont->hasGlyphs( OUString( sal_Unicode( 0x0631 ) ) ) || // 0600-06FF: Arabic + xFont->hasGlyphs( OUString( sal_Unicode( 0x0721 ) ) ) || // 0700-074F: Syriac + xFont->hasGlyphs( OUString( sal_Unicode( 0x0911 ) ) ) || // 0900-0DFF: Indic scripts + xFont->hasGlyphs( OUString( sal_Unicode( 0x0E01 ) ) ) || // 0E00-0E7F: Thai + xFont->hasGlyphs( OUString( sal_Unicode( 0xFB21 ) ) ) || // FB1D-FB4F: Hebrew Presentation Forms + xFont->hasGlyphs( OUString( sal_Unicode( 0xFB51 ) ) ) || // FB50-FDFF: Arabic Presentation Forms-A + xFont->hasGlyphs( OUString( sal_Unicode( 0xFE71 ) ) ); // FE70-FEFF: Arabic Presentation Forms-B + // Western fonts + bool bHasLatin = + (!bHasAsian && !bHasCmplx) || + xFont->hasGlyphs( OUString( sal_Unicode( 'A' ) ) ); + + lclSetFontName( maApiData.maLatinFont, maApiData.maDesc, bHasLatin ); + lclSetFontName( maApiData.maAsianFont, maApiData.maDesc, bHasAsian ); + lclSetFontName( maApiData.maCmplxFont, maApiData.maDesc, bHasCmplx ); + } + } + } +} + +const FontDescriptor& Font::getFontDescriptor() const +{ + return maApiData.maDesc; +} + +bool Font::needsRichTextFormat() const +{ + return maApiData.mnEscapement != API_ESCAPE_NONE; +} + +void Font::writeToPropertyMap( PropertyMap& rPropMap, FontPropertyType ePropType ) const +{ + // font name properties + if( maUsedFlags.mbNameUsed ) + { + if( maApiData.maLatinFont.maName.getLength() > 0 ) + { + rPropMap[ PROP_CharFontName ] <<= maApiData.maLatinFont.maName; + rPropMap[ PROP_CharFontFamily ] <<= maApiData.maLatinFont.mnFamily; + rPropMap[ PROP_CharFontCharSet ] <<= maApiData.maLatinFont.mnTextEnc; + } + if( maApiData.maAsianFont.maName.getLength() > 0 ) + { + rPropMap[ PROP_CharFontNameAsian ] <<= maApiData.maAsianFont.maName; + rPropMap[ PROP_CharFontFamilyAsian ] <<= maApiData.maAsianFont.mnFamily; + rPropMap[ PROP_CharFontCharSetAsian ] <<= maApiData.maAsianFont.mnTextEnc; + } + if( maApiData.maCmplxFont.maName.getLength() > 0 ) + { + rPropMap[ PROP_CharFontNameComplex ] <<= maApiData.maCmplxFont.maName; + rPropMap[ PROP_CharFontFamilyComplex ] <<= maApiData.maCmplxFont.mnFamily; + rPropMap[ PROP_CharFontCharSetComplex ] <<= maApiData.maCmplxFont.mnTextEnc; + } + } + // font height + if( maUsedFlags.mbHeightUsed ) + { + float fHeight = static_cast< float >( maApiData.maDesc.Height / 20.0 ); // twips to points + rPropMap[ PROP_CharHeight ] <<= fHeight; + rPropMap[ PROP_CharHeightAsian ] <<= fHeight; + rPropMap[ PROP_CharHeightComplex ] <<= fHeight; + } + // font weight + if( maUsedFlags.mbWeightUsed ) + { + float fWeight = maApiData.maDesc.Weight; + rPropMap[ PROP_CharWeight ] <<= fWeight; + rPropMap[ PROP_CharWeightAsian ] <<= fWeight; + rPropMap[ PROP_CharWeightComplex ] <<= fWeight; + } + // font posture + if( maUsedFlags.mbPostureUsed ) + { + rPropMap[ PROP_CharPosture ] <<= maApiData.maDesc.Slant; + rPropMap[ PROP_CharPostureAsian ] <<= maApiData.maDesc.Slant; + rPropMap[ PROP_CharPostureComplex ] <<= maApiData.maDesc.Slant; + } + // character color + if( maUsedFlags.mbColorUsed ) + rPropMap[ PROP_CharColor ] <<= maApiData.mnColor; + // underline style + if( maUsedFlags.mbUnderlineUsed ) + rPropMap[ PROP_CharUnderline ] <<= maApiData.maDesc.Underline; + // strike out style + if( maUsedFlags.mbStrikeoutUsed ) + rPropMap[ PROP_CharStrikeout ] <<= maApiData.maDesc.Strikeout; + // outline style + if( maUsedFlags.mbOutlineUsed ) + rPropMap[ PROP_CharContoured ] <<= maApiData.mbOutline; + // shadow style + if( maUsedFlags.mbShadowUsed ) + rPropMap[ PROP_CharShadowed ] <<= maApiData.mbShadow; + // escapement + if( maUsedFlags.mbEscapementUsed && (ePropType == FONT_PROPTYPE_TEXT) ) + { + rPropMap[ PROP_CharEscapement ] <<= maApiData.mnEscapement; + rPropMap[ PROP_CharEscapementHeight ] <<= maApiData.mnEscapeHeight; + } +} + +void Font::writeToPropertySet( PropertySet& rPropSet, FontPropertyType ePropType ) const +{ + PropertyMap aPropMap; + writeToPropertyMap( aPropMap, ePropType ); + rPropSet.setProperties( aPropMap ); +} + +void Font::importFontData2( BiffInputStream& rStrm ) +{ + sal_uInt16 nHeight, nFlags; + rStrm >> nHeight >> nFlags; + + maModel.setBiffHeight( nHeight ); + maModel.mnFamily = OOX_FONTFAMILY_NONE; + maModel.mnCharSet = -1; // ensure to not use font charset in byte string import + maModel.mnUnderline = getFlagValue( nFlags, BIFF_FONTFLAG_UNDERLINE, XML_single, XML_none ); + maModel.mnEscapement = XML_none; + maModel.mbBold = getFlag( nFlags, BIFF_FONTFLAG_BOLD ); + 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::importFontData5( BiffInputStream& rStrm ) +{ + sal_uInt16 nWeight, nEscapement; + sal_uInt8 nUnderline, nFamily, nCharSet; + rStrm >> nWeight >> nEscapement >> nUnderline >> nFamily >> nCharSet; + rStrm.skip( 1 ); + + maModel.setBiffWeight( nWeight ); + maModel.setBiffUnderline( nUnderline ); + maModel.setBiffEscapement( nEscapement ); + // equal constants in XML and BIFF for family and charset + maModel.mnFamily = nFamily; + maModel.mnCharSet = nCharSet; +} + +void Font::importFontName2( BiffInputStream& rStrm ) +{ + maModel.maName = rStrm.readByteStringUC( false, getTextEncoding() ); +} + +void Font::importFontName8( BiffInputStream& rStrm ) +{ + maModel.maName = rStrm.readUniStringBody( rStrm.readuInt8() ); +} + +// ============================================================================ + +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::setBinHorAlign( 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::setBinVerAlign( 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 ); +} + +void AlignmentModel::setBinTextOrient( sal_uInt8 nTextOrient ) +{ + static const sal_Int32 spnRotations[] = { + OOX_XF_ROTATION_NONE, OOX_XF_ROTATION_STACKED, + OOX_XF_ROTATION_90CCW, OOX_XF_ROTATION_90CW }; + mnRotation = STATIC_ARRAY_SELECT( spnRotations, nTextOrient, OOX_XF_ROTATION_NONE ); +} + +// ---------------------------------------------------------------------------- + +ApiAlignmentData::ApiAlignmentData() : + meHorJustify( ::com::sun::star::table::CellHoriJustify_STANDARD ), + meVerJustify( ::com::sun::star::table::CellVertJustify_STANDARD ), + meOrientation( ::com::sun::star::table::CellOrientation_STANDARD ), + mnRotation( 0 ), + mnWritingMode( ::com::sun::star::text::WritingMode2::PAGE ), + mnIndent( 0 ), + mbWrapText( false ), + mbShrink( false ) +{ +} + +bool operator==( const ApiAlignmentData& rLeft, const ApiAlignmentData& rRight ) +{ + return + (rLeft.meHorJustify == rRight.meHorJustify) && + (rLeft.meVerJustify == rRight.meVerJustify) && + (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.mnHorAlign = rAttribs.getToken( XML_horizontal, XML_general ); + 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 ); + 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::setBinData( sal_uInt32 nFlags ) +{ + maModel.setBinHorAlign( extractValue< sal_uInt8 >( nFlags, 16, 3 ) ); + maModel.setBinVerAlign( 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, OOBIN_XF_WRAPTEXT ); + maModel.mbShrink = getFlag( nFlags, OOBIN_XF_SHRINK ); + maModel.mbJustLastLine = getFlag( nFlags, OOBIN_XF_JUSTLASTLINE ); +} + +void Alignment::setBiff2Data( sal_uInt8 nFlags ) +{ + maModel.setBinHorAlign( extractValue< sal_uInt8 >( nFlags, 0, 3 ) ); +} + +void Alignment::setBiff3Data( sal_uInt16 nAlign ) +{ + maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) ); + maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); // new in BIFF3 +} + +void Alignment::setBiff4Data( sal_uInt16 nAlign ) +{ + maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) ); + maModel.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 2 ) ); // new in BIFF4 + maModel.setBinTextOrient( extractValue< sal_uInt8 >( nAlign, 6, 2 ) ); // new in BIFF4 + maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); +} + +void Alignment::setBiff5Data( sal_uInt16 nAlign ) +{ + maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) ); + maModel.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) ); + maModel.setBinTextOrient( extractValue< sal_uInt8 >( nAlign, 8, 2 ) ); + maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); +} + +void Alignment::setBiff8Data( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib ) +{ + maModel.setBinHorAlign( extractValue< sal_uInt8 >( nAlign, 0, 3 ) ); + maModel.setBinVerAlign( extractValue< sal_uInt8 >( nAlign, 4, 3 ) ); + maModel.mnTextDir = extractValue< sal_Int32 >( nMiscAttrib, 6, 2 ); // new in BIFF8 + maModel.mnRotation = extractValue< sal_Int32 >( nAlign, 8, 8 ); // new in BIFF8 + maModel.mnIndent = extractValue< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8 + maModel.mbWrapText = getFlag( nAlign, BIFF_XF_WRAPTEXT ); + maModel.mbShrink = getFlag( nMiscAttrib, BIFF_XF_SHRINK ); // new in BIFF8 + maModel.mbJustLastLine = getFlag( nAlign, BIFF_XF_JUSTLASTLINE ); // new in BIFF8(?) +} + +void Alignment::finalizeImport() +{ + namespace csstab = ::com::sun::star::table; + namespace csstxt = ::com::sun::star::text; + + // horizontal alignment + switch( maModel.mnHorAlign ) + { + case XML_center: maApiData.meHorJustify = csstab::CellHoriJustify_CENTER; break; + case XML_centerContinuous: maApiData.meHorJustify = csstab::CellHoriJustify_CENTER; break; + case XML_distributed: maApiData.meHorJustify = csstab::CellHoriJustify_BLOCK; break; + case XML_fill: maApiData.meHorJustify = csstab::CellHoriJustify_REPEAT; break; + case XML_general: maApiData.meHorJustify = csstab::CellHoriJustify_STANDARD; break; + case XML_justify: maApiData.meHorJustify = csstab::CellHoriJustify_BLOCK; break; + case XML_left: maApiData.meHorJustify = csstab::CellHoriJustify_LEFT; break; + case XML_right: maApiData.meHorJustify = csstab::CellHoriJustify_RIGHT; break; + } + + // vertical alignment + switch( maModel.mnVerAlign ) + { + case XML_bottom: maApiData.meVerJustify = csstab::CellVertJustify_BOTTOM; break; + case XML_center: maApiData.meVerJustify = csstab::CellVertJustify_CENTER; break; + case XML_distributed: maApiData.meVerJustify = csstab::CellVertJustify_TOP; break; + case XML_justify: maApiData.meVerJustify = csstab::CellVertJustify_TOP; break; + case XML_top: maApiData.meVerJustify = csstab::CellVertJustify_TOP; break; + } + + /* indentation: expressed as number of blocks of 3 space characters in + OOX, and as multiple of 10 points in BIFF. */ + sal_Int32 nIndent = 0; + switch( getFilterType() ) + { + case FILTER_OOX: nIndent = getUnitConverter().scaleToMm100( 3.0 * maModel.mnIndent, UNIT_SPACE ); break; + case FILTER_BIFF: nIndent = getUnitConverter().scaleToMm100( 10.0 * maModel.mnIndent, UNIT_POINT ); break; + case FILTER_UNKNOWN: break; + } + 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 = csstxt::WritingMode2::PAGE; break; + case OOX_XF_TEXTDIR_LTR: maApiData.mnWritingMode = csstxt::WritingMode2::LR_TB; break; + case OOX_XF_TEXTDIR_RTL: maApiData.mnWritingMode = csstxt::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 = ((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) ? + csstab::CellOrientation_STACKED : csstab::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; + +} + +void Alignment::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + rPropMap[ PROP_HoriJustify ] <<= maApiData.meHorJustify; + rPropMap[ PROP_VertJustify ] <<= maApiData.meVerJustify; + rPropMap[ PROP_WritingMode ] <<= maApiData.mnWritingMode; + rPropMap[ PROP_RotateAngle ] <<= maApiData.mnRotation; + rPropMap[ PROP_Orientation ] <<= maApiData.meOrientation; + rPropMap[ PROP_ParaIndent ] <<= maApiData.mnIndent; + rPropMap[ PROP_IsTextWrapped ] <<= maApiData.mbWrapText; + rPropMap[ PROP_ShrinkToFit ] <<= maApiData.mbShrink; +} + +// ============================================================================ + +ProtectionModel::ProtectionModel() : + mbLocked( true ), // default in Excel and Calc + mbHidden( false ) +{ +} + +// ---------------------------------------------------------------------------- + +ApiProtectionData::ApiProtectionData() : + maCellProt( sal_True, sal_False, sal_False, sal_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::setBinData( sal_uInt32 nFlags ) +{ + maModel.mbLocked = getFlag( nFlags, OOBIN_XF_LOCKED ); + maModel.mbHidden = getFlag( nFlags, OOBIN_XF_HIDDEN ); +} + +void Protection::setBiff2Data( sal_uInt8 nNumFmt ) +{ + maModel.mbLocked = getFlag( nNumFmt, BIFF2_XF_LOCKED ); + maModel.mbHidden = getFlag( nNumFmt, BIFF2_XF_HIDDEN ); +} + +void Protection::setBiff3Data( sal_uInt16 nProt ) +{ + maModel.mbLocked = getFlag( nProt, BIFF_XF_LOCKED ); + maModel.mbHidden = getFlag( nProt, BIFF_XF_HIDDEN ); +} + +void Protection::finalizeImport() +{ + maApiData.maCellProt.IsLocked = maModel.mbLocked; + maApiData.maCellProt.IsFormulaHidden = maModel.mbHidden; +} + +void Protection::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + rPropMap[ PROP_CellProtection ] <<= maApiData.maCellProt; +} + +// ============================================================================ + +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 ); +} + +void BorderLineModel::setBiffData( sal_uInt8 nLineStyle, sal_uInt16 nLineColor ) +{ + maColor.setIndexed( nLineColor ); + setBiffStyle( nLineStyle ); +} + +// ---------------------------------------------------------------------------- + +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 + (maBorder.IsTopLineValid && (maBorder.TopLine.OuterLineWidth > 0)) || + (maBorder.IsBottomLineValid && (maBorder.BottomLine.OuterLineWidth > 0)) || + (maBorder.IsLeftLineValid && (maBorder.LeftLine.OuterLineWidth > 0)) || + (maBorder.IsRightLineValid && (maBorder.RightLine.OuterLineWidth > 0)); +} + +namespace { + +bool operator==( const BorderLine& rLeft, const BorderLine& rRight ) +{ + return + (rLeft.Color == rRight.Color) && + (rLeft.InnerLineWidth == rRight.InnerLineWidth) && + (rLeft.OuterLineWidth == rRight.OuterLineWidth) && + (rLeft.LineDistance == rRight.LineDistance); +} + +bool operator==( const TableBorder& rLeft, const TableBorder& rRight ) +{ + return + (rLeft.TopLine == rRight.TopLine) && + (rLeft.IsTopLineValid == rRight.IsTopLineValid) && + (rLeft.BottomLine == rRight.BottomLine) && + (rLeft.IsBottomLineValid == rRight.IsBottomLineValid) && + (rLeft.LeftLine == rRight.LeftLine) && + (rLeft.IsLeftLineValid == rRight.IsLeftLineValid) && + (rLeft.RightLine == rRight.RightLine) && + (rLeft.IsRightLineValid == rRight.IsRightLineValid) && + (rLeft.HorizontalLine == rRight.HorizontalLine) && + (rLeft.IsHorizontalLineValid == rRight.IsHorizontalLineValid) && + (rLeft.VerticalLine == rRight.VerticalLine) && + (rLeft.IsVerticalLineValid == rRight.IsVerticalLineValid) && + (rLeft.Distance == rRight.Distance) && + (rLeft.IsDistanceValid == rRight.IsDistanceValid); +} + +} // namespace + +bool operator==( const ApiBorderData& rLeft, const ApiBorderData& rRight ) +{ + return + (rLeft.maBorder == rRight.maBorder) && + (rLeft.maTLtoBR == rRight.maTLtoBR) && + (rLeft.maBLtoTR == rRight.maBLtoTR) && + (rLeft.mbBorderUsed == rRight.mbBorderUsed) && + (rLeft.mbDiagUsed == rRight.mbDiagUsed); +} + +// ============================================================================ + +namespace { + +inline 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; +} + +inline sal_Int32 lclGetBorderLineWidth( const BorderLine& rBorderLine ) +{ + return rBorderLine.OuterLineWidth + rBorderLine.LineDistance + rBorderLine.InnerLineWidth; +} + +const BorderLine* lclGetThickerLine( const BorderLine& rBorderLine1, sal_Bool bValid1, const BorderLine& rBorderLine2, sal_Bool bValid2 ) +{ + if( bValid1 && bValid2 ) + return (lclGetBorderLineWidth( rBorderLine1 ) < lclGetBorderLineWidth( rBorderLine2 )) ? &rBorderLine2 : &rBorderLine1; + if( bValid1 ) + return &rBorderLine1; + if( bValid2 ) + return &rBorderLine2; + return 0; +} + +} // 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( RecordInputStream& rStrm ) +{ + sal_uInt8 nFlags = rStrm.readuInt8(); + maModel.mbDiagTLtoBR = getFlag( nFlags, OOBIN_BORDER_DIAG_TLBR ); + maModel.mbDiagBLtoTR = getFlag( nFlags, OOBIN_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, RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Border::importDxfBorder - missing conditional formatting flag" ); + if( BorderLineModel* pBorderLine = getBorderLine( nElement ) ) + { + sal_uInt16 nStyle; + rStrm >> pBorderLine->maColor >> nStyle; + pBorderLine->setBiffStyle( nStyle ); + pBorderLine->mbUsed = true; + } +} + +void Border::setBiff2Data( sal_uInt8 nFlags ) +{ + OSL_ENSURE( !mbDxf, "Border::setBiff2Data - unexpected conditional formatting flag" ); + maModel.maLeft.setBiffData( getFlagValue( nFlags, BIFF2_XF_LEFTLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK ); + maModel.maRight.setBiffData( getFlagValue( nFlags, BIFF2_XF_RIGHTLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK ); + maModel.maTop.setBiffData( getFlagValue( nFlags, BIFF2_XF_TOPLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK ); + maModel.maBottom.setBiffData( getFlagValue( nFlags, BIFF2_XF_BOTTOMLINE, BIFF_LINE_THIN, BIFF_LINE_NONE ), BIFF2_COLOR_BLACK ); + maModel.maDiagonal.mbUsed = false; +} + +void Border::setBiff3Data( sal_uInt32 nBorder ) +{ + OSL_ENSURE( !mbDxf, "Border::setBiff3Data - unexpected conditional formatting flag" ); + maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder, 8, 3 ), extractValue< sal_uInt16 >( nBorder, 11, 5 ) ); + maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder, 24, 3 ), extractValue< sal_uInt16 >( nBorder, 27, 5 ) ); + maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder, 0, 3 ), extractValue< sal_uInt16 >( nBorder, 3, 5 ) ); + maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nBorder, 16, 3 ), extractValue< sal_uInt16 >( nBorder, 19, 5 ) ); + maModel.maDiagonal.mbUsed = false; +} + +void Border::setBiff5Data( sal_uInt32 nBorder, sal_uInt32 nArea ) +{ + OSL_ENSURE( !mbDxf, "Border::setBiff5Data - unexpected conditional formatting flag" ); + maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder, 3, 3 ), extractValue< sal_uInt16 >( nBorder, 16, 7 ) ); + maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder, 6, 3 ), extractValue< sal_uInt16 >( nBorder, 23, 7 ) ); + maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder, 0, 3 ), extractValue< sal_uInt16 >( nBorder, 9, 7 ) ); + maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nArea, 22, 3 ), extractValue< sal_uInt16 >( nArea, 25, 7 ) ); + maModel.maDiagonal.mbUsed = false; +} + +void Border::setBiff8Data( sal_uInt32 nBorder1, sal_uInt32 nBorder2 ) +{ + OSL_ENSURE( !mbDxf, "Border::setBiff8Data - unexpected conditional formatting flag" ); + maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nBorder1, 0, 4 ), extractValue< sal_uInt16 >( nBorder1, 16, 7 ) ); + maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nBorder1, 4, 4 ), extractValue< sal_uInt16 >( nBorder1, 23, 7 ) ); + maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nBorder1, 8, 4 ), extractValue< sal_uInt16 >( nBorder2, 0, 7 ) ); + maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nBorder1, 12, 4 ), extractValue< sal_uInt16 >( nBorder2, 7, 7 ) ); + maModel.mbDiagTLtoBR = getFlag( nBorder1, BIFF_XF_DIAG_TLBR ); + maModel.mbDiagBLtoTR = getFlag( nBorder1, BIFF_XF_DIAG_BLTR ); + if( maModel.mbDiagTLtoBR || maModel.mbDiagBLtoTR ) + maModel.maDiagonal.setBiffData( extractValue< sal_uInt8 >( nBorder2, 21, 4 ), extractValue< sal_uInt16 >( nBorder2, 14, 7 ) ); +} + +void Border::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags ) +{ + OSL_ENSURE( mbDxf, "Border::importCfRule - missing conditional formatting flag" ); + OSL_ENSURE( getFlag( nFlags, BIFF_CFRULE_BORDERBLOCK ), "Border::importCfRule - missing border block flag" ); + sal_uInt16 nStyle; + sal_uInt32 nColor; + rStrm >> nStyle >> nColor; + rStrm.skip( 2 ); + maModel.maLeft.setBiffData( extractValue< sal_uInt8 >( nStyle, 0, 4 ), extractValue< sal_uInt16 >( nColor, 0, 7 ) ); + maModel.maRight.setBiffData( extractValue< sal_uInt8 >( nStyle, 4, 4 ), extractValue< sal_uInt16 >( nColor, 7, 7 ) ); + maModel.maTop.setBiffData( extractValue< sal_uInt8 >( nStyle, 8, 4 ), extractValue< sal_uInt16 >( nColor, 16, 7 ) ); + maModel.maBottom.setBiffData( extractValue< sal_uInt8 >( nStyle, 12, 4 ), extractValue< sal_uInt16 >( nColor, 23, 7 ) ); + maModel.maLeft.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_LEFT ); + maModel.maRight.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_RIGHT ); + maModel.maTop.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_TOP ); + maModel.maBottom.mbUsed = !getFlag( nFlags, BIFF_CFRULE_BORDER_BOTTOM ); +} + +void Border::finalizeImport() +{ + maApiData.mbBorderUsed = maModel.maLeft.mbUsed || maModel.maRight.mbUsed || maModel.maTop.mbUsed || maModel.maBottom.mbUsed; + maApiData.mbDiagUsed = maModel.maDiagonal.mbUsed; + + maApiData.maBorder.IsLeftLineValid = convertBorderLine( maApiData.maBorder.LeftLine, maModel.maLeft ); + maApiData.maBorder.IsRightLineValid = convertBorderLine( maApiData.maBorder.RightLine, maModel.maRight ); + maApiData.maBorder.IsTopLineValid = convertBorderLine( maApiData.maBorder.TopLine, maModel.maTop ); + maApiData.maBorder.IsBottomLineValid = convertBorderLine( maApiData.maBorder.BottomLine, maModel.maBottom ); + + if( !mbDxf ) + { + maApiData.maBorder.IsVerticalLineValid = maApiData.maBorder.IsLeftLineValid || maApiData.maBorder.IsRightLineValid; + if( const BorderLine* pVertLine = lclGetThickerLine( maApiData.maBorder.LeftLine, maApiData.maBorder.IsLeftLineValid, maApiData.maBorder.RightLine, maApiData.maBorder.IsRightLineValid ) ) + maApiData.maBorder.VerticalLine = *pVertLine; + + maApiData.maBorder.IsHorizontalLineValid = maApiData.maBorder.IsTopLineValid || maApiData.maBorder.IsBottomLineValid; + if( const BorderLine* pHorLine = lclGetThickerLine( maApiData.maBorder.TopLine, maApiData.maBorder.IsTopLineValid, maApiData.maBorder.BottomLine, maApiData.maBorder.IsBottomLineValid ) ) + maApiData.maBorder.HorizontalLine = *pHorLine; + } + + if( maModel.mbDiagTLtoBR ) + convertBorderLine( maApiData.maTLtoBR, maModel.maDiagonal ); + if( maModel.mbDiagBLtoTR ) + convertBorderLine( maApiData.maBLtoTR, maModel.maDiagonal ); +} + +void Border::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + if( maApiData.mbBorderUsed ) + rPropMap[ PROP_TableBorder ] <<= maApiData.maBorder; + if( maApiData.mbDiagUsed ) + { + rPropMap[ PROP_DiagonalTLBR ] <<= maApiData.maTLtoBR; + rPropMap[ PROP_DiagonalBLTR ] <<= maApiData.maBLtoTR; + } +} + +BorderLineModel* Border::getBorderLine( sal_Int32 nElement ) +{ + switch( nElement ) + { + case XLS_TOKEN( left ): return &maModel.maLeft; + case XLS_TOKEN( right ): 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 0; +} + +bool Border::convertBorderLine( BorderLine& rBorderLine, const BorderLineModel& rModel ) +{ + rBorderLine.Color = rModel.maColor.getColor( getBaseFilter().getGraphicHelper(), API_RGB_BLACK ); + switch( rModel.mnStyle ) + { + case XML_dashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; + case XML_dashDotDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; + case XML_dashed: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; + case XML_dotted: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; + case XML_double: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN, API_LINE_THIN, API_LINE_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 ); break; + case XML_mediumDashDotDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; + case XML_mediumDashed: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; + case XML_none: lclSetBorderLineWidth( rBorderLine, API_LINE_NONE ); break; + case XML_slantDashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); 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 ); + maFillColor.setIndexed( OOX_COLOR_WINDOWBACK ); +} + +void PatternFillModel::setBinPattern( 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 ); +} + +void PatternFillModel::setBiffData( sal_uInt16 nPatternColor, sal_uInt16 nFillColor, sal_uInt8 nPattern ) +{ + maPatternColor.setIndexed( nPatternColor ); + maFillColor.setIndexed( nFillColor ); + // patterns equal in BIFF and OOBIN + setBinPattern( nPattern ); +} + +// ---------------------------------------------------------------------------- + +GradientFillModel::GradientFillModel() : + mnType( XML_linear ), + mfAngle( 0.0 ), + mfLeft( 0.0 ), + mfRight( 0.0 ), + mfTop( 0.0 ), + mfBottom( 0.0 ) +{ +} + +void GradientFillModel::readGradient( RecordInputStream& rStrm ) +{ + sal_Int32 nType; + rStrm >> nType >> mfAngle >> mfLeft >> mfRight >> mfTop >> mfBottom; + static const sal_Int32 spnTypes[] = { XML_linear, XML_path }; + mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID ); +} + +void GradientFillModel::readGradientStop( RecordInputStream& rStrm, bool bDxf ) +{ + Color aColor; + double fPosition; + if( bDxf ) + { + rStrm.skip( 2 ); + rStrm >> fPosition >> aColor; + } + else + { + rStrm >> aColor >> fPosition; + } + if( !rStrm.isEof() && (fPosition >= 0.0) ) + maColors[ fPosition ] = aColor; +} + +// ---------------------------------------------------------------------------- + +ApiSolidFillData::ApiSolidFillData() : + mnColor( API_RGB_TRANSPARENT ), + mbTransparent( true ), + mbUsed( false ) +{ +} + +bool operator==( const ApiSolidFillData& rLeft, const ApiSolidFillData& rRight ) +{ + return + (rLeft.mnColor == rRight.mnColor) && + (rLeft.mbTransparent == rRight.mbTransparent) && + (rLeft.mbUsed == rRight.mbUsed); +} + +// ============================================================================ + +namespace { + +inline sal_Int32 lclGetMixedColorComp( sal_Int32 nPatt, sal_Int32 nFill, sal_Int32 nAlpha ) +{ + return ((nPatt - nFill) * nAlpha) / 0x80 + nFill; +} + +sal_Int32 lclGetMixedColor( sal_Int32 nPattColor, sal_Int32 nFillColor, sal_Int32 nAlpha ) +{ + return + (lclGetMixedColorComp( nPattColor & 0xFF0000, nFillColor & 0xFF0000, nAlpha ) & 0xFF0000) | + (lclGetMixedColorComp( nPattColor & 0x00FF00, nFillColor & 0x00FF00, nAlpha ) & 0x00FF00) | + (lclGetMixedColorComp( nPattColor & 0x0000FF, nFillColor & 0x0000FF, nAlpha ) & 0x0000FF); +} + +} // namespace + +// ---------------------------------------------------------------------------- + +Fill::Fill( const WorkbookHelper& rHelper, bool bDxf ) : + WorkbookHelper( rHelper ), + mbDxf( bDxf ) +{ +} + +void Fill::importPatternFill( const AttributeList& rAttribs ) +{ + mxPatternModel.reset( new 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.get(), "Fill::importFgColor - missing pattern data" ); + if( mxPatternModel.get() ) + { + mxPatternModel->maPatternColor.importColor( rAttribs ); + mxPatternModel->mbPattColorUsed = true; + } +} + +void Fill::importBgColor( const AttributeList& rAttribs ) +{ + OSL_ENSURE( mxPatternModel.get(), "Fill::importBgColor - missing pattern data" ); + if( mxPatternModel.get() ) + { + mxPatternModel->maFillColor.importColor( rAttribs ); + mxPatternModel->mbFillColorUsed = true; + } +} + +void Fill::importGradientFill( const AttributeList& rAttribs ) +{ + mxGradientModel.reset( new 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.get(), "Fill::importColor - missing gradient data" ); + if( mxGradientModel.get() && (fPosition >= 0.0) ) + mxGradientModel->maColors[ fPosition ].importColor( rAttribs ); +} + +void Fill::importFill( RecordInputStream& rStrm ) +{ + OSL_ENSURE( !mbDxf, "Fill::importFill - unexpected conditional formatting flag" ); + sal_Int32 nPattern = rStrm.readInt32(); + if( nPattern == OOBIN_FILL_GRADIENT ) + { + mxGradientModel.reset( new GradientFillModel ); + sal_Int32 nStopCount; + rStrm.skip( 16 ); + mxGradientModel->readGradient( rStrm ); + rStrm >> nStopCount; + for( sal_Int32 nStop = 0; (nStop < nStopCount) && !rStrm.isEof(); ++nStop ) + mxGradientModel->readGradientStop( rStrm, false ); + } + else + { + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->setBinPattern( nPattern ); + rStrm >> mxPatternModel->maPatternColor >> mxPatternModel->maFillColor; + } +} + +void Fill::importDxfPattern( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Fill::importDxfPattern - missing conditional formatting flag" ); + if( !mxPatternModel ) + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->setBinPattern( rStrm.readuInt8() ); + mxPatternModel->mbPatternUsed = true; +} + +void Fill::importDxfFgColor( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Fill::importDxfFgColor - missing conditional formatting flag" ); + if( !mxPatternModel ) + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->maPatternColor.importColor( rStrm ); + mxPatternModel->mbPattColorUsed = true; +} + +void Fill::importDxfBgColor( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Fill::importDxfBgColor - missing conditional formatting flag" ); + if( !mxPatternModel ) + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->maFillColor.importColor( rStrm ); + mxPatternModel->mbFillColorUsed = true; +} + +void Fill::importDxfGradient( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Fill::importDxfGradient - missing conditional formatting flag" ); + if( !mxGradientModel ) + mxGradientModel.reset( new GradientFillModel ); + mxGradientModel->readGradient( rStrm ); +} + +void Fill::importDxfStop( RecordInputStream& rStrm ) +{ + OSL_ENSURE( mbDxf, "Fill::importDxfStop - missing conditional formatting flag" ); + if( !mxGradientModel ) + mxGradientModel.reset( new GradientFillModel ); + mxGradientModel->readGradientStop( rStrm, true ); +} + +void Fill::setBiff2Data( sal_uInt8 nFlags ) +{ + OSL_ENSURE( !mbDxf, "Fill::setBiff2Data - unexpected conditional formatting flag" ); + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->setBiffData( + BIFF2_COLOR_BLACK, + BIFF2_COLOR_WHITE, + getFlagValue( nFlags, BIFF2_XF_BACKGROUND, BIFF_PATT_125, BIFF_PATT_NONE ) ); +} + +void Fill::setBiff3Data( sal_uInt16 nArea ) +{ + OSL_ENSURE( !mbDxf, "Fill::setBiff3Data - unexpected conditional formatting flag" ); + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->setBiffData( + extractValue< sal_uInt16 >( nArea, 6, 5 ), + extractValue< sal_uInt16 >( nArea, 11, 5 ), + extractValue< sal_uInt8 >( nArea, 0, 6 ) ); +} + +void Fill::setBiff5Data( sal_uInt32 nArea ) +{ + OSL_ENSURE( !mbDxf, "Fill::setBiff5Data - unexpected conditional formatting flag" ); + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->setBiffData( + extractValue< sal_uInt16 >( nArea, 0, 7 ), + extractValue< sal_uInt16 >( nArea, 7, 7 ), + extractValue< sal_uInt8 >( nArea, 16, 6 ) ); +} + +void Fill::setBiff8Data( sal_uInt32 nBorder2, sal_uInt16 nArea ) +{ + OSL_ENSURE( !mbDxf, "Fill::setBiff8Data - unexpected conditional formatting flag" ); + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + mxPatternModel->setBiffData( + extractValue< sal_uInt16 >( nArea, 0, 7 ), + extractValue< sal_uInt16 >( nArea, 7, 7 ), + extractValue< sal_uInt8 >( nBorder2, 26, 6 ) ); +} + +void Fill::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags ) +{ + OSL_ENSURE( mbDxf, "Fill::importCfRule - missing conditional formatting flag" ); + OSL_ENSURE( getFlag( nFlags, BIFF_CFRULE_FILLBLOCK ), "Fill::importCfRule - missing fill block flag" ); + mxPatternModel.reset( new PatternFillModel( mbDxf ) ); + sal_uInt32 nFillData; + rStrm >> nFillData; + mxPatternModel->setBiffData( + extractValue< sal_uInt16 >( nFillData, 16, 7 ), + extractValue< sal_uInt16 >( nFillData, 23, 7 ), + extractValue< sal_uInt8 >( nFillData, 10, 6 ) ); + mxPatternModel->mbPattColorUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_PATTCOLOR ); + mxPatternModel->mbFillColorUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_FILLCOLOR ); + mxPatternModel->mbPatternUsed = !getFlag( nFlags, BIFF_CFRULE_FILL_PATTERN ); +} + +void Fill::finalizeImport() +{ + const GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper(); + + if( mxPatternModel.get() ) + { + // finalize the OOX data struct + PatternFillModel& rModel = *mxPatternModel; + if( mbDxf ) + { + if( rModel.mbFillColorUsed && (!rModel.mbPatternUsed || (rModel.mnPattern == XML_solid)) ) + { + rModel.maPatternColor = rModel.maFillColor; + rModel.mnPattern = XML_solid; + rModel.mbPattColorUsed = rModel.mbPatternUsed = true; + } + else if( !rModel.mbFillColorUsed && rModel.mbPatternUsed && (rModel.mnPattern == XML_solid) ) + { + rModel.mbPatternUsed = false; + } + } + + // 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; + } + + sal_Int32 nWinTextColor = rGraphicHelper.getSystemColor( XML_windowText ); + sal_Int32 nWinColor = rGraphicHelper.getSystemColor( XML_window ); + + if( !rModel.mbPattColorUsed ) + rModel.maPatternColor.setAuto(); + sal_Int32 nPattColor = rModel.maPatternColor.getColor( rGraphicHelper, nWinTextColor ); + + if( !rModel.mbFillColorUsed ) + rModel.maFillColor.setAuto(); + sal_Int32 nFillColor = rModel.maFillColor.getColor( rGraphicHelper, nWinColor ); + + maApiData.mnColor = lclGetMixedColor( nPattColor, nFillColor, nAlpha ); + maApiData.mbTransparent = false; + } + } + else if( mxGradientModel.get() && !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" ); + sal_Int32 nEndColor = aIt->second.getColor( rGraphicHelper, API_RGB_WHITE ); + maApiData.mnColor = lclGetMixedColor( maApiData.mnColor, nEndColor, 0x40 ); + maApiData.mbTransparent = false; + } + } +} + +void Fill::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + if( maApiData.mbUsed ) + { + rPropMap[ PROP_CellBackColor ] <<= maApiData.mnColor; + rPropMap[ PROP_IsCellBackgroundTransparent ] <<= maApiData.mbTransparent; + } +} + +// ============================================================================ + +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::Xf( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + maAlignment( rHelper ), + maProtection( rHelper ), + meRotationRef( ::com::sun::star::table::CellVertJustify_STANDARD ) +{ +} + +void Xf::setAllUsedFlags( bool bUsed ) +{ + maModel.mbAlignUsed = maModel.mbProtUsed = maModel.mbFontUsed = + maModel.mbNumFmtUsed = maModel.mbBorderUsed = maModel.mbAreaUsed = bUsed; +} + +void Xf::importXf( const AttributeList& rAttribs, bool bCellXf ) +{ + maModel.mbCellXf = bCellXf; + maModel.mnStyleXfId = rAttribs.getInteger( XML_xfId, -1 ); + 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... */ + maModel.mbAlignUsed = rAttribs.getBool( XML_applyAlignment, !maModel.mbCellXf ); + maModel.mbProtUsed = rAttribs.getBool( XML_applyProtection, !maModel.mbCellXf ); + maModel.mbFontUsed = rAttribs.getBool( XML_applyFont, !maModel.mbCellXf ); + maModel.mbNumFmtUsed = rAttribs.getBool( XML_applyNumberFormat, !maModel.mbCellXf ); + maModel.mbBorderUsed = rAttribs.getBool( XML_applyBorder, !maModel.mbCellXf ); + maModel.mbAreaUsed = rAttribs.getBool( XML_applyFill, !maModel.mbCellXf ); +} + +void Xf::importAlignment( const AttributeList& rAttribs ) +{ + maAlignment.importAlignment( rAttribs ); +} + +void Xf::importProtection( const AttributeList& rAttribs ) +{ + maProtection.importProtection( rAttribs ); +} + +void Xf::importXf( RecordInputStream& 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.setBinData( nFlags ); + maProtection.setBinData( nFlags ); + // used flags, see comments in Xf::setBiffUsedFlags() + sal_uInt16 nUsedFlags = rStrm.readuInt16(); + maModel.mbFontUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_FONT_USED ); + maModel.mbNumFmtUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_NUMFMT_USED ); + maModel.mbAlignUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_ALIGN_USED ); + maModel.mbProtUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_PROT_USED ); + maModel.mbBorderUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_BORDER_USED ); + maModel.mbAreaUsed = maModel.mbCellXf == getFlag( nUsedFlags, OOBIN_XF_AREA_USED ); +} + +void Xf::importXf( BiffInputStream& rStrm ) +{ + BorderRef xBorder = getStyles().createBorder( &maModel.mnBorderId ); + FillRef xFill = getStyles().createFill( &maModel.mnFillId ); + + switch( getBiff() ) + { + case BIFF2: + { + sal_uInt8 nFontId, nNumFmtId, nFlags; + rStrm >> nFontId; + rStrm.skip( 1 ); + rStrm >> nNumFmtId >> nFlags; + + // only cell XFs in BIFF2, no parent style, used flags always true + setAllUsedFlags( true ); + + // attributes + maAlignment.setBiff2Data( nFlags ); + maProtection.setBiff2Data( nNumFmtId ); + xBorder->setBiff2Data( nFlags ); + xFill->setBiff2Data( nFlags ); + maModel.mnFontId = static_cast< sal_Int32 >( nFontId ); + maModel.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId & BIFF2_XF_VALFMT_MASK ); + } + break; + + case BIFF3: + { + sal_uInt32 nBorder; + sal_uInt16 nTypeProt, nAlign, nArea; + sal_uInt8 nFontId, nNumFmtId; + rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nArea >> nBorder; + + // XF type/parent + maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE ); // new in BIFF3 + maModel.mnStyleXfId = extractValue< sal_Int32 >( nAlign, 4, 12 ); // new in BIFF3 + // attribute used flags + setBiffUsedFlags( extractValue< sal_uInt8 >( nTypeProt, 10, 6 ) ); // new in BIFF3 + + // attributes + maAlignment.setBiff3Data( nAlign ); + maProtection.setBiff3Data( nTypeProt ); + xBorder->setBiff3Data( nBorder ); + xFill->setBiff3Data( nArea ); + maModel.mnFontId = static_cast< sal_Int32 >( nFontId ); + maModel.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId ); + } + break; + + case BIFF4: + { + sal_uInt32 nBorder; + sal_uInt16 nTypeProt, nAlign, nArea; + sal_uInt8 nFontId, nNumFmtId; + rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nArea >> nBorder; + + // XF type/parent + maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE ); + maModel.mnStyleXfId = extractValue< sal_Int32 >( nTypeProt, 4, 12 ); + // attribute used flags + setBiffUsedFlags( extractValue< sal_uInt8 >( nAlign, 10, 6 ) ); + + // attributes + maAlignment.setBiff4Data( nAlign ); + maProtection.setBiff3Data( nTypeProt ); + xBorder->setBiff3Data( nBorder ); + xFill->setBiff3Data( nArea ); + maModel.mnFontId = static_cast< sal_Int32 >( nFontId ); + maModel.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId ); + } + break; + + case BIFF5: + { + sal_uInt32 nArea, nBorder; + sal_uInt16 nFontId, nNumFmtId, nTypeProt, nAlign; + rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nArea >> nBorder; + + // XF type/parent + maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE ); + maModel.mnStyleXfId = extractValue< sal_Int32 >( nTypeProt, 4, 12 ); + // attribute used flags + setBiffUsedFlags( extractValue< sal_uInt8 >( nAlign, 10, 6 ) ); + + // attributes + maAlignment.setBiff5Data( nAlign ); + maProtection.setBiff3Data( nTypeProt ); + xBorder->setBiff5Data( nBorder, nArea ); + xFill->setBiff5Data( nArea ); + maModel.mnFontId = static_cast< sal_Int32 >( nFontId ); + maModel.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId ); + } + break; + + case BIFF8: + { + sal_uInt32 nBorder1, nBorder2; + sal_uInt16 nFontId, nNumFmtId, nTypeProt, nAlign, nMiscAttrib, nArea; + rStrm >> nFontId >> nNumFmtId >> nTypeProt >> nAlign >> nMiscAttrib >> nBorder1 >> nBorder2 >> nArea; + + // XF type/parent + maModel.mbCellXf = !getFlag( nTypeProt, BIFF_XF_STYLE ); + maModel.mnStyleXfId = extractValue< sal_Int32 >( nTypeProt, 4, 12 ); + // attribute used flags + setBiffUsedFlags( extractValue< sal_uInt8 >( nMiscAttrib, 10, 6 ) ); + + // attributes + maAlignment.setBiff8Data( nAlign, nMiscAttrib ); + maProtection.setBiff3Data( nTypeProt ); + xBorder->setBiff8Data( nBorder1, nBorder2 ); + xFill->setBiff8Data( nBorder2, nArea ); + maModel.mnFontId = static_cast< sal_Int32 >( nFontId ); + maModel.mnNumFmtId = static_cast< sal_Int32 >( nNumFmtId ); + } + break; + + case BIFF_UNKNOWN: break; + } +} + +void Xf::finalizeImport() +{ + StylesBuffer& rStyles = getStyles(); + + // alignment and protection + maAlignment.finalizeImport(); + maProtection.finalizeImport(); + + /* 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. + */ + const Xf* pStyleXf = isCellXf() ? rStyles.getStyleXf( maModel.mnStyleXfId ).get() : 0; + if( pStyleXf ) + { + 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 || !rStyles.equalBorders( maModel.mnBorderId, rStyleData.mnBorderId ); + if( !maModel.mbAreaUsed ) + maModel.mbAreaUsed = !rStyleData.mbAreaUsed || !rStyles.equalFills( maModel.mnFillId, rStyleData.mnFillId ); + } + + /* #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 : 0) ) + { + sal_Int32 nBorderId = maModel.mbBorderUsed ? maModel.mnBorderId : (pStyleXf ? pStyleXf->maModel.mnBorderId : -1); + if( const Border* pBorder = rStyles.getBorder( nBorderId ).get() ) + if( (pAlignment->getApiData().mnRotation != 0) && pBorder->getApiData().hasAnyOuterBorder() ) + meRotationRef = ::com::sun::star::table::CellVertJustify_BOTTOM; + } +} + +FontRef Xf::getFont() const +{ + return getStyles().getFont( maModel.mnFontId ); +} + +bool Xf::hasAnyUsedFlags() const +{ + return + maModel.mbAlignUsed || maModel.mbProtUsed || maModel.mbFontUsed || + maModel.mbNumFmtUsed || maModel.mbBorderUsed || maModel.mbAreaUsed; +} + +void Xf::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + StylesBuffer& rStyles = getStyles(); + + // create and set cell style + if( isCellXf() ) + rPropMap[ PROP_CellStyle ] <<= rStyles.createCellStyle( maModel.mnStyleXfId ); + + if( maModel.mbFontUsed ) + rStyles.writeFontToPropertyMap( rPropMap, maModel.mnFontId ); + if( maModel.mbNumFmtUsed ) + rStyles.writeNumFmtToPropertyMap( rPropMap, maModel.mnNumFmtId ); + if( maModel.mbAlignUsed ) + maAlignment.writeToPropertyMap( rPropMap ); + if( maModel.mbProtUsed ) + maProtection.writeToPropertyMap( rPropMap ); + if( maModel.mbBorderUsed ) + rStyles.writeBorderToPropertyMap( rPropMap, maModel.mnBorderId ); + if( maModel.mbAreaUsed ) + rStyles.writeFillToPropertyMap( rPropMap, maModel.mnFillId ); + if( maModel.mbAlignUsed || maModel.mbBorderUsed ) + rPropMap[ PROP_RotateReference ] <<= meRotationRef; +} + +void Xf::writeToPropertySet( PropertySet& rPropSet ) const +{ + PropertyMap aPropMap; + writeToPropertyMap( aPropMap ); + rPropSet.setProperties( aPropMap ); +} + +void Xf::setBiffUsedFlags( sal_uInt8 nUsedFlags ) +{ + /* Notes about finding the used flags: + - In cell XFs a *set* bit means a used attribute. + - In style XFs a *cleared* bit means a used attribute. + The boolean flags always store true, if the attribute is used. + The "isCellXf() == getFlag(...)" construct evaluates to true in both + mentioned cases: cell XF and set bit; or style XF and cleared bit. + */ + maModel.mbFontUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_FONT_USED ); + maModel.mbNumFmtUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_NUMFMT_USED ); + maModel.mbAlignUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_ALIGN_USED ); + maModel.mbProtUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_PROT_USED ); + maModel.mbBorderUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_BORDER_USED ); + maModel.mbAreaUsed = isCellXf() == getFlag( nUsedFlags, BIFF_XF_AREA_USED ); +} + +// ============================================================================ + +Dxf::Dxf( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ) +{ +} + +FontRef Dxf::createFont( bool bAlwaysNew ) +{ + if( bAlwaysNew || !mxFont ) + mxFont.reset( new Font( *this, true ) ); + return mxFont; +} + +BorderRef Dxf::createBorder( bool bAlwaysNew ) +{ + if( bAlwaysNew || !mxBorder ) + mxBorder.reset( new Border( *this, true ) ); + return mxBorder; +} + +FillRef Dxf::createFill( bool bAlwaysNew ) +{ + if( bAlwaysNew || !mxFill ) + mxFill.reset( new Fill( *this, true ) ); + return mxFill; +} + +void Dxf::importNumFmt( const AttributeList& rAttribs ) +{ + mxNumFmt = getStyles().importNumFmt( rAttribs ); +} + +void Dxf::importAlignment( const AttributeList& rAttribs ) +{ + mxAlignment.reset( new Alignment( *this ) ); + mxAlignment->importAlignment( rAttribs ); +} + +void Dxf::importProtection( const AttributeList& rAttribs ) +{ + mxProtection.reset( new Protection( *this ) ); + mxProtection->importProtection( rAttribs ); +} + +void Dxf::importDxf( RecordInputStream& rStrm ) +{ + sal_Int32 nNumFmtId = -1; + OUString aFmtCode; + sal_uInt16 nRecCount; + rStrm.skip( 4 ); // flags + rStrm >> nRecCount; + for( sal_uInt16 nRec = 0; !rStrm.isEof() && (nRec < nRecCount); ++nRec ) + { + sal_uInt16 nSubRecId, nSubRecSize; + sal_Int64 nRecEnd = rStrm.tell(); + rStrm >> nSubRecId >> nSubRecSize; + nRecEnd += nSubRecSize; + switch( nSubRecId ) + { + case OOBIN_DXF_FILL_PATTERN: createFill( false )->importDxfPattern( rStrm ); break; + case OOBIN_DXF_FILL_FGCOLOR: createFill( false )->importDxfFgColor( rStrm ); break; + case OOBIN_DXF_FILL_BGCOLOR: createFill( false )->importDxfBgColor( rStrm ); break; + case OOBIN_DXF_FILL_GRADIENT: createFill( false )->importDxfGradient( rStrm ); break; + case OOBIN_DXF_FILL_STOP: createFill( false )->importDxfStop( rStrm ); break; + case OOBIN_DXF_FONT_COLOR: createFont( false )->importDxfColor( rStrm ); break; + case OOBIN_DXF_BORDER_TOP: createBorder( false )->importDxfBorder( XLS_TOKEN( top ), rStrm ); break; + case OOBIN_DXF_BORDER_BOTTOM: createBorder( false )->importDxfBorder( XLS_TOKEN( bottom ), rStrm ); break; + case OOBIN_DXF_BORDER_LEFT: createBorder( false )->importDxfBorder( XLS_TOKEN( left ), rStrm ); break; + case OOBIN_DXF_BORDER_RIGHT: createBorder( false )->importDxfBorder( XLS_TOKEN( right ), rStrm ); break; + case OOBIN_DXF_FONT_NAME: createFont( false )->importDxfName( rStrm ); break; + case OOBIN_DXF_FONT_WEIGHT: createFont( false )->importDxfWeight( rStrm ); break; + case OOBIN_DXF_FONT_UNDERLINE: createFont( false )->importDxfUnderline( rStrm ); break; + case OOBIN_DXF_FONT_ESCAPEMENT: createFont( false )->importDxfEscapement( rStrm ); break; + case OOBIN_DXF_FONT_ITALIC: createFont( false )->importDxfFlag( XML_i, rStrm ); break; + case OOBIN_DXF_FONT_STRIKE: createFont( false )->importDxfFlag( XML_strike, rStrm ); break; + case OOBIN_DXF_FONT_OUTLINE: createFont( false )->importDxfFlag( XML_outline, rStrm ); break; + case OOBIN_DXF_FONT_SHADOW: createFont( false )->importDxfFlag( XML_shadow, rStrm ); break; + case OOBIN_DXF_FONT_HEIGHT: createFont( false )->importDxfHeight( rStrm ); break; + case OOBIN_DXF_FONT_SCHEME: createFont( false )->importDxfScheme( rStrm ); break; + case OOBIN_DXF_NUMFMT_CODE: aFmtCode = rStrm.readString( false ); break; + case OOBIN_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::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags ) +{ + if( getFlag( nFlags, BIFF_CFRULE_FONTBLOCK ) ) + createFont()->importCfRule( rStrm ); + if( getFlag( nFlags, BIFF_CFRULE_ALIGNBLOCK ) ) + rStrm.skip( 8 ); + if( getFlag( nFlags, BIFF_CFRULE_BORDERBLOCK ) ) + createBorder()->importCfRule( rStrm, nFlags ); + if( getFlag( nFlags, BIFF_CFRULE_FILLBLOCK ) ) + createFill()->importCfRule( rStrm, nFlags ); + if( getFlag( nFlags, BIFF_CFRULE_PROTBLOCK ) ) + rStrm.skip( 2 ); +} + +void Dxf::finalizeImport() +{ + if( mxFont.get() ) + mxFont->finalizeImport(); + // number format already finalized by the number formats buffer + if( mxAlignment.get() ) + mxAlignment->finalizeImport(); + if( mxProtection.get() ) + mxProtection->finalizeImport(); + if( mxBorder.get() ) + mxBorder->finalizeImport(); + if( mxFill.get() ) + mxFill->finalizeImport(); +} + +void Dxf::writeToPropertyMap( PropertyMap& rPropMap ) const +{ + if( mxFont.get() ) + mxFont->writeToPropertyMap( rPropMap, FONT_PROPTYPE_CELL ); + if( mxNumFmt.get() ) + mxNumFmt->writeToPropertyMap( rPropMap ); + if( mxAlignment.get() ) + mxAlignment->writeToPropertyMap( rPropMap ); + if( mxProtection.get() ) + mxProtection->writeToPropertyMap( rPropMap ); + if( mxBorder.get() ) + mxBorder->writeToPropertyMap( rPropMap ); + if( mxFill.get() ) + mxFill->writeToPropertyMap( rPropMap ); +} + +void Dxf::writeToPropertySet( PropertySet& rPropSet ) const +{ + PropertyMap aPropMap; + writeToPropertyMap( aPropMap ); + rPropSet.setProperties( aPropMap ); +} + +// ============================================================================ + +namespace { + +const sal_Char* const spcLegacyStyleNamePrefix = "Excel_BuiltIn_"; +const sal_Char* const sppcLegacyStyleNames[] = +{ + "Normal", + "RowLevel_", // outline level will be appended + "ColumnLevel_", // outline level will be appended + "Comma", + "Currency", + "Percent", + "Comma_0", // new in BIFF4 + "Currency_0", + "Hyperlink", // new in BIFF8 + "Followed_Hyperlink" +}; +const sal_Int32 snLegacyStyleNamesCount = static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( sppcLegacyStyleNames ) ); + +const sal_Char* const spcStyleNamePrefix = "Excel Built-in "; +const sal_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", + "", + "", + "", + "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 >( STATIC_ARRAY_SIZE( sppcStyleNames ) ); + +OUString lclGetBuiltinStyleName( sal_Int32 nBuiltinId, const OUString& rName, sal_Int32 nLevel = 0 ) +{ + OSL_ENSURE( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount), "lclGetBuiltinStyleName - unknown built-in style" ); + OUStringBuffer aStyleName; + aStyleName.appendAscii( spcStyleNamePrefix ); + if( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount) && (sppcStyleNames[ nBuiltinId ][ 0 ] != 0) ) + aStyleName.appendAscii( sppcStyleNames[ nBuiltinId ] ); + else if( rName.getLength() > 0 ) + aStyleName.append( rName ); + else + aStyleName.append( nBuiltinId ); + if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) ) + aStyleName.append( nLevel ); + return aStyleName.makeStringAndClear(); +} + +OUString lclGetBuiltInStyleName( const OUString& rName ) +{ + OUStringBuffer aStyleName; + aStyleName.appendAscii( spcStyleNamePrefix ).append( rName ); + return aStyleName.makeStringAndClear(); +} + +bool lclIsBuiltinStyleName( const OUString& rStyleName, sal_Int32* pnBuiltinId, sal_Int32* pnNextChar ) +{ + // try the other built-in styles + OUString aPrefix = OUString::createFromAscii( spcStyleNamePrefix ); + sal_Int32 nPrefixLen = aPrefix.getLength(); + sal_Int32 nFoundId = 0; + sal_Int32 nNextChar = 0; + if( rStyleName.matchIgnoreAsciiCase( aPrefix ) ) + { + OUString aShortName; + for( sal_Int32 nId = 0; nId < snStyleNamesCount; ++nId ) + { + aShortName = OUString::createFromAscii( sppcStyleNames[ nId ] ); + if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) && + (nNextChar < nPrefixLen + aShortName.getLength()) ) + { + nFoundId = nId; + nNextChar = nPrefixLen + aShortName.getLength(); + } + } + } + + if( nNextChar > 0 ) + { + if( pnBuiltinId ) *pnBuiltinId = nFoundId; + if( pnNextChar ) *pnNextChar = nNextChar; + return true; + } + + if( pnBuiltinId ) *pnBuiltinId = -1; + if( pnNextChar ) *pnNextChar = 0; + return false; +} + +bool lclGetBuiltinStyleId( sal_Int32& rnBuiltinId, sal_Int32& rnLevel, const OUString& rStyleName ) +{ + sal_Int32 nBuiltinId; + sal_Int32 nNextChar; + if( lclIsBuiltinStyleName( rStyleName, &nBuiltinId, &nNextChar ) ) + { + if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) ) + { + OUString aLevel = rStyleName.copy( nNextChar ); + sal_Int32 nLevel = aLevel.toInt32(); + if( (0 < nLevel) && (nLevel <= OOX_STYLE_LEVELCOUNT) ) + { + rnBuiltinId = nBuiltinId; + rnLevel = nLevel; + return true; + } + } + else if( rStyleName.getLength() == nNextChar ) + { + rnBuiltinId = nBuiltinId; + rnLevel = 0; + return true; + } + } + rnBuiltinId = -1; + rnLevel = 0; + return false; +} + +} // 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 ) +{ +} + +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( RecordInputStream& rStrm ) +{ + sal_uInt16 nFlags; + rStrm >> maModel.mnXfId >> nFlags; + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); + rStrm >> maModel.maName; + maModel.mbBuiltin = getFlag( nFlags, OOBIN_CELLSTYLE_BUILTIN ); + maModel.mbCustom = getFlag( nFlags, OOBIN_CELLSTYLE_CUSTOM ); + maModel.mbHidden = getFlag( nFlags, OOBIN_CELLSTYLE_HIDDEN ); +} + +void CellStyle::importStyle( BiffInputStream& rStrm ) +{ + sal_uInt16 nStyleXf; + rStrm >> nStyleXf; + maModel.mnXfId = static_cast< sal_Int32 >( nStyleXf & BIFF_STYLE_XFMASK ); + maModel.mbBuiltin = getFlag( nStyleXf, BIFF_STYLE_BUILTIN ); + if( maModel.mbBuiltin ) + { + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); + } + else + { + maModel.maName = (getBiff() == BIFF8) ? + rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ); + // #i103281# check if this is a new built-in style introduced in XL2007 + if( (getBiff() == BIFF8) && (rStrm.getNextRecId() == BIFF_ID_STYLEEXT) && rStrm.startNextRecord() ) + { + sal_uInt8 nExtFlags; + rStrm.skip( 12 ); + rStrm >> nExtFlags; + maModel.mbBuiltin = getFlag( nExtFlags, BIFF_STYLEEXT_BUILTIN ); + maModel.mbCustom = getFlag( nExtFlags, BIFF_STYLEEXT_CUSTOM ); + maModel.mbHidden = getFlag( nExtFlags, BIFF_STYLEEXT_HIDDEN ); + if( maModel.mbBuiltin ) + { + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); + } + } + } +} + +void CellStyle::createCellStyle() +{ + // #i1624# #i1768# ignore unnamed user styles + if( !mbCreated ) + mbCreated = maFinalName.getLength() == 0; + + /* #i103281# do not create another style of the same name, if it exists + already. This is needed to prevent that styles pasted from clipboard + get duplicated over and over. */ + if( !mbCreated ) try + { + Reference< XNameAccess > xCellStylesNA( getStyleFamily( false ), UNO_QUERY_THROW ); + mbCreated = xCellStylesNA->hasByName( maFinalName ); + } + catch( Exception& ) + { + } + + // create the style object in the document + if( !mbCreated ) try + { + mbCreated = true; + Reference< XStyle > xStyle( createStyleObject( maFinalName, false ), UNO_SET_THROW ); + // write style formatting properties + PropertySet aPropSet( xStyle ); + getStyles().writeStyleXfToPropertySet( aPropSet, maModel.mnXfId ); + if( !maModel.isDefaultStyle() ) + xStyle->setParentStyle( getStyles().getDefaultStyleName() ); + } + catch( Exception& ) + { + } +} + +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( new CellStyle( *this ) ); + xCellStyle->importCellStyle( rAttribs ); + insertCellStyle( xCellStyle ); + return xCellStyle; +} + +CellStyleRef CellStyleBuffer::importCellStyle( RecordInputStream& rStrm ) +{ + CellStyleRef xCellStyle( new CellStyle( *this ) ); + xCellStyle->importCellStyle( rStrm ); + insertCellStyle( xCellStyle ); + return xCellStyle; +} + +CellStyleRef CellStyleBuffer::importStyle( BiffInputStream& rStrm ) +{ + CellStyleRef xCellStyle( new CellStyle( *this ) ); + xCellStyle->importStyle( 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. For BIFF4 workbooks (which contain a + separate list of cell styles per sheet), reserve all existing styles if + current sheet is not the first sheet (this styles buffer will be + constructed again for every new sheet). This will create unique names + for styles in different sheets with the same name. Assuming that the + BIFF4W import filter is never used to import from clipboard... */ + bool bReserveAll = (getFilterType() == FILTER_BIFF) && (getBiff() == BIFF4) && isWorkbookFile() && (getCurrentSheetIndex() > 0); + try + { + // unfortunately, com.sun.star.style.StyleFamily does not implement XEnumerationAccess... + Reference< XIndexAccess > xStyleFamilyIA( getStyleFamily( false ), UNO_QUERY_THROW ); + for( sal_Int32 nIndex = 0, nCount = xStyleFamilyIA->getCount(); nIndex < nCount; ++nIndex ) + { + Reference< XStyle > xStyle( xStyleFamilyIA->getByIndex( nIndex ), UNO_QUERY_THROW ); + if( bReserveAll || !xStyle->isUserDefined() ) + { + Reference< XNamed > xStyleName( xStyle, UNO_QUERY_THROW ); + // create an empty entry by using ::std::map<>::operator[] + aCellStyles[ xStyleName->getName() ]; + } + } + } + catch( Exception& ) + { + } + + /* Calculate names of built-in styles. Store styles with reserved names + in the aConflictNameStyles list. */ + for( CellStyleVector::iterator aIt = maBuiltinStyles.begin(), aEnd = maBuiltinStyles.end(); aIt != aEnd; ++aIt ) + { + const CellStyleModel& rModel = (*aIt)->getModel(); + OUString aStyleName = lclGetBuiltinStyleName( rModel.mnBuiltinId, rModel.maName, rModel.mnLevel ); + OSL_ENSURE( bReserveAll || (aCellStyles.count( aStyleName ) == 0), + "CellStyleBuffer::finalizeImport - multiple styles with equal built-in identifier" ); + if( aCellStyles.count( aStyleName ) > 0 ) + aConflictNameStyles.push_back( *aIt ); + else + aCellStyles[ aStyleName ] = *aIt; + } + + /* Calculate names of user defined styles. Store styles with reserved + names in the aConflictNameStyles list. */ + for( CellStyleVector::iterator aIt = maUserStyles.begin(), aEnd = maUserStyles.end(); aIt != aEnd; ++aIt ) + { + const CellStyleModel& rModel = (*aIt)->getModel(); + // #i1624# #i1768# ignore unnamed user styles + if( rModel.maName.getLength() > 0 ) + { + if( aCellStyles.count( rModel.maName ) > 0 ) + aConflictNameStyles.push_back( *aIt ); + else + aCellStyles[ rModel.maName ] = *aIt; + } + } + + // find unused names for all styles with conflicting names + for( CellStyleVector::iterator aIt = aConflictNameStyles.begin(), aEnd = aConflictNameStyles.end(); aIt != aEnd; ++aIt ) + { + const CellStyleModel& rModel = (*aIt)->getModel(); + OUString aUnusedName; + sal_Int32 nIndex = 0; + do + { + aUnusedName = OUStringBuffer( rModel.maName ).append( sal_Unicode( ' ' ) ).append( ++nIndex ).makeStringAndClear(); + } + while( aCellStyles.count( aUnusedName ) > 0 ); + aCellStyles[ aUnusedName ] = *aIt; + } + + // set final names and create user-defined and modified built-in cell styles + aCellStyles.forEachMemWithKey( &CellStyle::finalizeImport ); +} + +sal_Int32 CellStyleBuffer::getDefaultXfId() const +{ + return mxDefStyle.get() ? mxDefStyle->getModel().mnXfId : -1; +} + +OUString CellStyleBuffer::getDefaultStyleName() const +{ + return createCellStyle( mxDefStyle ); +} + +OUString CellStyleBuffer::createCellStyle( sal_Int32 nXfId ) const +{ + return createCellStyle( maStylesByXf.get( nXfId ) ); +} + +// private -------------------------------------------------------------------- + +void CellStyleBuffer::insertCellStyle( CellStyleRef xCellStyle ) +{ + const CellStyleModel& rModel = xCellStyle->getModel(); + if( rModel.mnXfId >= 0 ) + { + // 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; + } +} + +OUString CellStyleBuffer::createCellStyle( const CellStyleRef& rxCellStyle ) const +{ + if( rxCellStyle.get() ) + { + rxCellStyle->createCellStyle(); + const OUString& rStyleName = rxCellStyle->getFinalStyleName(); + if( rStyleName.getLength() > 0 ) + return rStyleName; + } + // on error: fallback to default style + return lclGetBuiltinStyleName( OOX_STYLE_NORMAL, OUString() ); +} + +// ============================================================================ + +StylesBuffer::StylesBuffer( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + maPalette( rHelper ), + maNumFmts( rHelper ), + maCellStyles( rHelper ) +{ +} + +FontRef StylesBuffer::createFont( sal_Int32* opnFontId ) +{ + if( opnFontId ) *opnFontId = static_cast< sal_Int32 >( maFonts.size() ); + FontRef xFont( new Font( *this, false ) ); + maFonts.push_back( xFont ); + return xFont; +} + +NumberFormatRef StylesBuffer::createNumFmt( sal_Int32 nNumFmtId, const OUString& rFmtCode ) +{ + return maNumFmts.createNumFmt( nNumFmtId, rFmtCode ); +} + +BorderRef StylesBuffer::createBorder( sal_Int32* opnBorderId ) +{ + if( opnBorderId ) *opnBorderId = static_cast< sal_Int32 >( maBorders.size() ); + BorderRef xBorder( new Border( *this, false ) ); + maBorders.push_back( xBorder ); + return xBorder; +} + +FillRef StylesBuffer::createFill( sal_Int32* opnFillId ) +{ + if( opnFillId ) *opnFillId = static_cast< sal_Int32 >( maFills.size() ); + FillRef xFill( new Fill( *this, false ) ); + maFills.push_back( xFill ); + return xFill; +} + +XfRef StylesBuffer::createCellXf( sal_Int32* opnXfId ) +{ + if( opnXfId ) *opnXfId = static_cast< sal_Int32 >( maCellXfs.size() ); + XfRef xXf( new Xf( *this ) ); + maCellXfs.push_back( xXf ); + return xXf; +} + +XfRef StylesBuffer::createStyleXf( sal_Int32* opnXfId ) +{ + if( opnXfId ) *opnXfId = static_cast< sal_Int32 >( maStyleXfs.size() ); + XfRef xXf( new Xf( *this ) ); + maStyleXfs.push_back( xXf ); + return xXf; +} + +DxfRef StylesBuffer::createDxf( sal_Int32* opnDxfId ) +{ + if( opnDxfId ) *opnDxfId = static_cast< sal_Int32 >( maDxfs.size() ); + DxfRef xDxf( new Dxf( *this ) ); + maDxfs.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( RecordInputStream& rStrm ) +{ + maPalette.importPaletteColor( rStrm ); +} + +void StylesBuffer::importNumFmt( RecordInputStream& rStrm ) +{ + maNumFmts.importNumFmt( rStrm ); +} + +void StylesBuffer::importCellStyle( RecordInputStream& rStrm ) +{ + maCellStyles.importCellStyle( rStrm ); +} + +void StylesBuffer::importPalette( BiffInputStream& rStrm ) +{ + maPalette.importPalette( rStrm ); +} + +void StylesBuffer::importFont( BiffInputStream& rStrm ) +{ + /* Font with index 4 is not stored in BIFF. This means effectively, first + font in the BIFF file has index 0, fourth font has index 3, and fifth + font has index 5. Insert a dummy font to correctly map passed font + identifiers. */ + if( maFonts.size() == 4 ) + maFonts.push_back( maFonts.front() ); + + FontRef xFont = createFont(); + xFont->importFont( rStrm ); + + /* #i71033# Set stream text encoding from application font, if CODEPAGE + record is missing. Must be done now (not while finalizeImport() runs), + to be able to read all following byte strings correctly (e.g. cell + style names). */ + if( maFonts.size() == 1 ) + setAppFontEncoding( xFont->getFontEncoding() ); +} + +void StylesBuffer::importFontColor( BiffInputStream& rStrm ) +{ + if( !maFonts.empty() ) + maFonts.back()->importFontColor( rStrm ); +} + +void StylesBuffer::importFormat( BiffInputStream& rStrm ) +{ + maNumFmts.importFormat( rStrm ); +} + +void StylesBuffer::importXf( BiffInputStream& rStrm ) +{ + XfRef xXf( new Xf( *this ) ); + xXf->importXf( rStrm ); + + XfRef xCellXf, xStyleXf; + (xXf->isCellXf() ? xCellXf : xStyleXf) = xXf; + maCellXfs.push_back( xCellXf ); + maStyleXfs.push_back( xStyleXf ); +} + +void StylesBuffer::importStyle( BiffInputStream& rStrm ) +{ + maCellStyles.importStyle( 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 + maBorders.forEachMem( &Border::finalizeImport ); + 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 ); +} + +sal_Int32 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 ); +} + +DxfRef StylesBuffer::getDxf( sal_Int32 nDxfId ) const +{ + return maDxfs.get( nDxfId ); +} + +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.get(), "StylesBuffer::getDefaultFont - no default font found" ); + return xDefFont; +} + +const FontModel& StylesBuffer::getDefaultFontModel() const +{ + FontRef xDefFont = getDefaultFont(); + return xDefFont.get() ? xDefFont->getModel() : getTheme().getDefaultFontModel(); +} + +bool StylesBuffer::equalBorders( sal_Int32 nBorderId1, sal_Int32 nBorderId2 ) const +{ + if( nBorderId1 == nBorderId2 ) + return true; + + switch( getFilterType() ) + { + case FILTER_OOX: + // in OOXML, borders are assumed to be unique + return false; + + case FILTER_BIFF: + { + // in BIFF, a new border entry has been created for every XF + const Border* pBorder1 = maBorders.get( nBorderId1 ).get(); + const Border* pBorder2 = maBorders.get( nBorderId2 ).get(); + return pBorder1 && pBorder2 && (pBorder1->getApiData() == pBorder2->getApiData()); + } + + case FILTER_UNKNOWN: + break; + } + return false; +} + +bool StylesBuffer::equalFills( sal_Int32 nFillId1, sal_Int32 nFillId2 ) const +{ + if( nFillId1 == nFillId2 ) + return true; + + switch( getFilterType() ) + { + case FILTER_OOX: + // in OOXML, fills are assumed to be unique + return false; + + case FILTER_BIFF: + { + // in BIFF, a new fill entry has been created for every XF + const Fill* pFill1 = maFills.get( nFillId1 ).get(); + const Fill* pFill2 = maFills.get( nFillId2 ).get(); + return pFill1 && pFill2 && (pFill1->getApiData() == pFill2->getApiData()); + } + + case FILTER_UNKNOWN: + break; + } + return false; +} + +OUString StylesBuffer::getDefaultStyleName() const +{ + return maCellStyles.getDefaultStyleName(); +} + +OUString StylesBuffer::createCellStyle( sal_Int32 nXfId ) const +{ + return maCellStyles.createCellStyle( nXfId ); +} + +OUString StylesBuffer::createDxfStyle( sal_Int32 nDxfId ) const +{ + OUString& rStyleName = maDxfStyles[ nDxfId ]; + if( rStyleName.getLength() == 0 ) + { + if( Dxf* pDxf = maDxfs.get( nDxfId ).get() ) + { + rStyleName = OUStringBuffer( CREATE_OUSTRING( "ConditionalStyle_" ) ).append( nDxfId + 1 ).makeStringAndClear(); + // create the style sheet (this may change rStyleName if such a style already exists) + Reference< XStyle > xStyle = createStyleObject( rStyleName, false ); + // write style formatting properties + PropertySet aPropSet( xStyle ); + pDxf->writeToPropertySet( aPropSet ); + } + // on error: fallback to default style + if( rStyleName.getLength() == 0 ) + rStyleName = maCellStyles.getDefaultStyleName(); + } + return rStyleName; +} + +void StylesBuffer::writeFontToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFontId ) const +{ + if( Font* pFont = maFonts.get( nFontId ).get() ) + pFont->writeToPropertyMap( rPropMap, FONT_PROPTYPE_CELL ); +} + +void StylesBuffer::writeNumFmtToPropertyMap( PropertyMap& rPropMap, sal_Int32 nNumFmtId ) const +{ + maNumFmts.writeToPropertyMap( rPropMap, nNumFmtId ); +} + +void StylesBuffer::writeBorderToPropertyMap( PropertyMap& rPropMap, sal_Int32 nBorderId ) const +{ + if( Border* pBorder = maBorders.get( nBorderId ).get() ) + pBorder->writeToPropertyMap( rPropMap ); +} + +void StylesBuffer::writeFillToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFillId ) const +{ + if( Fill* pFill = maFills.get( nFillId ).get() ) + pFill->writeToPropertyMap( rPropMap ); +} + +void StylesBuffer::writeCellXfToPropertyMap( PropertyMap& rPropMap, sal_Int32 nXfId ) const +{ + if( Xf* pXf = maCellXfs.get( nXfId ).get() ) + pXf->writeToPropertyMap( rPropMap ); +} + +void StylesBuffer::writeStyleXfToPropertyMap( PropertyMap& rPropMap, sal_Int32 nXfId ) const +{ + if( Xf* pXf = maStyleXfs.get( nXfId ).get() ) + pXf->writeToPropertyMap( rPropMap ); +} + +void StylesBuffer::writeCellXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const +{ + if( Xf* pXf = maCellXfs.get( nXfId ).get() ) + pXf->writeToPropertySet( rPropSet ); +} + +void StylesBuffer::writeStyleXfToPropertySet( PropertySet& rPropSet, sal_Int32 nXfId ) const +{ + if( Xf* pXf = maStyleXfs.get( nXfId ).get() ) + pXf->writeToPropertySet( rPropSet ); +} + +// ============================================================================ + +} // namespace xls +} // namespace oox + |