bump product version to 7.6.3.2-android
[LibreOffice.git] / xmloff / source / style / TransGradientStyle.cxx
blob74b7670c024f1ff06ceef27c09f2c473936f4df9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <TransGradientStyle.hxx>
22 #include <com/sun/star/awt/Gradient2.hpp>
24 #include <basegfx/utils/bgradient.hxx>
25 #include <comphelper/documentconstants.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/ustring.hxx>
28 #include <sal/log.hxx>
29 #include <sax/tools/converter.hxx>
30 #include <tools/color.hxx>
31 #include <xmloff/namespacemap.hxx>
32 #include <xmloff/xmlement.hxx>
33 #include <xmloff/xmlexp.hxx>
34 #include <xmloff/xmlimp.hxx>
35 #include <xmloff/xmlnamespace.hxx>
36 #include <xmloff/xmltkmap.hxx>
37 #include <xmloff/xmluconv.hxx>
38 #include <docmodel/uno/UnoGradientTools.hxx>
40 using namespace ::com::sun::star;
42 using namespace ::xmloff::token;
44 SvXMLEnumMapEntry<awt::GradientStyle> const pXML_GradientStyle_Enum[] =
46 { XML_LINEAR, awt::GradientStyle_LINEAR },
47 { XML_GRADIENTSTYLE_AXIAL, awt::GradientStyle_AXIAL },
48 { XML_GRADIENTSTYLE_RADIAL, awt::GradientStyle_RADIAL },
49 { XML_GRADIENTSTYLE_ELLIPSOID, awt::GradientStyle_ELLIPTICAL },
50 { XML_GRADIENTSTYLE_SQUARE, awt::GradientStyle_SQUARE },
51 { XML_GRADIENTSTYLE_RECTANGULAR, awt::GradientStyle_RECT },
52 { XML_TOKEN_INVALID, awt::GradientStyle(0) }
55 // Import
57 XMLTransGradientStyleImport::XMLTransGradientStyleImport( SvXMLImport& rImp )
58 : rImport(rImp)
62 void XMLTransGradientStyleImport::importXML(
63 const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
64 uno::Any& rValue,
65 OUString& rStrName )
67 OUString aDisplayName;
69 awt::Gradient2 aGradient;
70 aGradient.XOffset = 0;
71 aGradient.YOffset = 0;
72 aGradient.StartIntensity = 100;
73 aGradient.EndIntensity = 100;
74 aGradient.Angle = 0;
75 aGradient.Border = 0;
77 for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
79 sal_Int32 nTmpValue;
81 switch( aIter.getToken() )
83 case XML_ELEMENT(DRAW, XML_NAME):
85 rStrName = aIter.toString();
87 break;
88 case XML_ELEMENT(DRAW, XML_DISPLAY_NAME):
90 aDisplayName = aIter.toString();
92 break;
93 case XML_ELEMENT(DRAW, XML_STYLE):
95 SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum );
97 break;
98 case XML_ELEMENT(DRAW, XML_CX):
99 ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
100 aGradient.XOffset = sal::static_int_cast< sal_Int16 >(nTmpValue);
101 break;
102 case XML_ELEMENT(DRAW, XML_CY):
103 ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
104 aGradient.YOffset = sal::static_int_cast< sal_Int16 >(nTmpValue);
105 break;
106 case XML_ELEMENT(DRAW, XML_START):
108 sal_Int32 aStartTransparency;
109 ::sax::Converter::convertPercent( aStartTransparency, aIter.toView() );
111 sal_uInt8 n = sal::static_int_cast< sal_uInt8 >(
112 ( (100 - aStartTransparency) * 255 ) / 100 );
114 Color aColor( n, n, n );
115 aGradient.StartColor = static_cast<sal_Int32>( aColor );
117 break;
118 case XML_ELEMENT(DRAW, XML_END):
120 sal_Int32 aEndTransparency;
121 ::sax::Converter::convertPercent( aEndTransparency, aIter.toView() );
123 sal_uInt8 n = sal::static_int_cast< sal_uInt8 >(
124 ( (100 - aEndTransparency) * 255 ) / 100 );
126 Color aColor( n, n, n );
127 aGradient.EndColor = static_cast<sal_Int32>( aColor );
129 break;
130 case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE):
132 auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT));
133 bool const bSuccess =
134 ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(),
135 // tdf#89475 try to detect borked OOo angles
136 (cmp12 < 0) || (cmp12 == 0
137 && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x)
138 // also for AOO 4.x, assume there won't ever be a 4.2
139 || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x)));
140 SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle");
142 break;
143 case XML_ELEMENT(DRAW, XML_BORDER):
144 ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
145 aGradient.Border = sal::static_int_cast< sal_Int16 >(nTmpValue);
146 break;
148 default:
149 XMLOFF_WARN_UNKNOWN("xmloff.style", aIter);
153 rValue <<= aGradient;
155 if( !aDisplayName.isEmpty() )
157 rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName,
158 aDisplayName );
159 rStrName = aDisplayName;
163 // Export
165 XMLTransGradientStyleExport::XMLTransGradientStyleExport( SvXMLExport& rExp )
166 : rExport(rExp)
170 void XMLTransGradientStyleExport::exportXML(
171 const OUString& rStrName,
172 const uno::Any& rValue )
174 // MCGR: We try to write the gradient so, that applications without multi-color gradient support
175 // can render it as best as possible.
176 // This is similar to XMLGradientStyleExport::exportXML(). For details see there.
177 if( rStrName.isEmpty() )
178 return;
179 if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>())
180 return;
182 basegfx::BGradient aGradient = model::gradient::getFromAny(rValue);
184 aGradient.tryToConvertToAxial();
186 aGradient.tryToRecreateBorder(nullptr);
188 OUString aStrValue;
189 OUStringBuffer aOut;
191 // Style
192 if (!SvXMLUnitConverter::convertEnum(aOut, aGradient.GetGradientStyle(),
193 pXML_GradientStyle_Enum))
194 return;
196 // Name
197 bool bEncoded = false;
198 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME,
199 rExport.EncodeStyleName( rStrName,
200 &bEncoded ) );
201 if( bEncoded )
202 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME,
203 rStrName );
205 aStrValue = aOut.makeStringAndClear();
206 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue );
208 // Center x/y
209 if (awt::GradientStyle_LINEAR != aGradient.GetGradientStyle()
210 && awt::GradientStyle_AXIAL != aGradient.GetGradientStyle())
212 ::sax::Converter::convertPercent(aOut, aGradient.GetXOffset());
213 aStrValue = aOut.makeStringAndClear();
214 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue );
216 ::sax::Converter::convertPercent(aOut, aGradient.GetYOffset());
217 aStrValue = aOut.makeStringAndClear();
218 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue );
221 // LO uses a gray color as transparency. ODF uses opacity in range [0%,100%].
222 // Default 100% opacity.
223 double fOpacityStartPerc = 100.0;
224 double fOpacityEndPerc = 100.0;
225 if (!aGradient.GetColorStops().empty())
227 fOpacityStartPerc
228 = (1.0 - aGradient.GetColorStops().front().getStopColor().getRed()) * 100.0;
229 fOpacityEndPerc = (1.0 - aGradient.GetColorStops().back().getStopColor().getRed()) * 100.0;
232 // Opacity start
233 ::sax::Converter::convertPercent(aOut, static_cast<sal_Int32>(std::lround(fOpacityStartPerc)));
234 aStrValue = aOut.makeStringAndClear();
235 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue );
237 // Opacity end
238 ::sax::Converter::convertPercent( aOut, static_cast<sal_Int32>(std::lround(fOpacityEndPerc)));
239 aStrValue = aOut.makeStringAndClear();
240 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue );
242 // Angle
243 if (awt::GradientStyle_RADIAL != aGradient.GetGradientStyle())
245 ::sax::Converter::convertAngle(aOut, aGradient.GetAngle().get(),
246 rExport.getSaneDefaultVersion());
247 aStrValue = aOut.makeStringAndClear();
248 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue );
251 // Border
252 ::sax::Converter::convertPercent(aOut, aGradient.GetBorder());
253 aStrValue = aOut.makeStringAndClear();
254 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue );
256 // ctor writes start tag. End-tag is written by destructor at block end.
257 SvXMLElementExport rElem(rExport, XML_NAMESPACE_DRAW, XML_OPACITY, true, false);
259 // Write child elements <loext:opacity-stop>
260 // Do not export in standard ODF 1.3 or older.
261 if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
262 return;
263 if (aGradient.GetColorStops().empty())
264 return;
266 double fPreviousOffset = 0.0;
267 for (auto& aCandidate : aGradient.GetColorStops())
269 // Attribute svg:offset. Make sure offsets are increasing.
270 double fOffset = std::clamp<double>(aCandidate.getStopOffset(), 0.0, 1.0);
271 if (fOffset < fPreviousOffset)
272 fOffset = fPreviousOffset;
273 rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset));
274 fPreviousOffset = fOffset;
276 // Attribute svg:stop-opacity, data type zeroToOneDecimal
277 double fOpacity = std::clamp<double>(1.0 - aCandidate.getStopColor().getRed(), 0.0, 1.0);
278 rExport.AddAttribute(XML_NAMESPACE_SVG, XML_STOP_OPACITY, OUString::number(fOpacity));
280 // write opacity stop element
281 SvXMLElementExport aStopElement(rExport, XML_NAMESPACE_LO_EXT, XML_OPACITY_STOP, true, true);
285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */