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 <oox/drawingml/drawingmltypes.hxx>
21 #include <com/sun/star/awt/FontUnderline.hpp>
22 #include <com/sun/star/awt/FontStrikeout.hpp>
23 #include <com/sun/star/drawing/Hatch.hpp>
24 #include <com/sun/star/style/CaseMap.hpp>
25 #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
26 #include <o3tl/safeint.hxx>
27 #include <osl/diagnose.h>
28 #include <sax/tools/converter.hxx>
29 #include <oox/token/tokens.hxx>
30 
31 using ::com::sun::star::uno::Reference;
32 using ::com::sun::star::xml::sax::XFastAttributeList;
33 using namespace ::com::sun::star;
34 using namespace ::com::sun::star::drawing;
35 using namespace ::com::sun::star::geometry;
36 using namespace ::com::sun::star::style;
37 
38 namespace oox {
39 namespace drawingml {
40 
41 /** converts EMUs into 1/100th mmm */
GetCoordinate(sal_Int32 nValue)42 sal_Int32 GetCoordinate( sal_Int32 nValue )
43 {
44     nValue = o3tl::saturating_add<sal_Int32>(nValue, 180);
45     return nValue / 360;
46 }
47 
48 /** converts an emu string into 1/100th mmm */
GetCoordinate(const OUString & sValue)49 sal_Int32 GetCoordinate( const OUString& sValue )
50 {
51     sal_Int32 nRet = 0;
52     if( !::sax::Converter::convertNumber( nRet, sValue ) )
53         nRet = 0;
54     return GetCoordinate( nRet );
55 }
56 
57 /** converts 1/100mm to EMU */
GetPointFromCoordinate(sal_Int32 nValue)58 sal_Int32 GetPointFromCoordinate( sal_Int32 nValue )
59 {
60     return nValue * 360;
61 }
62 
63 /** converts a ST_Percentage % string into 1/1000th of % */
GetPercent(const OUString & sValue)64 sal_Int32 GetPercent( const OUString& sValue )
65 {
66     sal_Int32 nRet = 0;
67     if( !::sax::Converter::convertNumber( nRet, sValue ) )
68         nRet = 0;
69 
70     return nRet;
71 }
72 
GetPositiveFixedPercentage(const OUString & sValue)73 double GetPositiveFixedPercentage( const OUString& sValue )
74 {
75     double fPercent = sValue.toFloat() / 100000.;
76     return fPercent;
77 }
78 
79 /** converts the attributes from a CT_TLPoint into an awt Point with 1/1000% */
GetPointPercent(const Reference<XFastAttributeList> & xAttribs)80 awt::Point GetPointPercent( const Reference< XFastAttributeList >& xAttribs )
81 {
82     return awt::Point(GetPercent(xAttribs->getOptionalValue(XML_x)), GetPercent(xAttribs->getOptionalValue(XML_y)));
83 }
84 
85 /** converts the ST_TextFontSize to point */
GetTextSize(const OUString & sValue)86 float GetTextSize( const OUString& sValue )
87 {
88     float fRet = 0;
89     sal_Int32 nRet;
90     if( ::sax::Converter::convertNumber( nRet, sValue ) )
91         fRet = static_cast< float >( static_cast< double >( nRet ) / 100.0 );
92     return fRet;
93 }
94 
95 /** converts the ST_TextSpacingPoint to 1/100mm */
GetTextSpacingPoint(const OUString & sValue)96 sal_Int32 GetTextSpacingPoint( const OUString& sValue )
97 {
98     sal_Int32 nRet;
99     if( ::sax::Converter::convertNumber( nRet, sValue, (SAL_MIN_INT32 + 360) / 254, (SAL_MAX_INT32 - 360) / 254 ) )
100         nRet = GetTextSpacingPoint( nRet );
101     return nRet;
102 }
103 
GetTextSpacingPoint(sal_Int32 nValue)104 sal_Int32 GetTextSpacingPoint(sal_Int32 nValue)
105 {
106     if (nValue > 0)
107         nValue = (nValue * 254 + 360);
108     else if (nValue < 0)
109         nValue = (nValue * 254 - 360);
110     return nValue / 720;
111 }
112 
GetFontHeight(sal_Int32 nHeight)113 float GetFontHeight( sal_Int32 nHeight )
114 {
115     // convert 1/100 points to points
116     return static_cast< float >( nHeight / 100.0 );
117 }
118 
GetFontUnderline(sal_Int32 nToken)119 sal_Int16 GetFontUnderline( sal_Int32 nToken )
120 {
121     OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
122     switch( nToken )
123     {
124         case XML_none:              return awt::FontUnderline::NONE;
125         case XML_dash:              return awt::FontUnderline::DASH;
126         case XML_dashHeavy:         return awt::FontUnderline::BOLDDASH;
127         case XML_dashLong:          return awt::FontUnderline::LONGDASH;
128         case XML_dashLongHeavy:     return awt::FontUnderline::BOLDLONGDASH;
129         case XML_dbl:               return awt::FontUnderline::DOUBLE;
130         case XML_dotDash:           return awt::FontUnderline::DASHDOT;
131         case XML_dotDashHeavy:      return awt::FontUnderline::BOLDDASHDOT;
132         case XML_dotDotDash:        return awt::FontUnderline::DASHDOTDOT;
133         case XML_dotDotDashHeavy:   return awt::FontUnderline::BOLDDASHDOTDOT;
134         case XML_dotted:            return awt::FontUnderline::DOTTED;
135         case XML_dottedHeavy:       return awt::FontUnderline::BOLDDOTTED;
136         case XML_heavy:             return awt::FontUnderline::BOLD;
137         case XML_sng:               return awt::FontUnderline::SINGLE;
138         case XML_wavy:              return awt::FontUnderline::WAVE;
139         case XML_wavyDbl:           return awt::FontUnderline::DOUBLEWAVE;
140         case XML_wavyHeavy:         return awt::FontUnderline::BOLDWAVE;
141 //        case XML_words:             // TODO
142     }
143     return awt::FontUnderline::DONTKNOW;
144 }
145 
GetFontStrikeout(sal_Int32 nToken)146 sal_Int16 GetFontStrikeout( sal_Int32 nToken )
147 {
148     OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
149     switch( nToken )
150     {
151         case XML_dblStrike: return awt::FontStrikeout::DOUBLE;
152         case XML_noStrike:  return awt::FontStrikeout::NONE;
153         case XML_sngStrike: return awt::FontStrikeout::SINGLE;
154     }
155     return awt::FontStrikeout::DONTKNOW;
156 }
157 
GetCaseMap(sal_Int32 nToken)158 sal_Int16 GetCaseMap( sal_Int32 nToken )
159 {
160     switch( nToken )
161     {
162         case XML_all:   return CaseMap::UPPERCASE;
163         case XML_small: return CaseMap::SMALLCAPS;
164     }
165     return CaseMap::NONE;
166 }
167 
168 /** converts a paragraph align to a ParaAdjust */
GetParaAdjust(sal_Int32 nAlign)169 ParagraphAdjust GetParaAdjust( sal_Int32 nAlign )
170 {
171     OSL_ASSERT((nAlign & sal_Int32(0xFFFF0000))==0);
172     ParagraphAdjust nEnum;
173     switch( nAlign )
174     {
175     case XML_ctr:
176         nEnum = ParagraphAdjust_CENTER;
177         break;
178     case XML_just:
179     case XML_justLow:
180         nEnum = ParagraphAdjust_BLOCK;
181         break;
182     case XML_r:
183         nEnum = ParagraphAdjust_RIGHT;
184         break;
185     case XML_thaiDist:
186     case XML_dist:
187         nEnum = ParagraphAdjust_STRETCH;
188         break;
189     case XML_l:
190     default:
191         nEnum = ParagraphAdjust_LEFT;
192         break;
193     }
194     return nEnum;
195 }
196 
GetTextVerticalAdjust(sal_Int32 nToken)197 TextVerticalAdjust GetTextVerticalAdjust( sal_Int32 nToken )
198 {
199     TextVerticalAdjust aVertAdjust;
200     switch( nToken )
201     {
202     case XML_b:
203         aVertAdjust = TextVerticalAdjust_BOTTOM;
204         break;
205     case XML_dist:
206     case XML_just:
207     case XML_ctr:
208         aVertAdjust = TextVerticalAdjust_CENTER;
209         break;
210     case XML_t:
211     default:
212         aVertAdjust = TextVerticalAdjust_TOP;
213         break;
214     }
215     return aVertAdjust;
216 }
217 
GetTextVerticalAdjust(TextVerticalAdjust eAdjust)218 const char* GetTextVerticalAdjust( TextVerticalAdjust eAdjust )
219 {
220     const char* sVerticalAdjust = nullptr;
221     switch( eAdjust )
222     {
223         case TextVerticalAdjust_BOTTOM:
224             sVerticalAdjust = "b";
225             break;
226         case TextVerticalAdjust_CENTER:
227             sVerticalAdjust = "ctr";
228             break;
229         case TextVerticalAdjust_TOP:
230         default:
231             sVerticalAdjust = "t";
232             break;
233     }
234     return sVerticalAdjust;
235 }
236 
GetTabAlign(sal_Int32 aToken)237 TabAlign GetTabAlign( sal_Int32 aToken )
238 {
239     OSL_ASSERT((aToken & sal_Int32(0xFFFF0000))==0);
240     TabAlign nEnum;
241     switch( aToken )
242     {
243     case XML_ctr:
244         nEnum = TabAlign_CENTER;
245         break;
246     case XML_dec:
247         nEnum = TabAlign_DECIMAL;
248         break;
249     case XML_l:
250         nEnum = TabAlign_LEFT;
251         break;
252     case XML_r:
253         nEnum = TabAlign_RIGHT;
254         break;
255     default:
256         nEnum = TabAlign_DEFAULT;
257         break;
258     }
259     return nEnum;
260 }
261 
GetHatchPattern(const drawing::Hatch & rHatch)262 const char* GetHatchPattern( const drawing::Hatch& rHatch )
263 {
264     const char* sPattern = nullptr;
265     const sal_Int32 nAngle = rHatch.Angle > 1800 ? rHatch.Angle - 1800 : rHatch.Angle;
266     // Angle ~ 0° (horizontal)
267     if( (nAngle >= 0 && nAngle < 225) || nAngle >= 1575 )
268     {
269         switch( rHatch.Style )
270         {
271             case drawing::HatchStyle_SINGLE:
272             {
273                 if( rHatch.Distance < 75 )
274                     sPattern = "ltHorz";
275                 else
276                     sPattern = "horz";
277 
278                 break;
279             }
280             case drawing::HatchStyle_DOUBLE:
281             case drawing::HatchStyle_TRIPLE:
282             {
283                 if( rHatch.Distance < 75 )
284                     sPattern = "smGrid";
285                 else
286                     sPattern = "lgGrid";
287 
288                 break;
289             }
290             default: break;
291         }
292     }
293     // Angle ~ 45° (upward diagonal)
294     else if( nAngle < 675 )
295     {
296         switch( rHatch.Style )
297         {
298             case drawing::HatchStyle_SINGLE:
299             {
300                 if( rHatch.Distance < 75 )
301                     sPattern = "ltUpDiag";
302                 else
303                     sPattern = "wdUpDiag";
304 
305                 break;
306             }
307             case drawing::HatchStyle_DOUBLE:
308             case drawing::HatchStyle_TRIPLE:
309             {
310                 if( rHatch.Distance < 75 )
311                     sPattern = "smCheck";
312                 else
313                     sPattern = "openDmnd";
314 
315                 break;
316             }
317             default: break;
318         }
319     }
320     // Angle ~ 90° (vertical)
321     else if( nAngle < 1125 )
322     {
323         switch( rHatch.Style )
324         {
325             case drawing::HatchStyle_SINGLE:
326             {
327                 // dkVert is imported as Distance = 25, ltVert as Distance = 50, export them accordingly.
328                 if( rHatch.Distance < 50 )
329                     sPattern = "dkVert";
330                 else if( rHatch.Distance < 75 )
331                     sPattern = "ltVert";
332                 else
333                     sPattern = "vert";
334 
335                 break;
336             }
337             case drawing::HatchStyle_DOUBLE:
338             case drawing::HatchStyle_TRIPLE:
339             {
340                 if( rHatch.Distance < 75 )
341                     sPattern = "smGrid";
342                 else
343                     sPattern = "lgGrid";
344 
345                 break;
346             }
347             default: break;
348         }
349     }
350     // Angle ~ 135° (downward diagonal)
351     else if( nAngle < 1575 )
352     {
353         switch( rHatch.Style )
354         {
355             case drawing::HatchStyle_SINGLE:
356             {
357                 if( rHatch.Distance < 75 )
358                     sPattern = "ltDnDiag";
359                 else
360                     sPattern = "wdDnDiag";
361 
362                 break;
363             }
364             case drawing::HatchStyle_DOUBLE:
365             case drawing::HatchStyle_TRIPLE:
366             {
367                 if( rHatch.Distance < 75 )
368                     sPattern = "smCheck";
369                 else
370                     sPattern = "openDmnd";
371 
372                 break;
373             }
374             default: break;
375         }
376     }
377     return sPattern;
378 }
379 
380 /** converts the attributes from a CT_RelativeRect to an IntegerRectangle2D */
GetRelativeRect(const Reference<XFastAttributeList> & xAttribs)381 IntegerRectangle2D GetRelativeRect( const Reference< XFastAttributeList >& xAttribs )
382 {
383     IntegerRectangle2D r;
384 
385     r.X1 = xAttribs->getOptionalValue( XML_l ).toInt32();
386     r.Y1 = xAttribs->getOptionalValue( XML_t ).toInt32();
387     r.X2 = xAttribs->getOptionalValue( XML_r ).toInt32();
388     r.Y2 = xAttribs->getOptionalValue( XML_b ).toInt32();
389 
390     return r;
391 }
392 
393 /** converts the attributes from a CT_Size2D into an awt Size with 1/100thmm */
GetSize2D(const Reference<XFastAttributeList> & xAttribs)394 awt::Size GetSize2D( const Reference< XFastAttributeList >& xAttribs )
395 {
396     return awt::Size( GetCoordinate( xAttribs->getOptionalValue( XML_cx ) ), GetCoordinate( xAttribs->getOptionalValue( XML_cy ) ) );
397 }
398 
GetIndexRange(const Reference<XFastAttributeList> & xAttributes)399 IndexRange GetIndexRange( const Reference< XFastAttributeList >& xAttributes )
400 {
401     IndexRange range;
402     range.start = xAttributes->getOptionalValue( XML_st ).toInt32();
403     range.end = xAttributes->getOptionalValue( XML_end ).toInt32();
404     return range;
405 }
406 
407 } // namespace drawingml
408 } // namespace oox
409 
410 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
411