xref: /core/oox/source/drawingml/drawingmltypes.cxx (revision 6e3ed71f906c3571a6b6efb5335c26807b566a42)
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 
27 #include <o3tl/string_view.hxx>
28 #include <optional>
29 #include <osl/diagnose.h>
30 #include <sax/tools/converter.hxx>
31 #include <oox/token/tokens.hxx>
32 
33 using ::com::sun::star::uno::Reference;
34 using ::com::sun::star::xml::sax::XFastAttributeList;
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::drawing;
37 using namespace ::com::sun::star::geometry;
38 using namespace ::com::sun::star::style;
39 
40 namespace oox::drawingml {
41 
42 /** converts EMUs into 1/100th mmm */
GetCoordinate(sal_Int32 nValue)43 sal_Int32 GetCoordinate( sal_Int32 nValue )
44 {
45     return o3tl::convert(nValue, o3tl::Length::emu, o3tl::Length::mm100);
46 }
47 
48 /** converts an emu string into 1/100th mmm */
GetCoordinate(std::u16string_view sValue)49 sal_Int32 GetCoordinate( std::u16string_view 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 o3tl::convert(nValue, o3tl::Length::mm100, o3tl::Length::emu);
61 }
62 
63 /** converts a ST_Percentage % string into 1/1000th of % */
GetPercent(std::u16string_view sValue)64 sal_Int32 GetPercent( std::u16string_view 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(std::u16string_view sValue)86 float GetTextSize( std::u16string_view 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 (1/100pt) to 1/100mm */
GetTextSpacingPoint(std::u16string_view sValue)96 sal_Int32 GetTextSpacingPoint( std::u16string_view sValue )
97 {
98     sal_Int32 nRet;
99     if( ::sax::Converter::convertNumber( nRet, sValue ) )
100         nRet = GetTextSpacingPoint( nRet );
101     return nRet;
102 }
103 
GetTextSpacingPoint(sal_Int32 nValue)104 sal_Int32 GetTextSpacingPoint(sal_Int32 nValue)
105 {
106     constexpr auto mdFromPt = o3tl::getConversionMulDiv(o3tl::Length::pt, o3tl::Length::mm100);
107     constexpr o3tl::detail::m_and_d md(mdFromPt.first, mdFromPt.second * 100);
108     return o3tl::convertNarrowing<sal_Int32, md.m, md.d>(nValue);
109 }
110 
GetFontHeight(sal_Int32 nHeight)111 float GetFontHeight( sal_Int32 nHeight )
112 {
113     // convert 1/100 points to points
114     return static_cast< float >( nHeight / 100.0 );
115 }
116 
GetFontUnderline(sal_Int32 nToken)117 sal_Int16 GetFontUnderline( sal_Int32 nToken )
118 {
119     OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
120     switch( nToken )
121     {
122         case XML_none:              return awt::FontUnderline::NONE;
123         case XML_dash:              return awt::FontUnderline::DASH;
124         case XML_dashHeavy:         return awt::FontUnderline::BOLDDASH;
125         case XML_dashLong:          return awt::FontUnderline::LONGDASH;
126         case XML_dashLongHeavy:     return awt::FontUnderline::BOLDLONGDASH;
127         case XML_dbl:               return awt::FontUnderline::DOUBLE;
128         case XML_dotDash:           return awt::FontUnderline::DASHDOT;
129         case XML_dotDashHeavy:      return awt::FontUnderline::BOLDDASHDOT;
130         case XML_dotDotDash:        return awt::FontUnderline::DASHDOTDOT;
131         case XML_dotDotDashHeavy:   return awt::FontUnderline::BOLDDASHDOTDOT;
132         case XML_dotted:            return awt::FontUnderline::DOTTED;
133         case XML_dottedHeavy:       return awt::FontUnderline::BOLDDOTTED;
134         case XML_heavy:             return awt::FontUnderline::BOLD;
135         case XML_sng:               return awt::FontUnderline::SINGLE;
136         case XML_wavy:              return awt::FontUnderline::WAVE;
137         case XML_wavyDbl:           return awt::FontUnderline::DOUBLEWAVE;
138         case XML_wavyHeavy:         return awt::FontUnderline::BOLDWAVE;
139 //        case XML_words:             // TODO
140     }
141     return awt::FontUnderline::DONTKNOW;
142 }
143 
GetFontStrikeout(sal_Int32 nToken)144 sal_Int16 GetFontStrikeout( sal_Int32 nToken )
145 {
146     OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
147     switch( nToken )
148     {
149         case XML_dblStrike: return awt::FontStrikeout::DOUBLE;
150         case XML_noStrike:  return awt::FontStrikeout::NONE;
151         case XML_sngStrike: return awt::FontStrikeout::SINGLE;
152     }
153     return awt::FontStrikeout::DONTKNOW;
154 }
155 
GetCaseMap(sal_Int32 nToken)156 sal_Int16 GetCaseMap( sal_Int32 nToken )
157 {
158     switch( nToken )
159     {
160         case XML_all:   return CaseMap::UPPERCASE;
161         case XML_small: return CaseMap::SMALLCAPS;
162     }
163     return CaseMap::NONE;
164 }
165 
166 /** converts a paragraph align to a ParaAdjust */
GetParaAdjust(sal_Int32 nAlign)167 ParagraphAdjust GetParaAdjust( sal_Int32 nAlign )
168 {
169     OSL_ASSERT((nAlign & sal_Int32(0xFFFF0000))==0);
170     ParagraphAdjust nEnum;
171     switch( nAlign )
172     {
173     case XML_ctr:
174         nEnum = ParagraphAdjust_CENTER;
175         break;
176     case XML_just:
177     case XML_justLow:
178         nEnum = ParagraphAdjust_BLOCK;
179         break;
180     case XML_r:
181         nEnum = ParagraphAdjust_RIGHT;
182         break;
183     case XML_thaiDist:
184     case XML_dist:
185         nEnum = ParagraphAdjust_STRETCH;
186         break;
187     case XML_l:
188     default:
189         nEnum = ParagraphAdjust_LEFT;
190         break;
191     }
192     return nEnum;
193 }
194 
GetTextVerticalAdjust(sal_Int32 nToken)195 TextVerticalAdjust GetTextVerticalAdjust( sal_Int32 nToken )
196 {
197     TextVerticalAdjust aVertAdjust;
198     switch( nToken )
199     {
200     case XML_b:
201         aVertAdjust = TextVerticalAdjust_BOTTOM;
202         break;
203     case XML_dist:
204     case XML_just:
205     case XML_ctr:
206         aVertAdjust = TextVerticalAdjust_CENTER;
207         break;
208     case XML_t:
209     default:
210         aVertAdjust = TextVerticalAdjust_TOP;
211         break;
212     }
213     return aVertAdjust;
214 }
215 
GetTextVerticalAdjust(TextVerticalAdjust eAdjust)216 const char* GetTextVerticalAdjust( TextVerticalAdjust eAdjust )
217 {
218     const char* sVerticalAdjust = nullptr;
219     switch( eAdjust )
220     {
221         case TextVerticalAdjust_BOTTOM:
222             sVerticalAdjust = "b";
223             break;
224         case TextVerticalAdjust_CENTER:
225             sVerticalAdjust = "ctr";
226             break;
227         case TextVerticalAdjust_TOP:
228         default:
229             sVerticalAdjust = "t";
230             break;
231     }
232     return sVerticalAdjust;
233 }
234 
GetTabAlign(sal_Int32 aToken)235 TabAlign GetTabAlign( sal_Int32 aToken )
236 {
237     OSL_ASSERT((aToken & sal_Int32(0xFFFF0000))==0);
238     TabAlign nEnum;
239     switch( aToken )
240     {
241     case XML_ctr:
242         nEnum = TabAlign_CENTER;
243         break;
244     case XML_dec:
245         nEnum = TabAlign_DECIMAL;
246         break;
247     case XML_l:
248         nEnum = TabAlign_LEFT;
249         break;
250     case XML_r:
251         nEnum = TabAlign_RIGHT;
252         break;
253     default:
254         nEnum = TabAlign_DEFAULT;
255         break;
256     }
257     return nEnum;
258 }
259 
GetHatchPattern(const drawing::Hatch & rHatch)260 const char* GetHatchPattern( const drawing::Hatch& rHatch )
261 {
262     const char* sPattern = nullptr;
263     const sal_Int32 nAngle = rHatch.Angle > 1800 ? rHatch.Angle - 1800 : rHatch.Angle;
264     // Angle ~ 0° (horizontal)
265     if( (nAngle >= 0 && nAngle < 225) || nAngle >= 1575 )
266     {
267         switch( rHatch.Style )
268         {
269             case drawing::HatchStyle_SINGLE:
270             {
271                 if( rHatch.Distance < 75 )
272                     sPattern = "ltHorz";
273                 else
274                     sPattern = "horz";
275 
276                 break;
277             }
278             case drawing::HatchStyle_DOUBLE:
279             case drawing::HatchStyle_TRIPLE:
280             {
281                 if( rHatch.Distance < 75 )
282                     sPattern = "smGrid";
283                 else
284                     sPattern = "lgGrid";
285 
286                 break;
287             }
288             default: break;
289         }
290     }
291     // Angle ~ 45° (upward diagonal)
292     else if( nAngle < 675 )
293     {
294         switch( rHatch.Style )
295         {
296             case drawing::HatchStyle_SINGLE:
297             {
298                 if( rHatch.Distance < 75 )
299                     sPattern = "ltUpDiag";
300                 else
301                     sPattern = "wdUpDiag";
302 
303                 break;
304             }
305             case drawing::HatchStyle_DOUBLE:
306             case drawing::HatchStyle_TRIPLE:
307             {
308                 if( rHatch.Distance < 75 )
309                     sPattern = "smCheck";
310                 else
311                     sPattern = "openDmnd";
312 
313                 break;
314             }
315             default: break;
316         }
317     }
318     // Angle ~ 90° (vertical)
319     else if( nAngle < 1125 )
320     {
321         switch( rHatch.Style )
322         {
323             case drawing::HatchStyle_SINGLE:
324             {
325                 // dkVert is imported as Distance = 25, ltVert as Distance = 50, export them accordingly.
326                 if( rHatch.Distance < 50 )
327                     sPattern = "dkVert";
328                 else if( rHatch.Distance < 75 )
329                     sPattern = "ltVert";
330                 else
331                     sPattern = "vert";
332 
333                 break;
334             }
335             case drawing::HatchStyle_DOUBLE:
336             case drawing::HatchStyle_TRIPLE:
337             {
338                 if( rHatch.Distance < 75 )
339                     sPattern = "smGrid";
340                 else
341                     sPattern = "lgGrid";
342 
343                 break;
344             }
345             default: break;
346         }
347     }
348     // Angle ~ 135° (downward diagonal)
349     else if( nAngle < 1575 )
350     {
351         switch( rHatch.Style )
352         {
353             case drawing::HatchStyle_SINGLE:
354             {
355                 if( rHatch.Distance < 75 )
356                     sPattern = "ltDnDiag";
357                 else
358                     sPattern = "wdDnDiag";
359 
360                 break;
361             }
362             case drawing::HatchStyle_DOUBLE:
363             case drawing::HatchStyle_TRIPLE:
364             {
365                 if( rHatch.Distance < 75 )
366                     sPattern = "smCheck";
367                 else
368                     sPattern = "openDmnd";
369 
370                 break;
371             }
372             default: break;
373         }
374     }
375     return sPattern;
376 }
377 
GetTextVerticalType(sal_Int32 nRotateAngle)378 std::optional<OString> GetTextVerticalType(sal_Int32 nRotateAngle)
379 {
380     switch (nRotateAngle)
381     {
382       case 9000:
383           return "vert270";
384       case 27000:
385           return "vert";
386       default:
387           return {};
388     }
389 }
390 
391 namespace
392 {
393 // ISO/IEC-29500 Part 1 ST_Percentage, and [MS-OI29500] 2.1.1324
GetST_Percentage(std::u16string_view s)394 sal_Int32 GetST_Percentage(std::u16string_view s)
395 {
396     if (o3tl::ends_with(s, u"%"))
397         return std::round(o3tl::toDouble(s) * 1000);
398     return o3tl::toInt32(s);
399 }
400 }
401 
402 /** converts the attributes from a CT_RelativeRect to an IntegerRectangle2D */
GetRelativeRect(const Reference<XFastAttributeList> & xAttribs)403 IntegerRectangle2D GetRelativeRect( const Reference< XFastAttributeList >& xAttribs )
404 {
405     IntegerRectangle2D r;
406 
407     r.X1 = GetST_Percentage(xAttribs->getOptionalValue( XML_l ));
408     r.Y1 = GetST_Percentage(xAttribs->getOptionalValue( XML_t ));
409     r.X2 = GetST_Percentage(xAttribs->getOptionalValue( XML_r ));
410     r.Y2 = GetST_Percentage(xAttribs->getOptionalValue( XML_b ));
411 
412     return r;
413 }
414 
fillRelativeRectangle(model::RelativeRectangle & rRelativeRectangle,const Reference<XFastAttributeList> & xAttribs)415 void fillRelativeRectangle(model::RelativeRectangle& rRelativeRectangle, const Reference<XFastAttributeList>& xAttribs)
416 {
417     rRelativeRectangle.mnLeft = GetST_Percentage(xAttribs->getOptionalValue(XML_l));
418     rRelativeRectangle.mnTop = GetST_Percentage(xAttribs->getOptionalValue(XML_t));
419     rRelativeRectangle.mnRight = GetST_Percentage(xAttribs->getOptionalValue(XML_r));
420     rRelativeRectangle.mnBottom = GetST_Percentage(xAttribs->getOptionalValue(XML_b));
421 }
422 
423 /** converts the attributes from a CT_Size2D into an awt Size with 1/100thmm */
GetSize2D(const Reference<XFastAttributeList> & xAttribs)424 awt::Size GetSize2D( const Reference< XFastAttributeList >& xAttribs )
425 {
426     return awt::Size( GetCoordinate( xAttribs->getOptionalValue( XML_cx ) ), GetCoordinate( xAttribs->getOptionalValue( XML_cy ) ) );
427 }
428 
GetIndexRange(const Reference<XFastAttributeList> & xAttributes)429 IndexRange GetIndexRange( const Reference< XFastAttributeList >& xAttributes )
430 {
431     IndexRange range;
432     range.start = xAttributes->getOptionalValue( XML_st ).toInt32();
433     range.end = xAttributes->getOptionalValue( XML_end ).toInt32();
434     return range;
435 }
436 
437 
convertToRectangleAlignment(sal_Int32 nToken)438 model::RectangleAlignment convertToRectangleAlignment(sal_Int32 nToken)
439 {
440     switch (nToken)
441     {
442         case XML_tl: return model::RectangleAlignment::TopLeft;
443         case XML_t: return model::RectangleAlignment::Top;
444         case XML_tr: return model::RectangleAlignment::TopRight;
445         case XML_l: return model::RectangleAlignment::Left;
446         case XML_ctr: return model::RectangleAlignment::Center;
447         case XML_r: return model::RectangleAlignment::Right;
448         case XML_bl: return model::RectangleAlignment::BottomLeft;
449         case XML_b: return model::RectangleAlignment::Bottom;
450         case XML_br: return model::RectangleAlignment::BottomRight;
451         default:
452             break;
453     }
454     return model::RectangleAlignment::Unset;
455 }
456 
457 } // namespace oox::drawingml
458 
459 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
460