Branch data Line data Source code
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/vml/vmlformatting.hxx"
21 : :
22 : : #include <rtl/strbuf.hxx>
23 : : #include "oox/drawingml/color.hxx"
24 : : #include "oox/drawingml/drawingmltypes.hxx"
25 : : #include "oox/drawingml/fillproperties.hxx"
26 : : #include "oox/drawingml/lineproperties.hxx"
27 : : #include "oox/drawingml/shapepropertymap.hxx"
28 : : #include "oox/helper/attributelist.hxx"
29 : : #include "oox/helper/graphichelper.hxx"
30 : :
31 : : namespace oox {
32 : : namespace vml {
33 : :
34 : : // ============================================================================
35 : :
36 : : using namespace ::com::sun::star::geometry;
37 : :
38 : : using ::oox::drawingml::Color;
39 : : using ::oox::drawingml::FillProperties;
40 : : using ::oox::drawingml::LineArrowProperties;
41 : : using ::oox::drawingml::LineProperties;
42 : : using ::oox::drawingml::ShapePropertyMap;
43 : : using ::rtl::OStringBuffer;
44 : : using ::rtl::OUString;
45 : :
46 : : // ============================================================================
47 : :
48 : : namespace {
49 : :
50 : 138 : bool lclExtractDouble( double& orfValue, sal_Int32& ornEndPos, const OUString& rValue )
51 : : {
52 : : // extract the double value and find start position of unit characters
53 : 138 : rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok;
54 : 138 : orfValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &ornEndPos );
55 : 138 : return eConvStatus == rtl_math_ConversionStatus_Ok;
56 : : }
57 : :
58 : : } // namespace
59 : :
60 : : // ----------------------------------------------------------------------------
61 : :
62 : 501 : /*static*/ bool ConversionHelper::separatePair( OUString& orValue1, OUString& orValue2,
63 : : const OUString& rValue, sal_Unicode cSep )
64 : : {
65 : 501 : sal_Int32 nSepPos = rValue.indexOf( cSep );
66 [ + + ]: 501 : if( nSepPos >= 0 )
67 : : {
68 : 465 : orValue1 = rValue.copy( 0, nSepPos ).trim();
69 : 465 : orValue2 = rValue.copy( nSepPos + 1 ).trim();
70 : : }
71 : : else
72 : : {
73 : 36 : orValue1 = rValue.trim();
74 : : }
75 [ + + ][ + + ]: 501 : return !orValue1.isEmpty() && !orValue2.isEmpty();
76 : : }
77 : :
78 : 42 : /*static*/ bool ConversionHelper::decodeBool( const OUString& rValue )
79 : : {
80 : 42 : sal_Int32 nToken = AttributeConversion::decodeToken( rValue );
81 : : // anything else than 't' or 'true' is considered to be false, as specified
82 [ - + ][ + + ]: 42 : return (nToken == XML_t) || (nToken == XML_true);
83 : : }
84 : :
85 : 0 : /*static*/ double ConversionHelper::decodePercent( const OUString& rValue, double fDefValue )
86 : : {
87 [ # # ]: 0 : if( rValue.isEmpty() )
88 : 0 : return fDefValue;
89 : :
90 : 0 : double fValue = 0.0;
91 : 0 : sal_Int32 nEndPos = 0;
92 [ # # ]: 0 : if( !lclExtractDouble( fValue, nEndPos, rValue ) )
93 : 0 : return fDefValue;
94 : :
95 [ # # ]: 0 : if( nEndPos == rValue.getLength() )
96 : 0 : return fValue;
97 : :
98 [ # # ][ # # ]: 0 : if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == '%') )
[ # # ]
99 : 0 : return fValue / 100.0;
100 : :
101 [ # # ][ # # ]: 0 : if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == 'f') )
[ # # ]
102 : 0 : return fValue / 65536.0;
103 : :
104 : : OSL_FAIL( "ConversionHelper::decodePercent - unknown measure unit" );
105 : 0 : return fDefValue;
106 : : }
107 : :
108 : 249 : /*static*/ sal_Int64 ConversionHelper::decodeMeasureToEmu( const GraphicHelper& rGraphicHelper,
109 : : const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
110 : : {
111 : : // default for missing values is 0
112 [ + + ]: 249 : if( rValue.isEmpty() )
113 : 111 : return 0;
114 : :
115 : : // TODO: according to spec, value may contain "auto"
116 [ - + ]: 138 : if ( rValue == "auto" )
117 : : {
118 : : OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - special value 'auto' must be handled by caller" );
119 : 0 : return nRefValue;
120 : : }
121 : :
122 : : // extract the double value and find start position of unit characters
123 : 138 : double fValue = 0.0;
124 : 138 : sal_Int32 nEndPos = 0;
125 [ + - ][ + + ]: 138 : if( !lclExtractDouble( fValue, nEndPos, rValue ) || (fValue == 0.0) )
[ + + ]
126 : 18 : return 0;
127 : :
128 : : // process trailing unit, convert to EMU
129 [ + + ][ + - ]: 120 : static const OUString saPx = CREATE_OUSTRING( "px" );
[ + - ][ # # ]
130 : 120 : OUString aUnit;
131 [ + - ][ + - ]: 120 : if( (0 < nEndPos) && (nEndPos < rValue.getLength()) )
[ + - ]
132 : 120 : aUnit = rValue.copy( nEndPos );
133 [ # # ]: 0 : else if( bDefaultAsPixel )
134 : 0 : aUnit = saPx;
135 : : // else default is EMU
136 : :
137 [ + - ]: 120 : if( aUnit.getLength() == 2 )
138 : : {
139 : 120 : sal_Unicode cChar1 = aUnit[ 0 ];
140 : 120 : sal_Unicode cChar2 = aUnit[ 1 ];
141 [ + - ][ + + ]: 120 : if( (cChar1 == 'i') && (cChar2 == 'n') ) // 1 inch = 914,400 EMU
142 : 6 : fValue *= 914400.0;
143 [ - + ][ # # ]: 114 : else if( (cChar1 == 'c') && (cChar2 == 'm') ) // 1 cm = 360,000 EMU
144 : 0 : fValue *= 360000.0;
145 [ - + ][ # # ]: 114 : else if( (cChar1 == 'm') && (cChar2 == 'm') ) // 1 mm = 36,000 EMU
146 : 0 : fValue *= 36000.0;
147 [ + - ][ + - ]: 114 : else if( (cChar1 == 'p') && (cChar2 == 't') ) // 1 point = 1/72 inch = 12,700 EMU
148 : 114 : fValue *= 12700.0;
149 [ # # ][ # # ]: 0 : else if( (cChar1 == 'p') && (cChar2 == 'c') ) // 1 pica = 1/6 inch = 152,400 EMU
150 : 0 : fValue *= 152400.0;
151 [ # # ][ # # ]: 0 : else if( (cChar1 == 'p') && (cChar2 == 'x') ) // 1 pixel, dependent on output device
152 : : fValue = static_cast< double >( ::oox::drawingml::convertHmmToEmu(
153 : : bPixelX ?
154 : 0 : rGraphicHelper.convertScreenPixelXToHmm( fValue ) :
155 [ # # ][ # # ]: 120 : rGraphicHelper.convertScreenPixelYToHmm( fValue ) ) );
[ # # ]
156 : : }
157 [ # # ][ # # ]: 0 : else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') )
[ # # ]
158 : : {
159 : 0 : fValue *= nRefValue / 100.0;
160 : : }
161 [ # # ][ # # ]: 0 : else if( bDefaultAsPixel || !aUnit.isEmpty() ) // default as EMU and no unit -> do nothing
[ # # ]
162 : : {
163 : : OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - unknown measure unit" );
164 : 0 : fValue = nRefValue;
165 : : }
166 : 249 : return static_cast< sal_Int64 >( fValue + 0.5 );
167 : : }
168 : :
169 : 246 : /*static*/ sal_Int32 ConversionHelper::decodeMeasureToHmm( const GraphicHelper& rGraphicHelper,
170 : : const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
171 : : {
172 : 246 : return ::oox::drawingml::convertEmuToHmm( decodeMeasureToEmu( rGraphicHelper, rValue, nRefValue, bPixelX, bDefaultAsPixel ) );
173 : : }
174 : :
175 : 54 : /*static*/ Color ConversionHelper::decodeColor( const GraphicHelper& rGraphicHelper,
176 : : const OptValue< OUString >& roVmlColor, const OptValue< double >& roVmlOpacity,
177 : : sal_Int32 nDefaultRgb, sal_Int32 nPrimaryRgb )
178 : : {
179 [ + - ]: 54 : Color aDmlColor;
180 : :
181 : : // convert opacity
182 : 54 : const sal_Int32 DML_FULL_OPAQUE = ::oox::drawingml::MAX_PERCENT;
183 : 54 : double fOpacity = roVmlOpacity.get( 1.0 );
184 [ + - ]: 54 : sal_Int32 nOpacity = getLimitedValue< sal_Int32, double >( fOpacity * DML_FULL_OPAQUE, 0, DML_FULL_OPAQUE );
185 [ - + ]: 54 : if( nOpacity < DML_FULL_OPAQUE )
186 [ # # ]: 0 : aDmlColor.addTransformation( XML_alpha, nOpacity );
187 : :
188 : : // color attribute not present - set passed default color
189 [ + + ]: 54 : if( !roVmlColor.has() )
190 : : {
191 [ + - ]: 42 : aDmlColor.setSrgbClr( nDefaultRgb );
192 : : return aDmlColor;
193 : : }
194 : :
195 : : // separate leading color name or RGB value from following palette index
196 : 12 : OUString aColorName, aColorIndex;
197 [ + - ]: 12 : separatePair( aColorName, aColorIndex, roVmlColor.get(), ' ' );
198 : :
199 : : // RGB colors in the format '#RRGGBB'
200 [ + + ][ + - ]: 12 : if( (aColorName.getLength() == 7) && (aColorName[ 0 ] == '#') )
[ + + ]
201 : : {
202 [ + - ]: 9 : aDmlColor.setSrgbClr( aColorName.copy( 1 ).toInt32( 16 ) );
203 : : return aDmlColor;
204 : : }
205 : :
206 : : // RGB colors in the format '#RGB'
207 [ + - ][ - + ]: 3 : if( (aColorName.getLength() == 4) && (aColorName[ 0 ] == '#') )
[ - + ]
208 : : {
209 : 0 : sal_Int32 nR = aColorName.copy( 1, 1 ).toInt32( 16 ) * 0x11;
210 : 0 : sal_Int32 nG = aColorName.copy( 2, 1 ).toInt32( 16 ) * 0x11;
211 : 0 : sal_Int32 nB = aColorName.copy( 3, 1 ).toInt32( 16 ) * 0x11;
212 [ # # ]: 0 : aDmlColor.setSrgbClr( (nR << 16) | (nG << 8) | nB );
213 : : return aDmlColor;
214 : : }
215 : :
216 : : /* Predefined color names or system color names (resolve to RGB to detect
217 : : valid color name). */
218 [ + - ]: 3 : sal_Int32 nColorToken = AttributeConversion::decodeToken( aColorName );
219 [ + - ]: 3 : sal_Int32 nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT );
220 [ - + ]: 3 : if( nRgbValue == API_RGB_TRANSPARENT )
221 [ # # ]: 0 : nRgbValue = rGraphicHelper.getSystemColor( nColorToken, API_RGB_TRANSPARENT );
222 [ + - ]: 3 : if( nRgbValue != API_RGB_TRANSPARENT )
223 : : {
224 [ + - ]: 3 : aDmlColor.setSrgbClr( nRgbValue );
225 : : return aDmlColor;
226 : : }
227 : :
228 : : // try palette colors enclosed in brackets
229 [ # # ][ # # ]: 0 : if( (aColorIndex.getLength() >= 3) && (aColorIndex[ 0 ] == '[') && (aColorIndex[ aColorIndex.getLength() - 1 ] == ']') )
[ # # ][ # # ]
230 : : {
231 [ # # ]: 0 : aDmlColor.setPaletteClr( aColorIndex.copy( 1, aColorIndex.getLength() - 2 ).toInt32() );
232 : : return aDmlColor;
233 : : }
234 : :
235 : : // try fill gradient modificator 'fill <modifier>(<amount>)'
236 [ # # ][ # # ]: 0 : if( (nPrimaryRgb != API_RGB_TRANSPARENT) && (nColorToken == XML_fill) )
237 : : {
238 : 0 : sal_Int32 nOpenParen = aColorIndex.indexOf( '(' );
239 : 0 : sal_Int32 nCloseParen = aColorIndex.indexOf( ')' );
240 [ # # ][ # # ]: 0 : if( (2 <= nOpenParen) && (nOpenParen + 1 < nCloseParen) && (nCloseParen + 1 == aColorIndex.getLength()) )
[ # # ][ # # ]
241 : : {
242 : 0 : sal_Int32 nModToken = XML_TOKEN_INVALID;
243 [ # # ]: 0 : switch( AttributeConversion::decodeToken( aColorIndex.copy( 0, nOpenParen ) ) )
[ # # # ]
244 : : {
245 : 0 : case XML_darken: nModToken = XML_shade;break;
246 : 0 : case XML_lighten: nModToken = XML_tint;
247 : : }
248 : 0 : sal_Int32 nValue = aColorIndex.copy( nOpenParen + 1, nCloseParen - nOpenParen - 1 ).toInt32();
249 [ # # ][ # # ]: 0 : if( (nModToken != XML_TOKEN_INVALID) && (0 <= nValue) && (nValue < 255) )
[ # # ]
250 : : {
251 : : /* Simulate this modifier color by a color with related transformation.
252 : : The modifier amount has to be converted from the range [0;255] to
253 : : percentage [0;100000] used by DrawingML. */
254 [ # # ]: 0 : aDmlColor.setSrgbClr( nPrimaryRgb );
255 [ # # ]: 0 : aDmlColor.addTransformation( nModToken, static_cast< sal_Int32 >( nValue * ::oox::drawingml::MAX_PERCENT / 255 ) );
256 : : return aDmlColor;
257 : : }
258 : : }
259 : : }
260 : :
261 : : OSL_FAIL( OStringBuffer( "lclGetColor - invalid VML color name '" ).
262 : : append( OUStringToOString( roVmlColor.get(), RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() );
263 [ # # ]: 0 : aDmlColor.setSrgbClr( nDefaultRgb );
264 : 54 : return aDmlColor;
265 : : }
266 : :
267 : : // ============================================================================
268 : :
269 : : namespace {
270 : :
271 : 30 : sal_Int64 lclGetEmu( const GraphicHelper& rGraphicHelper, const OptValue< OUString >& roValue, sal_Int64 nDefValue )
272 : : {
273 [ + + ]: 30 : return roValue.has() ? ConversionHelper::decodeMeasureToEmu( rGraphicHelper, roValue.get(), 0, false, false ) : nDefValue;
274 : : }
275 : :
276 : 30 : void lclGetDmlLineDash( OptValue< sal_Int32 >& oroPresetDash, LineProperties::DashStopVector& orCustomDash, const OptValue< OUString >& roDashStyle )
277 : : {
278 [ - + ]: 30 : if( roDashStyle.has() )
279 : : {
280 : 0 : const OUString& rDashStyle = roDashStyle.get();
281 [ # # # # : 0 : switch( AttributeConversion::decodeToken( rDashStyle ) )
# # # # #
# # # ]
282 : : {
283 : 0 : case XML_solid: oroPresetDash = XML_solid; return;
284 : 0 : case XML_shortdot: oroPresetDash = XML_sysDot; return;
285 : 0 : case XML_shortdash: oroPresetDash = XML_sysDash; return;
286 : 0 : case XML_shortdashdot: oroPresetDash = XML_sysDashDot; return;
287 : 0 : case XML_shortdashdotdot: oroPresetDash = XML_sysDashDotDot; return;
288 : 0 : case XML_dot: oroPresetDash = XML_dot; return;
289 : 0 : case XML_dash: oroPresetDash = XML_dash; return;
290 : 0 : case XML_dashdot: oroPresetDash = XML_dashDot; return;
291 : 0 : case XML_longdash: oroPresetDash = XML_lgDash; return;
292 : 0 : case XML_longdashdot: oroPresetDash = XML_lgDashDot; return;
293 : 0 : case XML_longdashdotdot: oroPresetDash = XML_lgDashDotDot; return;
294 : :
295 : : // try to convert user-defined dash style
296 : : default:
297 : : {
298 [ # # ]: 0 : ::std::vector< sal_Int32 > aValues;
299 : 0 : sal_Int32 nIndex = 0;
300 [ # # ]: 0 : while( nIndex >= 0 )
301 [ # # ]: 0 : aValues.push_back( rDashStyle.getToken( 0, ' ', nIndex ).toInt32() );
302 : 0 : size_t nPairs = aValues.size() / 2; // ignore last value if size is odd
303 [ # # ]: 0 : for( size_t nPairIdx = 0; nPairIdx < nPairs; ++nPairIdx )
304 [ # # ][ # # ]: 30 : orCustomDash.push_back( LineProperties::DashStop( aValues[ 2 * nPairIdx ], aValues[ 2 * nPairIdx + 1 ] ) );
[ # # ][ # # ]
305 : : }
306 : : }
307 : : }
308 : : }
309 : :
310 : 60 : sal_Int32 lclGetDmlArrowType( const OptValue< sal_Int32 >& roArrowType )
311 : : {
312 [ + + ][ - + : 60 : if( roArrowType.has() ) switch( roArrowType.get() )
- - - -
- ]
313 : : {
314 : 0 : case XML_none: return XML_none;
315 : 12 : case XML_block: return XML_triangle;
316 : 0 : case XML_classic: return XML_stealth;
317 : 0 : case XML_diamond: return XML_diamond;
318 : 0 : case XML_oval: return XML_oval;
319 : 0 : case XML_open: return XML_arrow;
320 : : }
321 : 60 : return XML_none;
322 : : }
323 : :
324 : 60 : sal_Int32 lclGetDmlArrowWidth( const OptValue< sal_Int32 >& roArrowWidth )
325 : : {
326 [ + + ]: 60 : if( roArrowWidth.has() ) switch( roArrowWidth.get() )
[ - + - - ]
327 : : {
328 : 0 : case XML_narrow: return XML_sm;
329 : 3 : case XML_medium: return XML_med;
330 : 0 : case XML_wide: return XML_lg;
331 : : }
332 : 60 : return XML_med;
333 : : }
334 : :
335 : 60 : sal_Int32 lclGetDmlArrowLength( const OptValue< sal_Int32 >& roArrowLength )
336 : : {
337 [ + + ]: 60 : if( roArrowLength.has() ) switch( roArrowLength.get() )
[ - + - - ]
338 : : {
339 : 0 : case XML_short: return XML_sm;
340 : 3 : case XML_medium: return XML_med;
341 : 0 : case XML_long: return XML_lg;
342 : : }
343 : 60 : return XML_med;
344 : : }
345 : :
346 : 60 : void lclConvertArrow( LineArrowProperties& orArrowProp, const StrokeArrowModel& rStrokeArrow )
347 : : {
348 [ + - ]: 60 : orArrowProp.moArrowType = lclGetDmlArrowType( rStrokeArrow.moArrowType );
349 [ + - ]: 60 : orArrowProp.moArrowWidth = lclGetDmlArrowWidth( rStrokeArrow.moArrowWidth );
350 [ + - ]: 60 : orArrowProp.moArrowLength = lclGetDmlArrowLength( rStrokeArrow.moArrowLength );
351 : 60 : }
352 : :
353 : 30 : sal_Int32 lclGetDmlLineCompound( const OptValue< sal_Int32 >& roLineStyle )
354 : : {
355 [ - + ][ # # : 30 : if( roLineStyle.has() ) switch( roLineStyle.get() )
# # # # ]
356 : : {
357 : 0 : case XML_single: return XML_sng;
358 : 0 : case XML_thinThin: return XML_dbl;
359 : 0 : case XML_thinThick: return XML_thinThick;
360 : 0 : case XML_thickThin: return XML_thickThin;
361 : 0 : case XML_thickBetweenThin: return XML_tri;
362 : : }
363 : 30 : return XML_sng;
364 : : }
365 : :
366 : 30 : sal_Int32 lclGetDmlLineCap( const OptValue< sal_Int32 >& roEndCap )
367 : : {
368 [ - + ]: 30 : if( roEndCap.has() ) switch( roEndCap.get() )
[ # # # # ]
369 : : {
370 : 0 : case XML_flat: return XML_flat;
371 : 0 : case XML_square: return XML_sq;
372 : 0 : case XML_round: return XML_rnd;
373 : : }
374 : 30 : return XML_flat; // different defaults in VML (flat) and DrawingML (square)
375 : : }
376 : :
377 : 30 : sal_Int32 lclGetDmlLineJoint( const OptValue< sal_Int32 >& roJoinStyle )
378 : : {
379 [ + + ]: 30 : if( roJoinStyle.has() ) switch( roJoinStyle.get() )
[ + - + - ]
380 : : {
381 : 3 : case XML_round: return XML_round;
382 : 0 : case XML_bevel: return XML_bevel;
383 : 12 : case XML_miter: return XML_miter;
384 : : }
385 : 30 : return XML_round;
386 : : }
387 : :
388 : : } // namespace
389 : :
390 : : // ============================================================================
391 : :
392 : 54 : void StrokeArrowModel::assignUsed( const StrokeArrowModel& rSource )
393 : : {
394 : 54 : moArrowType.assignIfUsed( rSource.moArrowType );
395 : 54 : moArrowWidth.assignIfUsed( rSource.moArrowWidth );
396 : 54 : moArrowLength.assignIfUsed( rSource.moArrowLength );
397 : 54 : }
398 : :
399 : : // ============================================================================
400 : :
401 : 27 : void StrokeModel::assignUsed( const StrokeModel& rSource )
402 : : {
403 : 27 : moStroked.assignIfUsed( rSource.moStroked );
404 : 27 : maStartArrow.assignUsed( rSource.maStartArrow );
405 : 27 : maEndArrow.assignUsed( rSource.maEndArrow );
406 : 27 : moColor.assignIfUsed( rSource.moColor );
407 : 27 : moOpacity.assignIfUsed( rSource.moOpacity );
408 : 27 : moWeight.assignIfUsed( rSource.moWeight );
409 : 27 : moDashStyle.assignIfUsed( rSource.moDashStyle );
410 : 27 : moLineStyle.assignIfUsed( rSource.moLineStyle );
411 : 27 : moEndCap.assignIfUsed( rSource.moEndCap );
412 : 27 : moJoinStyle.assignIfUsed( rSource.moJoinStyle );
413 : 27 : }
414 : :
415 : 39 : void StrokeModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
416 : : {
417 : : /* Convert VML line formatting to DrawingML line formatting and let the
418 : : DrawingML code do the hard work. */
419 [ + - ]: 39 : LineProperties aLineProps;
420 : :
421 [ + + ]: 39 : if( moStroked.get( true ) )
422 : : {
423 [ + - ]: 30 : aLineProps.maLineFill.moFillType = XML_solidFill;
424 [ + - ]: 30 : lclConvertArrow( aLineProps.maStartArrow, maStartArrow );
425 [ + - ]: 30 : lclConvertArrow( aLineProps.maEndArrow, maEndArrow );
426 [ + - ][ + - ]: 30 : aLineProps.maLineFill.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_BLACK );
[ + - ]
427 [ + - ][ + - ]: 30 : aLineProps.moLineWidth = getLimitedValue< sal_Int32, sal_Int64 >( lclGetEmu( rGraphicHelper, moWeight, 1 ), 0, SAL_MAX_INT32 );
[ + - ]
428 [ + - ]: 30 : lclGetDmlLineDash( aLineProps.moPresetDash, aLineProps.maCustomDash, moDashStyle );
429 [ + - ][ + - ]: 30 : aLineProps.moLineCompound = lclGetDmlLineCompound( moLineStyle );
430 [ + - ][ + - ]: 30 : aLineProps.moLineCap = lclGetDmlLineCap( moEndCap );
431 [ + - ][ + - ]: 30 : aLineProps.moLineJoint = lclGetDmlLineJoint( moJoinStyle );
432 : : }
433 : : else
434 : : {
435 [ + - ]: 9 : aLineProps.maLineFill.moFillType = XML_noFill;
436 : : }
437 : :
438 [ + - ][ + - ]: 39 : aLineProps.pushToPropMap( rPropMap, rGraphicHelper );
439 : 39 : }
440 : :
441 : : // ============================================================================
442 : :
443 : 27 : void FillModel::assignUsed( const FillModel& rSource )
444 : : {
445 : 27 : moFilled.assignIfUsed( rSource.moFilled );
446 : 27 : moColor.assignIfUsed( rSource.moColor );
447 : 27 : moOpacity.assignIfUsed( rSource.moOpacity );
448 : 27 : moColor2.assignIfUsed( rSource.moColor2 );
449 : 27 : moOpacity2.assignIfUsed( rSource.moOpacity2 );
450 : 27 : moType.assignIfUsed( rSource.moType );
451 : 27 : moAngle.assignIfUsed( rSource.moAngle );
452 : 27 : moFocus.assignIfUsed( rSource.moFocus );
453 : 27 : moFocusPos.assignIfUsed( rSource.moFocusPos );
454 : 27 : moFocusSize.assignIfUsed( rSource.moFocusSize );
455 : 27 : moBitmapPath.assignIfUsed( rSource.moBitmapPath );
456 : 27 : moRotate.assignIfUsed( rSource.moRotate );
457 : 27 : }
458 : :
459 : 39 : void FillModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
460 : : {
461 : : /* Convert VML fill formatting to DrawingML fill formatting and let the
462 : : DrawingML code do the hard work. */
463 [ + - ]: 39 : FillProperties aFillProps;
464 : :
465 [ + + ]: 39 : if( moFilled.get( true ) )
466 : : {
467 : 24 : sal_Int32 nFillType = moType.get( XML_solid );
468 [ - - + ]: 24 : switch( nFillType )
469 : : {
470 : : case XML_gradient:
471 : : case XML_gradientRadial:
472 : : {
473 [ # # ]: 0 : aFillProps.moFillType = XML_gradFill;
474 [ # # ]: 0 : aFillProps.maGradientProps.moRotateWithShape = moRotate.get( false );
475 : 0 : double fFocus = moFocus.get( 0.0 );
476 : :
477 : : // prepare colors
478 [ # # ]: 0 : Color aColor1 = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
479 [ # # ][ # # ]: 0 : Color aColor2 = ConversionHelper::decodeColor( rGraphicHelper, moColor2, moOpacity2, API_RGB_WHITE, aColor1.getColor( rGraphicHelper ) );
480 : :
481 : : // type XML_gradient is linear or axial gradient
482 [ # # ]: 0 : if( nFillType == XML_gradient )
483 : : {
484 : : // normalize angle to range [0;360) degrees
485 : 0 : sal_Int32 nVmlAngle = getIntervalValue< sal_Int32, sal_Int32 >( moAngle.get( 0 ), 0, 360 );
486 : :
487 : : // focus of -50% or 50% is axial gradient
488 [ # # ][ # # ]: 0 : if( ((-0.75 <= fFocus) && (fFocus <= -0.25)) || ((0.25 <= fFocus) && (fFocus <= 0.75)) )
[ # # ][ # # ]
489 : : {
490 : : /* According to spec, focus of 50% is outer-to-inner,
491 : : and -50% is inner-to-outer (color to color2).
492 : : BUT: For angles >= 180 deg., the behaviour is
493 : : reversed... that's not spec'ed of course. So,
494 : : [0;180) deg. and 50%, or [180;360) deg. and -50% is
495 : : outer-to-inner in fact. */
496 : 0 : bool bOuterToInner = (fFocus > 0.0) == (nVmlAngle < 180);
497 : : // simulate axial gradient by 3-step DrawingML gradient
498 [ # # ]: 0 : const Color& rOuterColor = bOuterToInner ? aColor1 : aColor2;
499 [ # # ]: 0 : const Color& rInnerColor = bOuterToInner ? aColor2 : aColor1;
500 [ # # ][ # # ]: 0 : aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aFillProps.maGradientProps.maGradientStops[ 1.0 ] = rOuterColor;
[ # # ][ # # ]
501 [ # # ][ # # ]: 0 : aFillProps.maGradientProps.maGradientStops[ 0.5 ] = rInnerColor;
502 : : }
503 : : else // focus of -100%, 0%, and 100% is linear gradient
504 : : {
505 : : /* According to spec, focus of -100% or 100% swaps the
506 : : start and stop colors, effectively reversing the
507 : : gradient. BUT: For angles >= 180 deg., the
508 : : behaviour is reversed. This means that in this case
509 : : a focus of 0% swaps the gradient. */
510 [ # # ][ # # ]: 0 : if( ((fFocus < -0.75) || (fFocus > 0.75)) == (nVmlAngle < 180) )
[ # # ]
511 : 0 : (nVmlAngle += 180) %= 360;
512 : : // set the start and stop colors
513 [ # # ][ # # ]: 0 : aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aColor1;
514 [ # # ][ # # ]: 0 : aFillProps.maGradientProps.maGradientStops[ 1.0 ] = aColor2;
515 : : }
516 : :
517 : : // VML counts counterclockwise from bottom, DrawingML clockwise from left
518 : 0 : sal_Int32 nDmlAngle = (630 - nVmlAngle) % 360;
519 [ # # ]: 0 : aFillProps.maGradientProps.moShadeAngle = nDmlAngle * ::oox::drawingml::PER_DEGREE;
520 : : }
521 : : else // XML_gradientRadial is rectangular gradient
522 : : {
523 [ # # ]: 0 : aFillProps.maGradientProps.moGradientPath = XML_rect;
524 : : // convert VML focus position and size to DrawingML fill-to-rect
525 [ # # ]: 0 : DoublePair aFocusPos = moFocusPos.get( DoublePair( 0.0, 0.0 ) );
526 [ # # ]: 0 : DoublePair aFocusSize = moFocusSize.get( DoublePair( 0.0, 0.0 ) );
527 [ # # ]: 0 : double fLeft = getLimitedValue< double, double >( aFocusPos.first, 0.0, 1.0 );
528 [ # # ]: 0 : double fTop = getLimitedValue< double, double >( aFocusPos.second, 0.0, 1.0 );
529 [ # # ]: 0 : double fRight = getLimitedValue< double, double >( fLeft + aFocusSize.first, fLeft, 1.0 );
530 [ # # ]: 0 : double fBottom = getLimitedValue< double, double >( fTop + aFocusSize.second, fTop, 1.0 );
531 : : aFillProps.maGradientProps.moFillToRect = IntegerRectangle2D(
532 : : static_cast< sal_Int32 >( fLeft * ::oox::drawingml::MAX_PERCENT ),
533 : : static_cast< sal_Int32 >( fTop * ::oox::drawingml::MAX_PERCENT ),
534 : : static_cast< sal_Int32 >( (1.0 - fRight) * ::oox::drawingml::MAX_PERCENT ),
535 [ # # ]: 0 : static_cast< sal_Int32 >( (1.0 - fBottom) * ::oox::drawingml::MAX_PERCENT ) );
536 : :
537 : : // set the start and stop colors (focus of 0% means outer-to-inner)
538 [ # # ][ # # ]: 0 : bool bOuterToInner = (-0.5 <= fFocus) && (fFocus <= 0.5);
539 [ # # ][ # # ]: 0 : aFillProps.maGradientProps.maGradientStops[ 0.0 ] = bOuterToInner ? aColor2 : aColor1;
[ # # ]
540 [ # # ][ # # ]: 0 : aFillProps.maGradientProps.maGradientStops[ 1.0 ] = bOuterToInner ? aColor1 : aColor2;
[ # # ]
541 [ # # ][ # # ]: 0 : }
542 : : }
543 : 0 : break;
544 : :
545 : : case XML_pattern:
546 : : case XML_tile:
547 : : case XML_frame:
548 : : {
549 [ # # ][ # # ]: 0 : if( moBitmapPath.has() && !moBitmapPath.get().isEmpty() )
[ # # ]
550 : : {
551 [ # # ][ # # ]: 0 : aFillProps.maBlipProps.mxGraphic = rGraphicHelper.importEmbeddedGraphic( moBitmapPath.get() );
552 [ # # ]: 0 : if( aFillProps.maBlipProps.mxGraphic.is() )
553 : : {
554 [ # # ]: 0 : aFillProps.moFillType = XML_blipFill;
555 [ # # ][ # # ]: 0 : aFillProps.maBlipProps.moBitmapMode = (nFillType == XML_frame) ? XML_stretch : XML_tile;
556 : 0 : break; // do not break if bitmap is missing, but run to XML_solid instead
557 : : }
558 : : }
559 : : }
560 : : // run-through to XML_solid in case of missing bitmap path intended!
561 : :
562 : : case XML_solid:
563 : : default:
564 : : {
565 [ + - ]: 24 : aFillProps.moFillType = XML_solidFill;
566 : : // fill color (default is white)
567 [ + - ][ + - ]: 24 : aFillProps.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
[ + - ]
568 : : }
569 : : }
570 : : }
571 : : else
572 : : {
573 [ + - ]: 15 : aFillProps.moFillType = XML_noFill;
574 : : }
575 : :
576 [ + - ][ + - ]: 39 : aFillProps.pushToPropMap( rPropMap, rGraphicHelper );
577 : 39 : }
578 : :
579 : : // ============================================================================
580 : :
581 : : } // namespace vml
582 [ + - ][ + - ]: 285 : } // namespace oox
583 : :
584 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|