LibreOffice Module xmloff (master) 1
TransGradientStyle.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
22#include <com/sun/star/awt/Gradient2.hpp>
23
26#include <rtl/ustrbuf.hxx>
27#include <rtl/ustring.hxx>
28#include <sal/log.hxx>
30#include <tools/color.hxx>
32#include <xmloff/xmlement.hxx>
33#include <xmloff/xmlexp.hxx>
34#include <xmloff/xmlimp.hxx>
36#include <xmloff/xmltkmap.hxx>
37#include <xmloff/xmluconv.hxx>
38
39using namespace ::com::sun::star;
40
41using namespace ::xmloff::token;
42
44{
45 { XML_LINEAR, awt::GradientStyle_LINEAR },
46 { XML_GRADIENTSTYLE_AXIAL, awt::GradientStyle_AXIAL },
47 { XML_GRADIENTSTYLE_RADIAL, awt::GradientStyle_RADIAL },
48 { XML_GRADIENTSTYLE_ELLIPSOID, awt::GradientStyle_ELLIPTICAL },
49 { XML_GRADIENTSTYLE_SQUARE, awt::GradientStyle_SQUARE },
50 { XML_GRADIENTSTYLE_RECTANGULAR, awt::GradientStyle_RECT },
51 { XML_TOKEN_INVALID, awt::GradientStyle(0) }
52};
53
54// Import
55
57 : rImport(rImp)
58{
59}
60
62 const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
63 uno::Any& rValue,
64 OUString& rStrName )
65{
66 OUString aDisplayName;
67
68 awt::Gradient2 aGradient;
69 aGradient.XOffset = 0;
70 aGradient.YOffset = 0;
71 aGradient.StartIntensity = 100;
72 aGradient.EndIntensity = 100;
73 aGradient.Angle = 0;
74 aGradient.Border = 0;
75
76 for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
77 {
78 sal_Int32 nTmpValue;
79
80 switch( aIter.getToken() )
81 {
83 {
84 rStrName = aIter.toString();
85 }
86 break;
88 {
89 aDisplayName = aIter.toString();
90 }
91 break;
93 {
94 SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum );
95 }
96 break;
97 case XML_ELEMENT(DRAW, XML_CX):
98 ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
99 aGradient.XOffset = sal::static_int_cast< sal_Int16 >(nTmpValue);
100 break;
101 case XML_ELEMENT(DRAW, XML_CY):
102 ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
103 aGradient.YOffset = sal::static_int_cast< sal_Int16 >(nTmpValue);
104 break;
106 {
107 sal_Int32 aStartTransparency;
108 ::sax::Converter::convertPercent( aStartTransparency, aIter.toView() );
109
110 sal_uInt8 n = sal::static_int_cast< sal_uInt8 >(
111 ( (100 - aStartTransparency) * 255 ) / 100 );
112
113 Color aColor( n, n, n );
114 aGradient.StartColor = static_cast<sal_Int32>( aColor );
115 }
116 break;
117 case XML_ELEMENT(DRAW, XML_END):
118 {
119 sal_Int32 aEndTransparency;
120 ::sax::Converter::convertPercent( aEndTransparency, aIter.toView() );
121
122 sal_uInt8 n = sal::static_int_cast< sal_uInt8 >(
123 ( (100 - aEndTransparency) * 255 ) / 100 );
124
125 Color aColor( n, n, n );
126 aGradient.EndColor = static_cast<sal_Int32>( aColor );
127 }
128 break;
130 {
131 auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT));
132 bool const bSuccess =
133 ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(),
134 // tdf#89475 try to detect borked OOo angles
135 (cmp12 < 0) || (cmp12 == 0
136 && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x)
137 // also for AOO 4.x, assume there won't ever be a 4.2
138 || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x)));
139 SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle");
140 }
141 break;
143 ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
144 aGradient.Border = sal::static_int_cast< sal_Int16 >(nTmpValue);
145 break;
146
147 default:
148 XMLOFF_WARN_UNKNOWN("xmloff.style", aIter);
149 }
150 }
151
152 rValue <<= aGradient;
153
154 if( !aDisplayName.isEmpty() )
155 {
156 rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName,
157 aDisplayName );
158 rStrName = aDisplayName;
159 }
160}
161
162// Export
163
165 : rExport(rExp)
166{
167}
168
170 const OUString& rStrName,
171 const uno::Any& rValue )
172{
173 // MCGR: We try to write the gradient so, that applications without multi-color gradient support
174 // can render it as best as possible.
175 // This is similar to XMLGradientStyleExport::exportXML(). For details see there.
176 if( rStrName.isEmpty() )
177 return;
178 if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>())
179 return;
180
181 basegfx::BGradient aGradient(rValue);
182
183 aGradient.tryToConvertToAxial();
184
185 aGradient.tryToRecreateBorder(nullptr);
186
187 OUString aStrValue;
188 OUStringBuffer aOut;
189
190 // Style
193 return;
194
195 // Name
196 bool bEncoded = false;
198 rExport.EncodeStyleName( rStrName,
199 &bEncoded ) );
200 if( bEncoded )
202 rStrName );
203
204 aStrValue = aOut.makeStringAndClear();
206
207 // Center x/y
208 if (awt::GradientStyle_LINEAR != aGradient.GetGradientStyle()
209 && awt::GradientStyle_AXIAL != aGradient.GetGradientStyle())
210 {
212 aStrValue = aOut.makeStringAndClear();
214
216 aStrValue = aOut.makeStringAndClear();
218 }
219
220 // LO uses a gray color as transparency. ODF uses opacity in range [0%,100%].
221 // Default 100% opacity.
222 double fOpacityStartPerc = 100.0;
223 double fOpacityEndPerc = 100.0;
224 if (!aGradient.GetColorStops().empty())
225 {
226 fOpacityStartPerc
227 = (1.0 - aGradient.GetColorStops().front().getStopColor().getRed()) * 100.0;
228 fOpacityEndPerc = (1.0 - aGradient.GetColorStops().back().getStopColor().getRed()) * 100.0;
229 }
230
231 // Opacity start
232 ::sax::Converter::convertPercent(aOut, static_cast<sal_Int32>(std::lround(fOpacityStartPerc)));
233 aStrValue = aOut.makeStringAndClear();
235
236 // Opacity end
237 ::sax::Converter::convertPercent( aOut, static_cast<sal_Int32>(std::lround(fOpacityEndPerc)));
238 aStrValue = aOut.makeStringAndClear();
240
241 // Angle
242 if (awt::GradientStyle_RADIAL != aGradient.GetGradientStyle())
243 {
244 ::sax::Converter::convertAngle(aOut, aGradient.GetAngle().get(),
246 aStrValue = aOut.makeStringAndClear();
248 }
249
250 // Border
252 aStrValue = aOut.makeStringAndClear();
254
255 // ctor writes start tag. End-tag is written by destructor at block end.
257
258 // Write child elements <loext:opacity-stop>
259 // Do not export in standard ODF 1.3 or older.
261 return;
262 if (aGradient.GetColorStops().empty())
263 return;
264
265 double fPreviousOffset = 0.0;
266 for (auto& aCandidate : aGradient.GetColorStops())
267 {
268 // Attribute svg:offset. Make sure offsets are increasing.
269 double fOffset = std::clamp<double>(aCandidate.getStopOffset(), 0.0, 1.0);
270 if (fOffset < fPreviousOffset)
271 fOffset = fPreviousOffset;
272 rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset));
273 fPreviousOffset = fOffset;
274
275 // Attribute svg:stop-opacity, data type zeroToOneDecimal
276 double fOpacity = std::clamp<double>(1.0 - aCandidate.getStopColor().getRed(), 0.0, 1.0);
277 rExport.AddAttribute(XML_NAMESPACE_SVG, XML_STOP_OPACITY, OUString::number(fOpacity));
278
279 // write opacity stop element
281 }
282}
283
284/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SvXMLEnumMapEntry< awt::GradientStyle > const pXML_GradientStyle_Enum[]
void AddAttribute(sal_uInt16 nPrefix, const OUString &rName, const OUString &rValue)
Definition: xmlexp.cxx:907
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
returns the deterministic version for odf export
Definition: xmlexp.cxx:2264
OUString EncodeStyleName(const OUString &rName, bool *pEncoded=nullptr) const
Definition: xmlexp.cxx:1934
static bool convertEnum(EnumT &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< EnumT > *pMap)
convert string to enum using given enum map, if the enum is not found in the map, this method will re...
Definition: xmluconv.hxx:145
void exportXML(const OUString &rStrName, const css::uno::Any &rValue)
XMLTransGradientStyleExport(SvXMLExport &rExport)
void importXML(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Any &rValue, OUString &rStrName)
XMLTransGradientStyleImport(SvXMLImport &rImport)
void tryToRecreateBorder(basegfx::BColorStops *pAssociatedTransparencyStops=nullptr)
sal_uInt16 GetBorder() const
sal_uInt16 GetXOffset() const
const basegfx::BColorStops & GetColorStops() const
void tryToConvertToAxial()
Degree10 GetAngle() const
css::awt::GradientStyle GetGradientStyle() const
sal_uInt16 GetYOffset() const
static bool convertPercent(sal_Int32 &rValue, std::u16string_view rString)
static void convertAngle(OUStringBuffer &rBuffer, sal_Int16 nAngle, SvtSaveOptions::ODFSaneDefaultVersion nVersion)
constexpr OUStringLiteral ODFVER_012_TEXT
DRAW
sal_Int64 n
#define SAL_INFO_IF(condition, area, stream)
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
Handling of tokens in XML:
@ XML_GRADIENTSTYLE_ELLIPSOID
Definition: xmltoken.hxx:985
@ XML_GRADIENTSTYLE_AXIAL
Definition: xmltoken.hxx:984
@ XML_GRADIENTSTYLE_SQUARE
Definition: xmltoken.hxx:988
@ XML_GRADIENTSTYLE_RECTANGULAR
Definition: xmltoken.hxx:987
@ XML_GRADIENTSTYLE_RADIAL
Definition: xmltoken.hxx:986
UNDERLYING_TYPE get() const
unsigned char sal_uInt8
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:97
constexpr sal_uInt16 XML_NAMESPACE_DRAW
constexpr sal_uInt16 XML_NAMESPACE_SVG
constexpr sal_uInt16 XML_NAMESPACE_LO_EXT