1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawingml/textcharacterproperties.hxx>
21 #include <com/sun/star/lang/Locale.hpp>
22 #include <com/sun/star/awt/FontSlant.hpp>
23 #include <com/sun/star/awt/FontWeight.hpp>
24 #include <com/sun/star/i18n/ScriptType.hpp>
25 #include <comphelper/sequence.hxx>
26 #include <i18nlangtag/languagetag.hxx>
27 #include <i18nlangtag/mslangid.hxx>
28 #include <editeng/escapementitem.hxx>
29 #include <docmodel/uno/UnoComplexColor.hxx>
30 #include <oox/helper/helper.hxx>
31 #include <oox/helper/propertyset.hxx>
32 #include <oox/core/xmlfilterbase.hxx>
33 #include <oox/drawingml/drawingmltypes.hxx>
34 #include <oox/token/properties.hxx>
35 #include <oox/token/tokens.hxx>
37 using ::oox::core::XmlFilterBase
;
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::beans
;
42 namespace oox::drawingml
{
44 void TextCharacterProperties::assignUsed( const TextCharacterProperties
& rSourceProps
)
46 // overwrite all properties existing in rSourceProps
47 maHyperlinkPropertyMap
.assignUsed( rSourceProps
.maHyperlinkPropertyMap
);
48 maLatinFont
.assignIfUsed( rSourceProps
.maLatinFont
);
49 maLatinThemeFont
.assignIfUsed( rSourceProps
.maLatinThemeFont
);
50 maAsianFont
.assignIfUsed( rSourceProps
.maAsianFont
);
51 maAsianThemeFont
.assignIfUsed( rSourceProps
.maAsianThemeFont
);
52 maComplexFont
.assignIfUsed( rSourceProps
.maComplexFont
);
53 maComplexThemeFont
.assignIfUsed( rSourceProps
.maComplexThemeFont
);
54 maSymbolFont
.assignIfUsed( rSourceProps
.maSymbolFont
);
55 maHighlightColor
.assignIfUsed( rSourceProps
.maHighlightColor
);
56 maUnderlineColor
.assignIfUsed( rSourceProps
.maUnderlineColor
);
57 assignIfUsed( moLang
, rSourceProps
.moLang
);
58 assignIfUsed( moHeight
, rSourceProps
.moHeight
);
59 assignIfUsed( moFontScale
, rSourceProps
.moFontScale
);
60 assignIfUsed( moSpacing
, rSourceProps
.moSpacing
);
61 assignIfUsed( moUnderline
, rSourceProps
.moUnderline
);
62 assignIfUsed( moBaseline
, rSourceProps
.moBaseline
);
63 assignIfUsed( moStrikeout
, rSourceProps
.moStrikeout
);
64 assignIfUsed( moCaseMap
, rSourceProps
.moCaseMap
);
65 assignIfUsed( moBold
, rSourceProps
.moBold
);
66 assignIfUsed( moItalic
, rSourceProps
.moItalic
);
67 assignIfUsed( moUnderlineLineFollowText
, rSourceProps
.moUnderlineLineFollowText
);
68 assignIfUsed( moUnderlineFillFollowText
, rSourceProps
.moUnderlineFillFollowText
);
69 assignIfUsed( moTextOutlineProperties
, rSourceProps
.moTextOutlineProperties
);
71 maTextEffectsProperties
= rSourceProps
.maTextEffectsProperties
;
72 maFillProperties
.assignUsed( rSourceProps
.maFillProperties
);
75 void TextCharacterProperties::pushToPropMap( PropertyMap
& rPropMap
, const XmlFilterBase
& rFilter
) const
78 sal_Int16 nFontPitch
= 0;
79 sal_Int16 nFontFamily
= 0;
81 bool bRet
= maLatinFont
.getFontData( aFontName
, nFontPitch
, nFontFamily
, rFilter
);
83 // In case there is no direct font, try to look it up as a theme reference.
84 bRet
= maLatinThemeFont
.getFontData( aFontName
, nFontPitch
, nFontFamily
, rFilter
);
87 rPropMap
.setProperty( PROP_CharFontName
, aFontName
);
88 rPropMap
.setProperty( PROP_CharFontPitch
, nFontPitch
);
89 rPropMap
.setProperty( PROP_CharFontFamily
, nFontFamily
);
92 bRet
= maAsianFont
.getFontData( aFontName
, nFontPitch
, nFontFamily
, rFilter
);
94 bRet
= maAsianThemeFont
.getFontData( aFontName
, nFontPitch
, nFontFamily
, rFilter
);
97 rPropMap
.setProperty( PROP_CharFontNameAsian
, aFontName
);
98 rPropMap
.setProperty( PROP_CharFontPitchAsian
, nFontFamily
);
99 rPropMap
.setProperty( PROP_CharFontFamilyAsian
, nFontPitch
);
102 bRet
= maComplexFont
.getFontData( aFontName
, nFontPitch
, nFontFamily
, rFilter
);
104 bRet
= maComplexThemeFont
.getFontData( aFontName
, nFontPitch
, nFontFamily
, rFilter
);
107 rPropMap
.setProperty( PROP_CharFontNameComplex
, aFontName
);
108 rPropMap
.setProperty( PROP_CharFontPitchComplex
, nFontPitch
);
109 rPropMap
.setProperty( PROP_CharFontFamilyComplex
, nFontFamily
);
112 if ( maFillProperties
.moFillType
.has_value() )
114 Color aColor
= maFillProperties
.getBestSolidColor();
115 bool bContoured
= false;
117 // noFill doesn't exist for characters. Map noFill to 99% transparency
118 if (maFillProperties
.moFillType
.value() == XML_noFill
)
119 aColor
.addTransformation(XML_alpha
, 1000);
121 // tdf#137438 Emulate text outline color/transparency.
122 // If the outline color dominates, then use it as the text color.
123 if (moTextOutlineProperties
.has_value()
124 && moTextOutlineProperties
.value().maLineFill
.moFillType
.has_value()
125 && moTextOutlineProperties
.value().maLineFill
.moFillType
.value() != XML_noFill
)
127 Color aLineColor
= moTextOutlineProperties
.value().maLineFill
.getBestSolidColor();
128 sal_Int16 nLineTransparency
= aLineColor
.getTransparency();
130 // tdf#127696 If the text color is white (and the outline color doesn't dominate),
131 // then this is contoured text in LO.
132 if (nLineTransparency
< aColor
.getTransparency()
133 || (bContoured
= aColor
.getColor(rFilter
.getGraphicHelper()) == COL_WHITE
))
136 rPropMap
.setProperty(PROP_CharColor
, aColor
.getColor(rFilter
.getGraphicHelper()));
139 model::ComplexColor aComplexColor
= aColor
.getComplexColor();
140 rPropMap
.setProperty(PROP_CharComplexColor
, model::color::createXComplexColor(aComplexColor
));
141 rPropMap
.setProperty(PROP_CharContoured
, bContoured
);
143 if (aColor
.hasTransparency())
145 const auto nTransparency
= aColor
.getTransparency();
146 rPropMap
.setProperty(PROP_CharTransparence
, nTransparency
);
148 // WORKAROUND: Fully transparent white has the same value as COL_AUTO, avoid collision
149 if (nTransparency
== 100
150 && aColor
.getColor(rFilter
.getGraphicHelper()).GetRGBColor() == COL_AUTO
.GetRGBColor())
151 rPropMap
.setProperty(PROP_CharColor
, ::Color(ColorTransparency
, 0xFFFFFFFE));
155 if( moLang
.has_value() && !moLang
.value().isEmpty() )
157 LanguageTag
aTag(moLang
.value());
158 lang::Locale
aLocale(aTag
.getLocale());
159 switch(MsLangId::getScriptType(aTag
.getLanguageType()))
161 case css::i18n::ScriptType::LATIN
:
162 rPropMap
.setProperty( PROP_CharLocale
, aLocale
);break;
163 case css::i18n::ScriptType::ASIAN
:
164 rPropMap
.setProperty( PROP_CharLocaleAsian
, aLocale
);break;
165 case css::i18n::ScriptType::COMPLEX
:
166 rPropMap
.setProperty( PROP_CharLocaleComplex
, aLocale
);break;
170 if( moHeight
.has_value() )
172 float fHeight
= GetFontHeight( moHeight
.value() );
173 if (moFontScale
.has_value())
174 fHeight
*= (moFontScale
.value() / 100000);
175 rPropMap
.setProperty( PROP_CharHeight
, fHeight
);
176 rPropMap
.setProperty( PROP_CharHeightAsian
, fHeight
);
177 rPropMap
.setProperty( PROP_CharHeightComplex
, fHeight
);
180 rPropMap
.setProperty( PROP_CharKerning
, static_cast<sal_Int16
>(GetTextSpacingPoint( moSpacing
.value_or( 0 ) )));
182 rPropMap
.setProperty( PROP_CharUnderline
, GetFontUnderline( moUnderline
.value_or( XML_none
) ));
183 rPropMap
.setProperty( PROP_CharStrikeout
, GetFontStrikeout( moStrikeout
.value_or( XML_noStrike
) ));
184 rPropMap
.setProperty( PROP_CharCaseMap
, GetCaseMap( moCaseMap
.value_or( XML_none
) ));
186 if( moBaseline
.has_value() ) {
187 rPropMap
.setProperty( PROP_CharEscapement
, sal_Int16(moBaseline
.value_or( 0 ) / 1000));
188 rPropMap
.setProperty( PROP_CharEscapementHeight
, sal_Int8(DFLT_ESC_PROP
));
190 rPropMap
.setProperty( PROP_CharEscapement
, sal_Int16(0));
191 rPropMap
.setProperty( PROP_CharEscapementHeight
, sal_Int8(100)); // 100%
194 float fWeight
= moBold
.value_or( false ) ? awt::FontWeight::BOLD
: awt::FontWeight::NORMAL
;
195 rPropMap
.setProperty( PROP_CharWeight
, fWeight
);
196 rPropMap
.setProperty( PROP_CharWeightAsian
, fWeight
);
197 rPropMap
.setProperty( PROP_CharWeightComplex
, fWeight
);
199 awt::FontSlant eSlant
= moItalic
.value_or( false ) ? awt::FontSlant_ITALIC
: awt::FontSlant_NONE
;
200 rPropMap
.setProperty( PROP_CharPosture
, eSlant
);
201 rPropMap
.setProperty( PROP_CharPostureAsian
, eSlant
);
202 rPropMap
.setProperty( PROP_CharPostureComplex
, eSlant
);
204 bool bUnderlineFillFollowText
= moUnderlineFillFollowText
.value_or( false );
205 if( moUnderline
.has_value() && maUnderlineColor
.isUsed() && !bUnderlineFillFollowText
)
207 rPropMap
.setProperty( PROP_CharUnderlineHasColor
, true);
208 rPropMap
.setProperty( PROP_CharUnderlineColor
, maUnderlineColor
.getColor( rFilter
.getGraphicHelper() ));
209 model::ComplexColor aComplexColor
= maUnderlineColor
.getComplexColor();
210 rPropMap
.setProperty( PROP_CharUnderlineComplexColor
, model::color::createXComplexColor(aComplexColor
));
214 rPropMap
.setProperty( PROP_CharUnderlineHasColor
, false);
215 rPropMap
.setProperty( PROP_CharUnderlineColor
, sal_Int32(-1));
218 if (maHighlightColor
.isUsed() && maHighlightColor
.getTransparency() != 100)
220 rPropMap
.setProperty(PROP_CharBackColor
, maHighlightColor
.getColor( rFilter
.getGraphicHelper() ));
221 model::ComplexColor aComplexColor
= maHighlightColor
.getComplexColor();
222 rPropMap
.setProperty(PROP_CharBackgroundComplexColor
, model::color::createXComplexColor(aComplexColor
));
225 rPropMap
.setProperty( PROP_CharBackColor
, sal_Int32(-1));
228 static void pushToGrabBag( PropertySet
& rPropSet
, const std::vector
<PropertyValue
>& aVectorOfPropertyValues
)
230 if (!rPropSet
.hasProperty(PROP_CharInteropGrabBag
) || aVectorOfPropertyValues
.empty())
232 Sequence
<PropertyValue
> aGrabBag
;
233 Any aAnyGrabBag
= rPropSet
.getAnyProperty(PROP_CharInteropGrabBag
);
234 aAnyGrabBag
>>= aGrabBag
;
236 rPropSet
.setAnyProperty(PROP_CharInteropGrabBag
, Any(comphelper::concatSequences(aGrabBag
, aVectorOfPropertyValues
)));
239 void TextCharacterProperties::pushToPropSet( PropertySet
& rPropSet
, const XmlFilterBase
& rFilter
) const
241 PropertyMap aPropMap
;
242 pushToPropMap( aPropMap
, rFilter
);
243 rPropSet
.setProperties( aPropMap
);
244 pushToGrabBag(rPropSet
, maTextEffectsProperties
);
247 float TextCharacterProperties::getCharHeightPoints( float fDefault
) const
249 return moHeight
.has_value() ? GetFontHeight( moHeight
.value() ) : fDefault
;
252 } // namespace oox::drawingml
254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */