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 
20 #include <TransGradientStyle.hxx>
21 
22 #include <com/sun/star/awt/Gradient.hpp>
23 
24 #include <sax/tools/converter.hxx>
25 #include <comphelper/documentconstants.hxx>
26 
27 #include <xmloff/namespacemap.hxx>
28 #include <xmloff/xmluconv.hxx>
29 #include <xmloff/xmlnamespace.hxx>
30 #include <rtl/ustrbuf.hxx>
31 #include <rtl/ustring.hxx>
32 #include <sal/log.hxx>
33 #include <tools/color.hxx>
34 #include <xmloff/xmltkmap.hxx>
35 #include <xmloff/xmlexp.hxx>
36 #include <xmloff/xmlimp.hxx>
37 #include <xmloff/xmlement.hxx>
38 
39 using namespace ::com::sun::star;
40 
41 using namespace ::xmloff::token;
42 
43 SvXMLEnumMapEntry<awt::GradientStyle> const pXML_GradientStyle_Enum[] =
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 
XMLTransGradientStyleImport(SvXMLImport & rImp)56 XMLTransGradientStyleImport::XMLTransGradientStyleImport( SvXMLImport& rImp )
57     : rImport(rImp)
58 {
59 }
60 
~XMLTransGradientStyleImport()61 XMLTransGradientStyleImport::~XMLTransGradientStyleImport()
62 {
63 }
64 
importXML(const uno::Reference<xml::sax::XFastAttributeList> & xAttrList,uno::Any & rValue,OUString & rStrName)65 void XMLTransGradientStyleImport::importXML(
66     const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
67     uno::Any& rValue,
68     OUString& rStrName )
69 {
70     OUString aDisplayName;
71 
72     awt::Gradient aGradient;
73     aGradient.XOffset = 0;
74     aGradient.YOffset = 0;
75     aGradient.StartIntensity = 100;
76     aGradient.EndIntensity = 100;
77     aGradient.Angle = 0;
78     aGradient.Border = 0;
79 
80     for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
81     {
82         sal_Int32 nTmpValue;
83 
84         switch( aIter.getToken() )
85         {
86         case XML_ELEMENT(DRAW, XML_NAME):
87             {
88                 rStrName = aIter.toString();
89             }
90             break;
91         case XML_ELEMENT(DRAW, XML_DISPLAY_NAME):
92             {
93                 aDisplayName = aIter.toString();
94             }
95             break;
96         case XML_ELEMENT(DRAW, XML_STYLE):
97             {
98                 SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum );
99             }
100             break;
101         case XML_ELEMENT(DRAW, XML_CX):
102             ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
103             aGradient.XOffset = sal::static_int_cast< sal_Int16 >(nTmpValue);
104             break;
105         case XML_ELEMENT(DRAW, XML_CY):
106             ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
107             aGradient.YOffset = sal::static_int_cast< sal_Int16 >(nTmpValue);
108             break;
109         case XML_ELEMENT(DRAW, XML_START):
110             {
111                 sal_Int32 aStartTransparency;
112                 ::sax::Converter::convertPercent( aStartTransparency, aIter.toView() );
113 
114                 sal_uInt8 n = sal::static_int_cast< sal_uInt8 >(
115                     ( (100 - aStartTransparency) * 255 ) / 100 );
116 
117                 Color aColor( n, n, n );
118                 aGradient.StartColor = static_cast<sal_Int32>( aColor );
119             }
120             break;
121         case XML_ELEMENT(DRAW, XML_END):
122             {
123                 sal_Int32 aEndTransparency;
124                 ::sax::Converter::convertPercent( aEndTransparency, aIter.toView() );
125 
126                 sal_uInt8 n = sal::static_int_cast< sal_uInt8 >(
127                     ( (100 - aEndTransparency) * 255 ) / 100 );
128 
129                 Color aColor( n, n, n );
130                 aGradient.EndColor = static_cast<sal_Int32>( aColor );
131             }
132             break;
133         case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE):
134             {
135                 auto const cmp12(rImport.GetODFVersion().compareTo(u"" ODFVER_012_TEXT));
136                 bool const bSuccess =
137                     ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(),
138                         // tdf#89475 try to detect borked OOo angles
139                         (cmp12 < 0) || (cmp12 == 0
140                             && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x)
141                                 // also for AOO 4.x, assume there won't ever be a 4.2
142                                 || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x)));
143                 SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle");
144             }
145             break;
146         case XML_ELEMENT(DRAW, XML_BORDER):
147             ::sax::Converter::convertPercent( nTmpValue, aIter.toView() );
148             aGradient.Border = sal::static_int_cast< sal_Int16 >(nTmpValue);
149             break;
150 
151         default:
152             XMLOFF_WARN_UNKNOWN("xmloff.style", aIter);
153         }
154     }
155 
156     rValue <<= aGradient;
157 
158     if( !aDisplayName.isEmpty() )
159     {
160         rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName,
161                                      aDisplayName );
162         rStrName = aDisplayName;
163     }
164 }
165 
166 // Export
167 
XMLTransGradientStyleExport(SvXMLExport & rExp)168 XMLTransGradientStyleExport::XMLTransGradientStyleExport( SvXMLExport& rExp )
169     : rExport(rExp)
170 {
171 }
172 
~XMLTransGradientStyleExport()173 XMLTransGradientStyleExport::~XMLTransGradientStyleExport()
174 {
175 }
176 
exportXML(const OUString & rStrName,const uno::Any & rValue)177 void XMLTransGradientStyleExport::exportXML(
178     const OUString& rStrName,
179     const uno::Any& rValue )
180 {
181     awt::Gradient aGradient;
182 
183     if( rStrName.isEmpty() )
184         return;
185 
186     if( !(rValue >>= aGradient) )
187         return;
188 
189     OUString aStrValue;
190     OUStringBuffer aOut;
191 
192     // Style
193     if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.Style, pXML_GradientStyle_Enum ) )
194         return;
195 
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 );
204 
205     aStrValue = aOut.makeStringAndClear();
206     rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue );
207 
208     // Center x/y
209     if( aGradient.Style != awt::GradientStyle_LINEAR &&
210         aGradient.Style != awt::GradientStyle_AXIAL   )
211     {
212         ::sax::Converter::convertPercent(aOut, aGradient.XOffset);
213         aStrValue = aOut.makeStringAndClear();
214         rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue );
215 
216         ::sax::Converter::convertPercent(aOut, aGradient.YOffset);
217         aStrValue = aOut.makeStringAndClear();
218         rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue );
219     }
220 
221     // Transparency start
222     Color aColor(ColorTransparency, aGradient.StartColor);
223     sal_Int32 aStartValue = 100 - static_cast<sal_Int32>(((aColor.GetRed() + 1) * 100) / 255);
224     ::sax::Converter::convertPercent( aOut, aStartValue );
225     aStrValue = aOut.makeStringAndClear();
226     rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue );
227 
228     // Transparency end
229     aColor = Color(ColorTransparency, aGradient.EndColor);
230     sal_Int32 aEndValue = 100 - static_cast<sal_Int32>(((aColor.GetRed() + 1) * 100) / 255);
231     ::sax::Converter::convertPercent( aOut, aEndValue );
232     aStrValue = aOut.makeStringAndClear();
233     rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue );
234 
235     // Angle
236     if( aGradient.Style != awt::GradientStyle_RADIAL )
237     {
238         ::sax::Converter::convertAngle(aOut, aGradient.Angle, rExport.getSaneDefaultVersion());
239         aStrValue = aOut.makeStringAndClear();
240         rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue );
241     }
242 
243     // Border
244     ::sax::Converter::convertPercent( aOut, aGradient.Border );
245     aStrValue = aOut.makeStringAndClear();
246     rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue );
247 
248     // Do Write
249     SvXMLElementExport rElem( rExport,
250                               XML_NAMESPACE_DRAW, XML_OPACITY,
251                               true, false );
252 }
253 
254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
255