LibreOffice Module oox (master)  1
vmlformatting.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 
20 #include <sal/config.h>
21 
22 #include <cstdlib>
23 
25 
26 #include <com/sun/star/beans/PropertyValue.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/drawing/XShape.hpp>
29 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
30 #include <com/sun/star/table/ShadowFormat.hpp>
31 #include <com/sun/star/text/XTextRange.hpp>
32 #include <o3tl/unit_conversion.hxx>
33 #include <rtl/strbuf.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
36 #include <oox/drawingml/color.hxx>
43 #include <oox/token/properties.hxx>
44 #include <oox/token/tokens.hxx>
45 #include <svx/svdtrans.hxx>
47 #include <vcl/virdev.hxx>
48 
49 namespace oox::vml {
50 
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::geometry;
53 
54 using ::oox::drawingml::Color;
55 using ::oox::drawingml::FillProperties;
56 using ::oox::drawingml::LineArrowProperties;
57 using ::oox::drawingml::LineProperties;
58 using ::oox::drawingml::ShapePropertyMap;
59 using ::com::sun::star::awt::Point;
60 using ::com::sun::star::drawing::PolygonFlags;
61 using ::com::sun::star::drawing::PolygonFlags_NORMAL;
62 using ::com::sun::star::drawing::PolygonFlags_CONTROL;
63 
64 namespace {
65 
66 bool lclExtractDouble( double& orfValue, sal_Int32& ornEndPos, const OUString& rValue )
67 {
68  // extract the double value and find start position of unit characters
69  rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok;
70  orfValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &ornEndPos );
71  return eConvStatus == rtl_math_ConversionStatus_Ok;
72 }
73 
74 } // namespace
75 
76 bool ConversionHelper::separatePair( OUString& orValue1, OUString& orValue2,
77  const OUString& rValue, sal_Unicode cSep )
78 {
79  sal_Int32 nSepPos = rValue.indexOf( cSep );
80  if( nSepPos >= 0 )
81  {
82  orValue1 = rValue.copy( 0, nSepPos ).trim();
83  orValue2 = rValue.copy( nSepPos + 1 ).trim();
84  }
85  else
86  {
87  orValue1 = rValue.trim();
88  }
89  return !orValue1.isEmpty() && !orValue2.isEmpty();
90 }
91 
92 bool ConversionHelper::decodeBool( std::u16string_view rValue )
93 {
94  sal_Int32 nToken = AttributeConversion::decodeToken( rValue );
95  // anything else than 't' or 'true' is considered to be false, as specified
96  return (nToken == XML_t) || (nToken == XML_true);
97 }
98 
99 double ConversionHelper::decodePercent( const OUString& rValue, double fDefValue )
100 {
101  if( rValue.isEmpty() )
102  return fDefValue;
103 
104  double fValue = 0.0;
105  sal_Int32 nEndPos = 0;
106  if( !lclExtractDouble( fValue, nEndPos, rValue ) )
107  return fDefValue;
108 
109  if( nEndPos == rValue.getLength() )
110  return fValue;
111 
112  if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == '%') )
113  return fValue / 100.0;
114 
115  if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == 'f') )
116  return fValue / 65536.0;
117 
118  OSL_FAIL( "ConversionHelper::decodePercent - unknown measure unit" );
119  return fDefValue;
120 }
121 
123 {
124  if( rValue.isEmpty() )
125  return 0_deg100;
126 
127  double fValue = 0.0;
128  double fRotation = 0.0;
129  sal_Int32 nEndPos = 0;
130  if( !lclExtractDouble(fValue, nEndPos, rValue) )
131  return 0_deg100;
132 
133  if( nEndPos == rValue.getLength() )
134  fRotation = fValue;
135  else if( (nEndPos + 2 == rValue.getLength()) && (rValue[nEndPos] == 'f') && (rValue[nEndPos+1] == 'd') )
136  fRotation = fValue / 65536.0;
137  else
138  {
139  OSL_FAIL("ConversionHelper::decodeRotation - unknown measure unit");
140  return 0_deg100;
141  }
142 
143  return NormAngle36000(Degree100(static_cast<sal_Int32>(fRotation * -100)));
144 }
145 
146 sal_Int64 ConversionHelper::decodeMeasureToEmu( const GraphicHelper& rGraphicHelper,
147  const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
148 {
149  // default for missing values is 0
150  if( rValue.isEmpty() )
151  return 0;
152 
153  // TODO: according to spec, value may contain "auto"
154  if ( rValue == "auto" )
155  {
156  OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - special value 'auto' must be handled by caller" );
157  return nRefValue;
158  }
159 
160  // extract the double value and find start position of unit characters
161  double fValue = 0.0;
162  sal_Int32 nEndPos = 0;
163  if( !lclExtractDouble( fValue, nEndPos, rValue ) || (fValue == 0.0) )
164  return 0;
165 
166  // process trailing unit, convert to EMU
167  OUString aUnit;
168  if( (0 < nEndPos) && (nEndPos < rValue.getLength()) )
169  aUnit = rValue.copy( nEndPos );
170  else if( bDefaultAsPixel )
171  aUnit = "px";
172  // else default is EMU
173 
174  if( aUnit.getLength() == 2 )
175  {
176  sal_Unicode cChar1 = aUnit[ 0 ];
177  sal_Unicode cChar2 = aUnit[ 1 ];
178  if ((cChar1 == 'i') && (cChar2 == 'n'))
180  else if ((cChar1 == 'c') && (cChar2 == 'm'))
182  else if ((cChar1 == 'm') && (cChar2 == 'm'))
184  else if ((cChar1 == 'p') && (cChar2 == 't'))
186  else if ((cChar1 == 'p') && (cChar2 == 'c'))
188  else if( (cChar1 == 'p') && (cChar2 == 'x') ) // 1 pixel, dependent on output device
189  fValue = o3tl::convert(bPixelX ? rGraphicHelper.convertScreenPixelXToHmm(fValue)
190  : rGraphicHelper.convertScreenPixelYToHmm(fValue),
192  }
193  else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') )
194  {
195  fValue *= nRefValue / 100.0;
196  }
197  else if( bDefaultAsPixel || !aUnit.isEmpty() ) // default as EMU and no unit -> do nothing
198  {
199  OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - unknown measure unit" );
200  fValue = nRefValue;
201  }
202  return static_cast< sal_Int64 >( fValue + 0.5 );
203 }
204 
205 sal_Int32 ConversionHelper::decodeMeasureToHmm( const GraphicHelper& rGraphicHelper,
206  const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
207 {
208  return ::oox::drawingml::convertEmuToHmm( decodeMeasureToEmu( rGraphicHelper, rValue, nRefValue, bPixelX, bDefaultAsPixel ) );
209 }
210 
212  const OptValue< OUString >& roVmlColor, const OptValue< double >& roVmlOpacity,
213  ::Color nDefaultRgb, ::Color nPrimaryRgb )
214 {
215  Color aDmlColor;
216 
217  // convert opacity
218  const sal_Int32 DML_FULL_OPAQUE = ::oox::drawingml::MAX_PERCENT;
219  double fOpacity = roVmlOpacity.get( 1.0 );
220  sal_Int32 nOpacity = getLimitedValue< sal_Int32, double >( fOpacity * DML_FULL_OPAQUE, 0, DML_FULL_OPAQUE );
221  if( nOpacity < DML_FULL_OPAQUE )
222  aDmlColor.addTransformation( XML_alpha, nOpacity );
223 
224  // color attribute not present - set passed default color
225  if( !roVmlColor.has() )
226  {
227  aDmlColor.setSrgbClr( nDefaultRgb );
228  return aDmlColor;
229  }
230 
231  // separate leading color name or RGB value from following palette index
232  OUString aColorName, aColorIndex;
233  separatePair( aColorName, aColorIndex, roVmlColor.get(), ' ' );
234 
235  // RGB colors in the format '#RRGGBB'
236  if( (aColorName.getLength() == 7) && (aColorName[ 0 ] == '#') )
237  {
238  aDmlColor.setSrgbClr( aColorName.copy( 1 ).toUInt32( 16 ) );
239  return aDmlColor;
240  }
241 
242  // RGB colors in the format '#RGB'
243  if( (aColorName.getLength() == 4) && (aColorName[ 0 ] == '#') )
244  {
245  sal_Int32 nR = aColorName.copy( 1, 1 ).toUInt32( 16 ) * 0x11;
246  sal_Int32 nG = aColorName.copy( 2, 1 ).toUInt32( 16 ) * 0x11;
247  sal_Int32 nB = aColorName.copy( 3, 1 ).toUInt32( 16 ) * 0x11;
248  aDmlColor.setSrgbClr( (nR << 16) | (nG << 8) | nB );
249  return aDmlColor;
250  }
251 
252  /* Predefined color names or system color names (resolve to RGB to detect
253  valid color name). */
254  sal_Int32 nColorToken = AttributeConversion::decodeToken( aColorName );
255  ::Color nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT );
256  if( nRgbValue == API_RGB_TRANSPARENT )
257  nRgbValue = rGraphicHelper.getSystemColor( nColorToken );
258  if( nRgbValue != API_RGB_TRANSPARENT )
259  {
260  aDmlColor.setSrgbClr( nRgbValue );
261  return aDmlColor;
262  }
263 
264  // try palette colors enclosed in brackets
265  if( (aColorIndex.getLength() >= 3) && (aColorIndex[ 0 ] == '[') && (aColorIndex[ aColorIndex.getLength() - 1 ] == ']') )
266  {
267  aDmlColor.setPaletteClr( aColorIndex.copy( 1, aColorIndex.getLength() - 2 ).toInt32() );
268  return aDmlColor;
269  }
270 
271  // try fill gradient modificator 'fill <modifier>(<amount>)'
272  if( (nPrimaryRgb != API_RGB_TRANSPARENT) && (nColorToken == XML_fill) )
273  {
274  sal_Int32 nOpenParen = aColorIndex.indexOf( '(' );
275  sal_Int32 nCloseParen = aColorIndex.indexOf( ')' );
276  if( (2 <= nOpenParen) && (nOpenParen + 1 < nCloseParen) && (nCloseParen + 1 == aColorIndex.getLength()) )
277  {
278  sal_Int32 nModToken = XML_TOKEN_INVALID;
279  switch( AttributeConversion::decodeToken( aColorIndex.subView( 0, nOpenParen ) ) )
280  {
281  case XML_darken: nModToken = XML_shade;break;
282  case XML_lighten: nModToken = XML_tint;
283  }
284  sal_Int32 nValue = aColorIndex.copy( nOpenParen + 1, nCloseParen - nOpenParen - 1 ).toInt32();
285  if( (nModToken != XML_TOKEN_INVALID) && (0 <= nValue) && (nValue < 255) )
286  {
287  /* Simulate this modifier color by a color with related transformation.
288  The modifier amount has to be converted from the range [0;255] to
289  percentage [0;100000] used by DrawingML. */
290  aDmlColor.setSrgbClr( nPrimaryRgb );
291  aDmlColor.addTransformation( nModToken, static_cast< sal_Int32 >( nValue * ::oox::drawingml::MAX_PERCENT / 255 ) );
292  return aDmlColor;
293  }
294  }
295  }
296 
297  OSL_FAIL( OStringBuffer( "lclGetColor - invalid VML color name '" +
298  OUStringToOString( roVmlColor.get(), RTL_TEXTENCODING_ASCII_US ) + "'" ).getStr() );
299  aDmlColor.setSrgbClr( nDefaultRgb );
300  return aDmlColor;
301 }
302 
303 void ConversionHelper::decodeVmlPath( ::std::vector< ::std::vector< Point > >& rPointLists, ::std::vector< ::std::vector< PolygonFlags > >& rFlagLists, const OUString& rPath )
304 {
305  ::std::vector< sal_Int32 > aCoordList;
306  Point aCurrentPoint;
307  sal_Int32 nTokenStart = 0;
308  sal_Int32 nTokenLen = 0;
309  sal_Int32 nParamCount = 0;
310  bool bCommand = false;
311  enum VML_State { START, MOVE_REL, MOVE_ABS, BEZIER_REL, BEZIER_ABS,
312  LINE_REL, LINE_ABS, CLOSE, END, UNSUPPORTED };
313  VML_State state = START;
314 
315  rPointLists.emplace_back( );
316  rFlagLists.emplace_back( );
317 
318  for ( sal_Int32 i = 0; i < rPath.getLength(); i++ )
319  {
320  // Keep track of current integer token
321  if ( ( rPath[ i ] >= '0' && rPath[ i ] <= '9' ) || rPath[ i ] == '-' )
322  nTokenLen++;
323  else if ( rPath[ i ] != ' ' )
324  {
325  // Store coordinate from current token
326  if ( state != START && state != UNSUPPORTED )
327  {
328  if ( nTokenLen > 0 )
329  aCoordList.push_back( rPath.copy( nTokenStart, nTokenLen ).toInt32() );
330  else
331  aCoordList.push_back( 0 );
332  nTokenLen = 0;
333  }
334 
335  if (rPath[ i ] == ',' )
336  {
337  nParamCount--;
338  }
339 
340  // Upon finding the next command code, deal with stored
341  // coordinates for previous command and reset parameters counter if needed.
342  // See http://www.w3.org/TR/NOTE-VML#_Toc416858382 for params count reference
343  if ( rPath[ i ] != ',' || nParamCount == 0 )
344  {
345  switch ( state )
346  {
347  case MOVE_REL:
348  aCoordList.resize(2, 0); // 2* params -> param count reset
349  if ( !rPointLists.empty() && !rPointLists.back().empty() )
350  {
351  rPointLists.emplace_back( );
352  rFlagLists.emplace_back( );
353  }
354  rPointLists.back().emplace_back( aCoordList[ 0 ], aCoordList[ 1 ] );
355  rFlagLists.back().push_back( PolygonFlags_NORMAL );
356  aCurrentPoint = rPointLists.back().back();
357  nParamCount = 2;
358  break;
359 
360  case MOVE_ABS:
361  aCoordList.resize(2, 0); // 2 params -> no param count reset
362  if ( !rPointLists.empty() && !rPointLists.back().empty() )
363  {
364  rPointLists.emplace_back( );
365  rFlagLists.emplace_back( );
366  }
367  rPointLists.back().emplace_back( (aCoordList[ 0 ]), aCoordList[ 1 ] );
368  rFlagLists.back().push_back( PolygonFlags_NORMAL );
369  aCurrentPoint = rPointLists.back().back();
370  break;
371 
372  case BEZIER_REL:
373  aCoordList.resize(6, 0); // 6* params -> param count reset
374  rPointLists.back().emplace_back( aCurrentPoint.X + aCoordList[ 0 ],
375  aCurrentPoint.Y + aCoordList[ 1 ] );
376  rPointLists.back().emplace_back( aCurrentPoint.X + aCoordList[ 2 ],
377  aCurrentPoint.Y + aCoordList[ 3 ] );
378  rPointLists.back().emplace_back( aCurrentPoint.X + aCoordList[ 4 ],
379  aCurrentPoint.Y + aCoordList[ 5 ] );
380  rFlagLists.back().push_back( PolygonFlags_CONTROL );
381  rFlagLists.back().push_back( PolygonFlags_CONTROL );
382  rFlagLists.back().push_back( PolygonFlags_NORMAL );
383  aCurrentPoint = rPointLists.back().back();
384  nParamCount = 6;
385  break;
386 
387  case BEZIER_ABS:
388  aCoordList.resize(6, 0); // 6* params -> param count reset
389  rPointLists.back().emplace_back( aCoordList[ 0 ], aCoordList[ 1 ] );
390  rPointLists.back().emplace_back( aCoordList[ 2 ], aCoordList[ 3 ] );
391  rPointLists.back().emplace_back( aCoordList[ 4 ], aCoordList[ 5 ] );
392  rFlagLists.back().push_back( PolygonFlags_CONTROL );
393  rFlagLists.back().push_back( PolygonFlags_CONTROL );
394  rFlagLists.back().push_back( PolygonFlags_NORMAL );
395  aCurrentPoint = rPointLists.back().back();
396  nParamCount = 6;
397  break;
398 
399  case LINE_REL:
400  aCoordList.resize(2, 0); // 2* params -> param count reset
401  rPointLists.back().emplace_back( aCurrentPoint.X + aCoordList[ 0 ],
402  aCurrentPoint.Y + aCoordList[ 1 ] );
403  rFlagLists.back().push_back( PolygonFlags_NORMAL );
404  aCurrentPoint = rPointLists.back().back();
405  nParamCount = 2;
406  break;
407 
408  case LINE_ABS:
409  aCoordList.resize(2, 0); // 2* params -> param count reset
410  rPointLists.back().emplace_back( aCoordList[ 0 ], (aCoordList.size() > 1 ? aCoordList[ 1 ] : 0) );
411  rFlagLists.back().push_back( PolygonFlags_NORMAL );
412  aCurrentPoint = rPointLists.back().back();
413  nParamCount = 2;
414  break;
415 
416  case CLOSE: // 0 param
417  SAL_WARN_IF(rPointLists.back().empty() || rFlagLists.back().empty(), "oox", "empty pointlists at close");
418  if (!rPointLists.back().empty() && !rFlagLists.back().empty())
419  {
420  rPointLists.back().push_back( rPointLists.back()[ 0 ] );
421  rFlagLists.back().push_back( rFlagLists.back()[ 0 ] );
422  aCurrentPoint = rPointLists.back().back();
423  }
424  break;
425 
426  case END: // 0 param
427  rPointLists.emplace_back( );
428  rFlagLists.emplace_back( );
429  break;
430 
431  case START:
432  case UNSUPPORTED:
433  break;
434  }
435 
436  aCoordList.clear();
437  }
438 
439  // Allow two-char commands to peek ahead to the next character
440  sal_Unicode nextChar = '\0';
441  if (i+1 < rPath.getLength())
442  nextChar = rPath[i+1];
443 
444  // Move to relevant state upon finding a command
445  bCommand = true;
446  switch ( rPath[ i ] )
447  {
448  // Single-character commands
449  case 't': // rmoveto
450  state = MOVE_REL; nParamCount = 2; break;
451  case 'm': // moveto
452  state = MOVE_ABS; nParamCount = 2; break;
453  case 'v': // rcurveto
454  state = BEZIER_REL; nParamCount = 6; break;
455  case 'c': // curveto
456  state = BEZIER_ABS; nParamCount = 6; break;
457  case 'r': // rlineto
458  state = LINE_REL; nParamCount = 2; break;
459  case 'l': // lineto
460  state = LINE_ABS; nParamCount = 2; break;
461  case 'x': // close
462  state = CLOSE; break;
463  case 'e': // end
464  state = END; break;
465 
466  // Two-character commands
467  case 'n':
468  {
469  switch ( nextChar )
470  {
471  case 'f': // nf - nofill
472  case 's': // ns - nostroke
473  state = UNSUPPORTED; i++; break;
474  }
475  break;
476  }
477  case 'a': // Elliptical curves
478  {
479  switch ( nextChar )
480  {
481  case 'e': // ae - angleellipseto
482  case 'l': // al - angleellipse
483  state = UNSUPPORTED; i++; break;
484  case 't': // at - arcto
485  case 'r': // ar - arc
486  state = UNSUPPORTED; i++; break;
487  }
488  break;
489  }
490  case 'w': // Clockwise elliptical arcs
491  {
492  switch ( nextChar )
493  {
494  case 'a': // wa - clockwisearcto
495  case 'r': // wr - clockwisearc
496  state = UNSUPPORTED; i++; break;
497  }
498  break;
499  }
500  case 'q':
501  {
502  switch ( nextChar )
503  {
504  case 'x': // qx - ellipticalquadrantx
505  case 'y': // qy - ellipticalquadranty
506  state = UNSUPPORTED; i++; break;
507  case 'b': // qb - quadraticbezier
508  state = UNSUPPORTED; i++; break;
509  }
510  break;
511  }
512  case 'h': // behaviour extensions
513  {
514  switch ( nextChar )
515  {
516  case 'a': // ha - AutoLine
517  case 'b': // hb - AutoCurve
518  case 'c': // hc - CornerLine
519  case 'd': // hd - CornerCurve
520  case 'e': // he - SmoothLine
521  case 'f': // hf - SmoothCurve
522  case 'g': // hg - SymmetricLine
523  case 'h': // hh - SymmetricCurve
524  case 'i': // hi - Freeform
525  state = UNSUPPORTED; i++; break;
526  }
527  break;
528  }
529  default:
530  bCommand = false;
531  break;
532  }
533 
534  if (bCommand) nTokenLen = 0;
535  nTokenStart = i+1;
536  }
537  }
538 }
539 
540 namespace {
541 
542 sal_Int64 lclGetEmu( const GraphicHelper& rGraphicHelper, const OptValue< OUString >& roValue, sal_Int64 nDefValue )
543 {
544  return roValue.has() ? ConversionHelper::decodeMeasureToEmu( rGraphicHelper, roValue.get(), 0, false, false ) : nDefValue;
545 }
546 
547 void lclGetDmlLineDash( OptValue< sal_Int32 >& oroPresetDash, LineProperties::DashStopVector& orCustomDash, const OptValue< OUString >& roDashStyle )
548 {
549  if( !roDashStyle.has() )
550  return;
551 
552  const OUString& rDashStyle = roDashStyle.get();
553  switch( AttributeConversion::decodeToken( rDashStyle ) )
554  {
555  case XML_solid: oroPresetDash = XML_solid; return;
556  case XML_shortdot: oroPresetDash = XML_sysDot; return;
557  case XML_shortdash: oroPresetDash = XML_sysDash; return;
558  case XML_shortdashdot: oroPresetDash = XML_sysDashDot; return;
559  case XML_shortdashdotdot: oroPresetDash = XML_sysDashDotDot; return;
560  case XML_dot: oroPresetDash = XML_dot; return;
561  case XML_dash: oroPresetDash = XML_dash; return;
562  case XML_dashdot: oroPresetDash = XML_dashDot; return;
563  case XML_longdash: oroPresetDash = XML_lgDash; return;
564  case XML_longdashdot: oroPresetDash = XML_lgDashDot; return;
565  case XML_longdashdotdot: oroPresetDash = XML_lgDashDotDot; return;
566 
567  // try to convert user-defined dash style
568  default:
569  {
570  ::std::vector< sal_Int32 > aValues;
571  sal_Int32 nIndex = 0;
572  while( nIndex >= 0 )
573  aValues.push_back( rDashStyle.getToken( 0, ' ', nIndex ).toInt32() );
574  size_t nPairs = aValues.size() / 2; // ignore last value if size is odd
575  for( size_t nPairIdx = 0; nPairIdx < nPairs; ++nPairIdx )
576  orCustomDash.emplace_back( aValues[ 2 * nPairIdx ], aValues[ 2 * nPairIdx + 1 ] );
577  }
578  }
579 }
580 
581 sal_Int32 lclGetDmlArrowType( const OptValue< sal_Int32 >& roArrowType )
582 {
583  if( roArrowType.has() ) switch( roArrowType.get() )
584  {
585  case XML_none: return XML_none;
586  case XML_block: return XML_triangle;
587  case XML_classic: return XML_stealth;
588  case XML_diamond: return XML_diamond;
589  case XML_oval: return XML_oval;
590  case XML_open: return XML_arrow;
591  }
592  return XML_none;
593 }
594 
595 sal_Int32 lclGetDmlArrowWidth( const OptValue< sal_Int32 >& roArrowWidth )
596 {
597  if( roArrowWidth.has() ) switch( roArrowWidth.get() )
598  {
599  case XML_narrow: return XML_sm;
600  case XML_medium: return XML_med;
601  case XML_wide: return XML_lg;
602  }
603  return XML_med;
604 }
605 
606 sal_Int32 lclGetDmlArrowLength( const OptValue< sal_Int32 >& roArrowLength )
607 {
608  if( roArrowLength.has() ) switch( roArrowLength.get() )
609  {
610  case XML_short: return XML_sm;
611  case XML_medium: return XML_med;
612  case XML_long: return XML_lg;
613  }
614  return XML_med;
615 }
616 
617 void lclConvertArrow( LineArrowProperties& orArrowProp, const StrokeArrowModel& rStrokeArrow )
618 {
619  orArrowProp.moArrowType = lclGetDmlArrowType( rStrokeArrow.moArrowType );
620  orArrowProp.moArrowWidth = lclGetDmlArrowWidth( rStrokeArrow.moArrowWidth );
621  orArrowProp.moArrowLength = lclGetDmlArrowLength( rStrokeArrow.moArrowLength );
622 }
623 
624 sal_Int32 lclGetDmlLineCompound( const OptValue< sal_Int32 >& roLineStyle )
625 {
626  if( roLineStyle.has() ) switch( roLineStyle.get() )
627  {
628  case XML_single: return XML_sng;
629  case XML_thinThin: return XML_dbl;
630  case XML_thinThick: return XML_thinThick;
631  case XML_thickThin: return XML_thickThin;
632  case XML_thickBetweenThin: return XML_tri;
633  }
634  return XML_sng;
635 }
636 
637 sal_Int32 lclGetDmlLineCap( const OptValue< sal_Int32 >& roEndCap )
638 {
639  if( roEndCap.has() ) switch( roEndCap.get() )
640  {
641  case XML_flat: return XML_flat;
642  case XML_square: return XML_sq;
643  case XML_round: return XML_rnd;
644  }
645  return XML_flat; // different defaults in VML (flat) and DrawingML (square)
646 }
647 
648 sal_Int32 lclGetDmlLineJoint( const OptValue< sal_Int32 >& roJoinStyle )
649 {
650  if( roJoinStyle.has() ) switch( roJoinStyle.get() )
651  {
652  case XML_round: return XML_round;
653  case XML_bevel: return XML_bevel;
654  case XML_miter: return XML_miter;
655  }
656  return XML_round;
657 }
658 
659 } // namespace
660 
662 {
666 }
667 
668 void StrokeModel::assignUsed( const StrokeModel& rSource )
669 {
670  moStroked.assignIfUsed( rSource.moStroked );
672  maEndArrow.assignUsed( rSource.maEndArrow );
673  moColor.assignIfUsed( rSource.moColor );
674  moOpacity.assignIfUsed( rSource.moOpacity );
675  moWeight.assignIfUsed( rSource.moWeight );
678  moEndCap.assignIfUsed( rSource.moEndCap );
680 }
681 
682 void StrokeModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
683 {
684  /* Convert VML line formatting to DrawingML line formatting and let the
685  DrawingML code do the hard work. */
686  LineProperties aLineProps;
687 
688  if( moStroked.get( true ) )
689  {
690  aLineProps.maLineFill.moFillType = XML_solidFill;
691  lclConvertArrow( aLineProps.maStartArrow, maStartArrow );
692  lclConvertArrow( aLineProps.maEndArrow, maEndArrow );
693  aLineProps.maLineFill.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_BLACK );
694  aLineProps.moLineWidth = getLimitedValue< sal_Int32, sal_Int64 >( lclGetEmu( rGraphicHelper, moWeight, 1 ), 0, SAL_MAX_INT32 );
695  lclGetDmlLineDash( aLineProps.moPresetDash, aLineProps.maCustomDash, moDashStyle );
696  aLineProps.moLineCompound = lclGetDmlLineCompound( moLineStyle );
697  aLineProps.moLineCap = lclGetDmlLineCap( moEndCap );
698  aLineProps.moLineJoint = lclGetDmlLineJoint( moJoinStyle );
699  }
700  else
701  {
702  aLineProps.maLineFill.moFillType = XML_noFill;
703  }
704 
705  aLineProps.pushToPropMap( rPropMap, rGraphicHelper );
706 }
707 
708 void FillModel::assignUsed( const FillModel& rSource )
709 {
710  moFilled.assignIfUsed( rSource.moFilled );
711  moColor.assignIfUsed( rSource.moColor );
712  moOpacity.assignIfUsed( rSource.moOpacity );
713  moColor2.assignIfUsed( rSource.moColor2 );
715  moType.assignIfUsed( rSource.moType );
716  moAngle.assignIfUsed( rSource.moAngle );
717  moFocus.assignIfUsed( rSource.moFocus );
721  moRotate.assignIfUsed( rSource.moRotate );
722 }
723 
724 static void lcl_setGradientStop( std::multimap< double, Color >& rMap, const double fKey, const Color& rValue ) {
725  auto aElement = rMap.find( fKey );
726 
727  if (aElement != rMap.end())
728  aElement->second = rValue;
729  else
730  rMap.emplace( fKey, rValue );
731 }
732 
733 void FillModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
734 {
735  /* Convert VML fill formatting to DrawingML fill formatting and let the
736  DrawingML code do the hard work. */
737  FillProperties aFillProps;
738 
739  if( moFilled.get( true ) )
740  {
741  sal_Int32 nFillType = moType.get( XML_solid );
742  switch( nFillType )
743  {
744  case XML_gradient:
745  case XML_gradientRadial:
746  {
747  aFillProps.moFillType = XML_gradFill;
748  aFillProps.maGradientProps.moRotateWithShape = moRotate.get( false );
749  double fFocus = moFocus.get( 0.0 );
750 
751  // prepare colors
752  Color aColor1 = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
753  Color aColor2 = ConversionHelper::decodeColor( rGraphicHelper, moColor2, moOpacity2, API_RGB_WHITE, aColor1.getColor( rGraphicHelper ) );
754 
755  // type XML_gradient is linear or axial gradient
756  if( nFillType == XML_gradient )
757  {
758  // normalize angle to range [0;360) degrees
759  sal_Int32 nVmlAngle = getIntervalValue< sal_Int32, sal_Int32 >( moAngle.get( 0 ), 0, 360 );
760 
761  // focus of -50% or 50% is axial gradient
762  if( ((-0.75 <= fFocus) && (fFocus <= -0.25)) || ((0.25 <= fFocus) && (fFocus <= 0.75)) )
763  {
764  /* According to spec, focus of 50% is outer-to-inner,
765  and -50% is inner-to-outer (color to color2).
766  BUT: For angles >= 180 deg., the behaviour is
767  reversed... that's not spec'ed of course. So,
768  [0;180) deg. and 50%, or [180;360) deg. and -50% is
769  outer-to-inner in fact. */
770  bool bOuterToInner = (fFocus > 0.0) == (nVmlAngle < 180);
771  // simulate axial gradient by 3-step DrawingML gradient
772  const Color& rOuterColor = bOuterToInner ? aColor1 : aColor2;
773  const Color& rInnerColor = bOuterToInner ? aColor2 : aColor1;
774 
775  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.0, rOuterColor);
776  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 1.0, rOuterColor);
777  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.5, rInnerColor );
778  }
779  else // focus of -100%, 0%, and 100% is linear gradient
780  {
781  /* According to spec, focus of -100% or 100% swaps the
782  start and stop colors, effectively reversing the
783  gradient. BUT: For angles >= 180 deg., the
784  behaviour is reversed. This means that in this case
785  a focus of 0% swaps the gradient. */
786  if( fFocus < -0.5 || fFocus > 0.5 )
787  nVmlAngle = (nVmlAngle + 180) % 360;
788  // set the start and stop colors
789  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.0, aColor1 );
790  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 1.0, aColor2 );
791  }
792 
793  // VML counts counterclockwise from bottom, DrawingML clockwise from left
794  sal_Int32 nDmlAngle = (630 - nVmlAngle) % 360;
795  aFillProps.maGradientProps.moShadeAngle = nDmlAngle * ::oox::drawingml::PER_DEGREE;
796  }
797  else // XML_gradientRadial is rectangular gradient
798  {
799  aFillProps.maGradientProps.moGradientPath = XML_rect;
800  // convert VML focus position and size to DrawingML fill-to-rect
801  DoublePair aFocusPos = moFocusPos.get( DoublePair( 0.0, 0.0 ) );
802  DoublePair aFocusSize = moFocusSize.get( DoublePair( 0.0, 0.0 ) );
803  double fLeft = getLimitedValue< double, double >( aFocusPos.first, 0.0, 1.0 );
804  double fTop = getLimitedValue< double, double >( aFocusPos.second, 0.0, 1.0 );
805  double fRight = getLimitedValue< double, double >( fLeft + aFocusSize.first, fLeft, 1.0 );
806  double fBottom = getLimitedValue< double, double >( fTop + aFocusSize.second, fTop, 1.0 );
807  aFillProps.maGradientProps.moFillToRect = IntegerRectangle2D(
808  static_cast< sal_Int32 >( fLeft * ::oox::drawingml::MAX_PERCENT ),
809  static_cast< sal_Int32 >( fTop * ::oox::drawingml::MAX_PERCENT ),
810  static_cast< sal_Int32 >( (1.0 - fRight) * ::oox::drawingml::MAX_PERCENT ),
811  static_cast< sal_Int32 >( (1.0 - fBottom) * ::oox::drawingml::MAX_PERCENT ) );
812 
813  // set the start and stop colors (focus of 0% means outer-to-inner)
814  bool bOuterToInner = (-0.5 <= fFocus) && (fFocus <= 0.5);
815  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.0, bOuterToInner ? aColor2 : aColor1 );
816  lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 1.0, bOuterToInner ? aColor1 : aColor2 );
817  }
818  }
819  break;
820 
821  case XML_pattern:
822  case XML_tile:
823  case XML_frame:
824  {
825  if( moBitmapPath.has() && !moBitmapPath.get().isEmpty() )
826  {
827  aFillProps.maBlipProps.mxFillGraphic = rGraphicHelper.importEmbeddedGraphic(moBitmapPath.get());
828  if (aFillProps.maBlipProps.mxFillGraphic.is())
829  {
830  aFillProps.moFillType = XML_blipFill;
831  aFillProps.maBlipProps.moBitmapMode = (nFillType == XML_frame) ? XML_stretch : XML_tile;
832  break; // do not break if bitmap is missing, but run to XML_solid instead
833  }
834  }
835  }
836  [[fallthrough]]; // to XML_solid in case of missing bitmap path intended!
837 
838  case XML_solid:
839  default:
840  {
841  aFillProps.moFillType = XML_solidFill;
842  // fill color (default is white)
843  aFillProps.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
844  }
845  }
846  }
847  else
848  {
849  aFillProps.moFillType = XML_noFill;
850  }
851 
852  aFillProps.pushToPropMap( rPropMap, rGraphicHelper );
853 }
854 
856  : mbHasShadow(false)
857 {
858 }
859 
860 void ShadowModel::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper) const
861 {
862  if (!mbHasShadow || (moShadowOn.has() && !moShadowOn.get()))
863  return;
864 
866  // nOffset* is in mm100, default value is 35 twips, see DffPropertyReader::ApplyAttributes() in msfilter.
867  sal_Int32 nOffsetX = 62, nOffsetY = 62;
868  if (moOffset.has())
869  {
870  OUString aOffsetX, aOffsetY;
871  ConversionHelper::separatePair(aOffsetX, aOffsetY, moOffset.get(), ',');
872  if (!aOffsetX.isEmpty())
873  nOffsetX = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aOffsetX, 0, false, false );
874  if (!aOffsetY.isEmpty())
875  nOffsetY = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aOffsetY, 0, false, false );
876  }
877 
878  table::ShadowFormat aFormat;
879  aFormat.Color = sal_Int32(aColor.getColor(rGraphicHelper));
880  aFormat.Location = nOffsetX < 0
881  ? nOffsetY < 0 ? table::ShadowLocation_TOP_LEFT : table::ShadowLocation_BOTTOM_LEFT
882  : nOffsetY < 0 ? table::ShadowLocation_TOP_RIGHT : table::ShadowLocation_BOTTOM_RIGHT;
883  // The width of the shadow is the average of the x and y values, see SwWW8ImplReader::MatchSdrItemsIntoFlySet().
884  aFormat.ShadowWidth = ((std::abs(nOffsetX) + std::abs(nOffsetY)) / 2);
885  rPropMap.setProperty(PROP_ShadowFormat, aFormat);
886 }
887 
889 {
890 }
891 
892 static beans::PropertyValue lcl_createTextpathProps()
893 {
894  uno::Sequence<beans::PropertyValue> aTextpathPropSeq( comphelper::InitPropertySequence({
895  { "TextPath", uno::Any(true) },
896  { "TextPathMode", uno::Any(drawing::EnhancedCustomShapeTextPathMode_SHAPE) },
897  { "ScaleX", uno::Any(false) },
898  { "SameLetterHeights", uno::Any(false) }
899  }));
900 
901  beans::PropertyValue aRet;
902  aRet.Name = "TextPath";
903  aRet.Value <<= aTextpathPropSeq;
904  return aRet;
905 }
906 
907 void TextpathModel::pushToPropMap(ShapePropertyMap& rPropMap, const uno::Reference<drawing::XShape>& xShape, const GraphicHelper& rGraphicHelper) const
908 {
909  OUString sFont = "";
910 
911  if (moString.has())
912  {
913  uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
914  xTextRange->setString(moString.get());
915 
916  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
917  uno::Sequence<beans::PropertyValue> aGeomPropSeq = xPropertySet->getPropertyValue("CustomShapeGeometry").get< uno::Sequence<beans::PropertyValue> >();
918  bool bFound = false;
919  for (beans::PropertyValue& rProp : aGeomPropSeq)
920  {
921  if (rProp.Name == "TextPath")
922  {
923  bFound = true;
924  rProp = lcl_createTextpathProps();
925  }
926  }
927  if (!bFound)
928  {
929  sal_Int32 nSize = aGeomPropSeq.getLength();
930  aGeomPropSeq.realloc(nSize+1);
931  aGeomPropSeq[nSize] = lcl_createTextpathProps();
932  }
933  rPropMap.setAnyProperty(PROP_CustomShapeGeometry, uno::makeAny(aGeomPropSeq));
934  }
935  if (moStyle.has())
936  {
937  OUString aStyle = moStyle.get(OUString());
938 
939  sal_Int32 nIndex = 0;
940  while( nIndex >= 0 )
941  {
942  OUString aName, aValue;
943  if (ConversionHelper::separatePair(aName, aValue, aStyle.getToken(0, ';', nIndex), ':'))
944  {
945  if (aName == "font-family")
946  {
947  // remove " (first, and last character)
948  if (aValue.getLength() > 2)
949  aValue = aValue.copy(1, aValue.getLength() - 2);
950 
951  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
952  xPropertySet->setPropertyValue("CharFontName", uno::makeAny(aValue));
953  sFont = aValue;
954  }
955  else if (aName == "font-size")
956  {
957  oox::OptValue<OUString> aOptString(aValue);
958  float nSize = drawingml::convertEmuToPoints(lclGetEmu(rGraphicHelper, aOptString, 1));
959 
960  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
961  xPropertySet->setPropertyValue("CharHeight", uno::makeAny(nSize));
962  }
963  }
964  }
965  }
966  if (moTrim.has() && moTrim.get())
967  return;
968 
969  OUString sText = moString.get();
971  vcl::Font aFont = pDevice->GetFont();
972  aFont.SetFamilyName(sFont);
973  aFont.SetFontSize(Size(0, 96));
974  pDevice->SetFont(aFont);
975 
976  auto nTextWidth = pDevice->GetTextWidth(sText);
977  if (nTextWidth)
978  {
979  sal_Int32 nNewHeight = (static_cast<double>(pDevice->GetTextHeight()) / nTextWidth) * xShape->getSize().Width;
980  xShape->setSize(awt::Size(xShape->getSize().Width, nNewHeight));
981  }
982 }
983 
984 } // namespace oox
985 
986 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
css::uno::Reference< css::graphic::XGraphic > importEmbeddedGraphic(const OUString &rStreamName, const WmfExternal *pExtHeader=nullptr) const
Imports a graphic from the storage stream with the passed path and name.
OOX_DLLPUBLIC sal_Int32 decodeMeasureToHmm(const GraphicHelper &rGraphicHelper, const OUString &rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel)
Converts the passed VML measure string to 1/100 mm.
sal_Int32 nIndex
OptValue< bool > moTrim
Specifies whether extra space is removed above and below the text.
const ::Color API_RGB_TRANSPARENT(ColorTransparency, 0xffffffff)
Transparent color for API calls.
void SetFontSize(const Size &)
sal_Int32 convertEmuToHmm(sal_Int64 nValue)
Converts the passed 64-bit integer value from EMUs to 1/100 mm.
OptValue< OUString > moColor
Specifies the color of the shadow.
OptValue< OUString > moDashStyle
Line dash (predefined or manually).
void pushToPropMap(oox::drawingml::ShapePropertyMap &rPropMap, const css::uno::Reference< css::drawing::XShape > &xShape, const GraphicHelper &rGraphicHelper) const
Writes the properties to the passed property map.
const sal_Int32 PER_DEGREE
float convertEmuToPoints(sal_Int64 nValue)
Converts the passed 64-bit integer value from EMUs to Points.
The stroke model structure contains all shape border properties.
OOX_DLLPUBLIC bool decodeBool(std::u16string_view rValue)
Returns the boolean value from the passed string of a VML attribute.
OptValue< OUString > moStyle
Specifies the style of the textpath.
::Color getSystemColor(sal_Int32 nToken,::Color nDefaultRgb=API_RGB_TRANSPARENT) const
Returns a system color specified by the passed XML token identifier.
OptValue< sal_Int32 > moArrowType
OptValue< double > moOpacity
Solid fill color opacity.
sal_Int32 toInt32(OUString const &rStr)
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
static void lcl_setGradientStop(std::multimap< double, Color > &rMap, const double fKey, const Color &rValue)
OptValue< sal_Int32 > moAngle
Gradient rotation angle.
OOX_DLLPUBLIC Degree100 decodeRotation(const OUString &rValue)
Converts the passed VML rotation value to degrees.
StrokeArrowModel maStartArrow
Start line arrow style.
OptValue< OUString > moColor2
End color of gradient.
OptValue< double > moOpacity
Specifies the opacity of the shadow.
OptValue< sal_Int32 > moType
Fill type.
void pushToPropMap(oox::drawingml::ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper) const
Writes the properties to the passed property map.
sal_uInt16 sal_Unicode
char sal_uInt16 & nParamCount
OptValue< bool > moStroked
Shape border line on/off.
OptValue< sal_Int32 > moArrowLength
The fill model structure contains all shape fill properties.
const Type & get() const
Definition: helper.hxx:185
Degree100 NormAngle36000(Degree100 deg100)
OOX_DLLPUBLIC sal_Int64 decodeMeasureToEmu(const GraphicHelper &rGraphicHelper, const OUString &rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel)
Converts the passed VML measure string to EMU (English Metric Units).
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
START
OptValue< OUString > moBitmapPath
Path to fill bitmap fragment.
::std::pair< double, double > DoublePair
OptValue< double > moOpacity2
End color opacity of gradient.
OOX_DLLPUBLIC bool separatePair(OUString &orValue1, OUString &orValue2, const OUString &rValue, sal_Unicode cSep)
Returns two values contained in rValue separated by cSep.
END
OptValue< sal_Int32 > moLineStyle
Line style (single, double, ...).
OptValue< DoublePair > moFocusPos
Rectangular gradient focus position of second color.
::Color getColor(const GraphicHelper &rGraphicHelper,::Color nPhClr=API_RGB_TRANSPARENT) const
Returns the final RGB color value.
Definition: color.cxx:481
#define SAL_MAX_INT32
void SetFamilyName(const OUString &rFamilyName)
const short CLOSE
OptValue< double > moOpacity
Solid line color opacity.
static sal_Int32 decodeToken(std::u16string_view rValue)
Returns the XML token identifier from the passed string.
The stroke arrow model structure contains all properties for a line end arrow.
OptValue< OUString > moColor
Solid line color.
StrokeArrowModel maEndArrow
End line arrow style.
const sal_Int32 MAX_PERCENT
OptValue< sal_Int32 > moArrowWidth
OptValue< DoublePair > moFocusSize
Rectangular gradient focus size of second color.
void assignIfUsed(const OptValue &rValue)
Definition: helper.hxx:196
sal_Int32 convertScreenPixelXToHmm(double fPixelX) const
Converts the passed value from horizontal screen pixels to 1/100 mm.
OptValue< OUString > moWeight
Line width.
OOX_DLLPUBLIC::oox::drawingml::Color decodeColor(const GraphicHelper &rGraphicHelper, const OptValue< OUString > &roVmlColor, const OptValue< double > &roVmlOpacity,::Color nDefaultRgb,::Color nPrimaryRgb=API_RGB_TRANSPARENT)
Converts VML color attributes to a DrawingML color.
XML_TOKEN_INVALID
OOX_DLLPUBLIC void decodeVmlPath(::std::vector< ::std::vector< css::awt::Point > > &rPoints,::std::vector< ::std::vector< css::drawing::PolygonFlags > > &rFlags, const OUString &rPath)
Converts VML path string into point and flag vectors.
void assignUsed(const StrokeModel &rSource)
bool mbHasShadow
Is a v:shadow element seen?
const ::Color API_RGB_BLACK(0x000000)
Black color for API calls.
OptValue< OUString > moString
Specifies the string of the textpath.
sal_Int32 convertScreenPixelYToHmm(double fPixelY) const
Converts the passed value from vertical screen pixels to 1/100 mm.
DefTokenId nToken
OptValue< double > moFocus
Linear gradient focus of second color.
static beans::PropertyValue lcl_createTextpathProps()
void assignUsed(const StrokeArrowModel &rSource)
#define SAL_WARN_IF(condition, area, stream)
OUString aName
OptValue< OUString > moColor
Solid fill color.
OptValue< bool > moFilled
Shape fill on/off.
void assignUsed(const FillModel &rSource)
const ::Color API_RGB_GRAY(0x808080)
Gray color for API calls.
OptValue< bool > moShadowOn
Is the element turned on?
OOX_DLLPUBLIC double decodePercent(const OUString &rValue, double fDefValue)
Converts the passed VML percentage measure string to a normalized floating-point value.
OptValue< bool > moRotate
True = rotate gradient/bitmap with shape.
OptValue< sal_Int32 > moJoinStyle
Type of line join.
bool has() const
Definition: helper.hxx:181
OptValue< OUString > moOffset
Specifies the shadow's offset from the shape's location.
void pushToPropMap(::oox::drawingml::ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper) const
Writes the properties to the passed property map.
const ::Color API_RGB_WHITE(0xFFFFFF)
White color for API calls.
void pushToPropMap(::oox::drawingml::ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper) const
Writes the properties to the passed property map.
sal_Int16 nValue
OptValue< sal_Int32 > moEndCap
Type of line end cap.