fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / oox / source / drawingml / lineproperties.cxx
blob09432ab3db729dcf6207d8198999d52552c5ea76
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "oox/drawingml/lineproperties.hxx"
21 #include <vector>
22 #include <rtl/ustrbuf.hxx>
23 #include <com/sun/star/beans/NamedValue.hpp>
24 #include <com/sun/star/container/XNameContainer.hpp>
25 #include <com/sun/star/drawing/FlagSequence.hpp>
26 #include <com/sun/star/drawing/LineDash.hpp>
27 #include <com/sun/star/drawing/LineJoint.hpp>
28 #include <com/sun/star/drawing/LineStyle.hpp>
29 #include <com/sun/star/drawing/PointSequence.hpp>
30 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
31 #include "oox/drawingml/drawingmltypes.hxx"
32 #include "oox/drawingml/shapepropertymap.hxx"
33 #include "oox/helper/containerhelper.hxx"
34 #include "oox/helper/graphichelper.hxx"
35 #include "oox/token/tokens.hxx"
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::beans;
39 using namespace ::com::sun::star::drawing;
41 using ::com::sun::star::uno::Any;
42 using ::com::sun::star::uno::Reference;
43 using ::com::sun::star::container::XNameContainer;
45 namespace oox {
46 namespace drawingml {
48 // ============================================================================
50 namespace {
52 void lclSetDashData( LineDash& orLineDash, sal_Int16 nDots, sal_Int32 nDotLen,
53 sal_Int16 nDashes, sal_Int32 nDashLen, sal_Int32 nDistance )
55 orLineDash.Dots = nDots;
56 orLineDash.DotLen = nDotLen;
57 orLineDash.Dashes = nDashes;
58 orLineDash.DashLen = nDashLen;
59 orLineDash.Distance = nDistance;
62 /** Converts the specified preset dash to API dash.
64 Line length and dot length are set relative to line width and have to be
65 multiplied by the actual line width after this function.
67 void lclConvertPresetDash( LineDash& orLineDash, sal_Int32 nPresetDash )
69 switch( nPresetDash )
71 case XML_dot: lclSetDashData( orLineDash, 1, 1, 0, 0, 3 ); break;
72 case XML_dash: lclSetDashData( orLineDash, 0, 0, 1, 4, 3 ); break;
73 case XML_dashDot: lclSetDashData( orLineDash, 1, 1, 1, 4, 3 ); break;
75 case XML_lgDash: lclSetDashData( orLineDash, 0, 0, 1, 8, 3 ); break;
76 case XML_lgDashDot: lclSetDashData( orLineDash, 1, 1, 1, 8, 3 ); break;
77 case XML_lgDashDotDot: lclSetDashData( orLineDash, 2, 1, 1, 8, 3 ); break;
79 case XML_sysDot: lclSetDashData( orLineDash, 1, 1, 0, 0, 1 ); break;
80 case XML_sysDash: lclSetDashData( orLineDash, 0, 0, 1, 3, 1 ); break;
81 case XML_sysDashDot: lclSetDashData( orLineDash, 1, 1, 1, 3, 1 ); break;
82 case XML_sysDashDotDot: lclSetDashData( orLineDash, 2, 1, 1, 3, 1 ); break;
84 default:
85 OSL_FAIL( "lclConvertPresetDash - unsupported preset dash" );
86 lclSetDashData( orLineDash, 0, 0, 1, 4, 3 );
90 /** Converts the passed custom dash to API dash.
92 Line length and dot length are set relative to line width and have to be
93 multiplied by the actual line width after this function.
95 void lclConvertCustomDash( LineDash& orLineDash, const LineProperties::DashStopVector& rCustomDash )
97 if( rCustomDash.empty() )
99 OSL_FAIL( "lclConvertCustomDash - unexpected empty custom dash" );
100 lclSetDashData( orLineDash, 0, 0, 1, 4, 3 );
101 return;
104 // count dashes and dots (stops equal or less than 2 are assumed to be dots)
105 sal_Int16 nDots = 0;
106 sal_Int32 nDotLen = 0;
107 sal_Int16 nDashes = 0;
108 sal_Int32 nDashLen = 0;
109 sal_Int32 nDistance = 0;
110 for( LineProperties::DashStopVector::const_iterator aIt = rCustomDash.begin(), aEnd = rCustomDash.end(); aIt != aEnd; ++aIt )
112 if( aIt->first <= 2 )
114 ++nDots;
115 nDotLen += aIt->first;
117 else
119 ++nDashes;
120 nDashLen += aIt->first;
122 nDistance += aIt->second;
124 orLineDash.DotLen = (nDots > 0) ? ::std::max< sal_Int32 >( nDotLen / nDots, 1 ) : 0;
125 orLineDash.Dots = nDots;
126 orLineDash.DashLen = (nDashes > 0) ? ::std::max< sal_Int32 >( nDashLen / nDashes, 1 ) : 0;
127 orLineDash.Dashes = nDashes;
128 orLineDash.Distance = ::std::max< sal_Int32 >( nDistance / rCustomDash.size(), 1 );
131 DashStyle lclGetDashStyle( sal_Int32 nToken )
133 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
134 switch( nToken )
136 case XML_rnd: return DashStyle_ROUNDRELATIVE;
137 case XML_sq: return DashStyle_RECTRELATIVE;
138 case XML_flat: return DashStyle_RECT;
140 return DashStyle_ROUNDRELATIVE;
143 LineJoint lclGetLineJoint( sal_Int32 nToken )
145 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
146 switch( nToken )
148 case XML_round: return LineJoint_ROUND;
149 case XML_bevel: return LineJoint_BEVEL;
150 case XML_miter: return LineJoint_MITER;
152 return LineJoint_ROUND;
155 const sal_Int32 OOX_ARROWSIZE_SMALL = 0;
156 const sal_Int32 OOX_ARROWSIZE_MEDIUM = 1;
157 const sal_Int32 OOX_ARROWSIZE_LARGE = 2;
159 sal_Int32 lclGetArrowSize( sal_Int32 nToken )
161 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
162 switch( nToken )
164 case XML_sm: return OOX_ARROWSIZE_SMALL;
165 case XML_med: return OOX_ARROWSIZE_MEDIUM;
166 case XML_lg: return OOX_ARROWSIZE_LARGE;
168 return OOX_ARROWSIZE_MEDIUM;
171 // ----------------------------------------------------------------------------
173 void lclPushMarkerProperties( ShapePropertyMap& rPropMap,
174 const LineArrowProperties& rArrowProps, sal_Int32 nLineWidth, bool bLineEnd )
176 /* Store the marker polygon and the marker name in a single value, to be
177 able to pass both to the ShapePropertyMap::setProperty() function. */
178 NamedValue aNamedMarker;
180 OUStringBuffer aBuffer;
181 sal_Int32 nMarkerWidth = 0;
182 bool bMarkerCenter = false;
183 sal_Int32 nArrowType = rArrowProps.moArrowType.get( XML_none );
184 OSL_ASSERT((nArrowType & sal_Int32(0xFFFF0000))==0);
185 switch( nArrowType )
187 case XML_triangle:
188 aBuffer.append( "msArrowEnd" );
189 break;
190 case XML_arrow:
191 aBuffer.append( "msArrowOpenEnd" );
192 break;
193 case XML_stealth:
194 aBuffer.append( "msArrowStealthEnd" );
195 break;
196 case XML_diamond:
197 aBuffer.append( "msArrowDiamondEnd" );
198 bMarkerCenter = true;
199 break;
200 case XML_oval:
201 aBuffer.append( "msArrowOvalEnd" );
202 bMarkerCenter = true;
203 break;
206 if( aBuffer.getLength() > 0 )
208 sal_Int32 nLength = lclGetArrowSize( rArrowProps.moArrowLength.get( XML_med ) );
209 sal_Int32 nWidth = lclGetArrowSize( rArrowProps.moArrowWidth.get( XML_med ) );
211 sal_Int32 nNameIndex = nWidth * 3 + nLength + 1;
212 aBuffer.append( sal_Unicode( ' ' ) ).append( nNameIndex );
213 OUString aMarkerName = aBuffer.makeStringAndClear();
215 bool bIsArrow = nArrowType == XML_arrow;
216 double fArrowLength = 1.0;
217 switch( nLength )
219 case OOX_ARROWSIZE_SMALL: fArrowLength = (bIsArrow ? 3.5 : 2.0); break;
220 case OOX_ARROWSIZE_MEDIUM: fArrowLength = (bIsArrow ? 4.5 : 3.0); break;
221 case OOX_ARROWSIZE_LARGE: fArrowLength = (bIsArrow ? 6.0 : 5.0); break;
223 double fArrowWidth = 1.0;
224 switch( nWidth )
226 case OOX_ARROWSIZE_SMALL: fArrowWidth = (bIsArrow ? 3.5 : 2.0); break;
227 case OOX_ARROWSIZE_MEDIUM: fArrowWidth = (bIsArrow ? 4.5 : 3.0); break;
228 case OOX_ARROWSIZE_LARGE: fArrowWidth = (bIsArrow ? 6.0 : 5.0); break;
230 // set arrow width relative to line width
231 sal_Int32 nBaseLineWidth = ::std::max< sal_Int32 >( nLineWidth, 70 );
232 nMarkerWidth = static_cast< sal_Int32 >( fArrowWidth * nBaseLineWidth );
234 /* Test if the marker already exists in the marker table, do not
235 create it again in this case. If markers are inserted explicitly
236 instead by their name, the polygon will be created always.
237 TODO: this can be optimized by using a map. */
238 if( !rPropMap.hasNamedLineMarkerInTable( aMarkerName ) )
240 // pass X and Y as percentage to OOX_ARROW_POINT
241 #define OOX_ARROW_POINT( x, y ) awt::Point( static_cast< sal_Int32 >( fArrowWidth * x ), static_cast< sal_Int32 >( fArrowLength * y ) )
243 ::std::vector< awt::Point > aPoints;
244 OSL_ASSERT((rArrowProps.moArrowType.get() & sal_Int32(0xFFFF0000))==0);
245 switch( rArrowProps.moArrowType.get() )
247 case XML_triangle:
248 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
249 aPoints.push_back( OOX_ARROW_POINT( 100, 100 ) );
250 aPoints.push_back( OOX_ARROW_POINT( 0, 100 ) );
251 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
252 break;
253 case XML_arrow:
254 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
255 aPoints.push_back( OOX_ARROW_POINT( 100, 91 ) );
256 aPoints.push_back( OOX_ARROW_POINT( 85, 100 ) );
257 aPoints.push_back( OOX_ARROW_POINT( 50, 36 ) );
258 aPoints.push_back( OOX_ARROW_POINT( 15, 100 ) );
259 aPoints.push_back( OOX_ARROW_POINT( 0, 91 ) );
260 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
261 break;
262 case XML_stealth:
263 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
264 aPoints.push_back( OOX_ARROW_POINT( 100, 100 ) );
265 aPoints.push_back( OOX_ARROW_POINT( 50, 60 ) );
266 aPoints.push_back( OOX_ARROW_POINT( 0, 100 ) );
267 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
268 break;
269 case XML_diamond:
270 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
271 aPoints.push_back( OOX_ARROW_POINT( 100, 50 ) );
272 aPoints.push_back( OOX_ARROW_POINT( 50, 100 ) );
273 aPoints.push_back( OOX_ARROW_POINT( 0, 50 ) );
274 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
275 break;
276 case XML_oval:
277 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
278 aPoints.push_back( OOX_ARROW_POINT( 75, 7 ) );
279 aPoints.push_back( OOX_ARROW_POINT( 93, 25 ) );
280 aPoints.push_back( OOX_ARROW_POINT( 100, 50 ) );
281 aPoints.push_back( OOX_ARROW_POINT( 93, 75 ) );
282 aPoints.push_back( OOX_ARROW_POINT( 75, 93 ) );
283 aPoints.push_back( OOX_ARROW_POINT( 50, 100 ) );
284 aPoints.push_back( OOX_ARROW_POINT( 25, 93 ) );
285 aPoints.push_back( OOX_ARROW_POINT( 7, 75 ) );
286 aPoints.push_back( OOX_ARROW_POINT( 0, 50 ) );
287 aPoints.push_back( OOX_ARROW_POINT( 7, 25 ) );
288 aPoints.push_back( OOX_ARROW_POINT( 25, 7 ) );
289 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
290 break;
292 #undef OOX_ARROW_POINT
294 OSL_ENSURE( !aPoints.empty(), "lclPushMarkerProperties - missing arrow coordinates" );
295 if( !aPoints.empty() )
297 PolyPolygonBezierCoords aMarkerCoords;
298 aMarkerCoords.Coordinates.realloc( 1 );
299 aMarkerCoords.Coordinates[ 0 ] = ContainerHelper::vectorToSequence( aPoints );
301 ::std::vector< PolygonFlags > aFlags( aPoints.size(), PolygonFlags_NORMAL );
302 aMarkerCoords.Flags.realloc( 1 );
303 aMarkerCoords.Flags[ 0 ] = ContainerHelper::vectorToSequence( aFlags );
305 aNamedMarker.Name = aMarkerName;
306 aNamedMarker.Value <<= aMarkerCoords;
309 else
311 /* Named marker object exists already in the marker table, pass
312 its name only. This will set the name as property value, but
313 does not create a new object in the marker table. */
314 aNamedMarker.Name = aMarkerName;
318 // push the properties (filled aNamedMarker.Name indicates valid marker)
319 if( !aNamedMarker.Name.isEmpty() )
321 if( bLineEnd )
323 rPropMap.setProperty( SHAPEPROP_LineEnd, aNamedMarker );
324 rPropMap.setProperty( SHAPEPROP_LineEndWidth, nMarkerWidth );
325 rPropMap.setProperty( SHAPEPROP_LineEndCenter, bMarkerCenter );
327 else
329 rPropMap.setProperty( SHAPEPROP_LineStart, aNamedMarker );
330 rPropMap.setProperty( SHAPEPROP_LineStartWidth, nMarkerWidth );
331 rPropMap.setProperty( SHAPEPROP_LineStartCenter, bMarkerCenter );
336 } // namespace
338 // ============================================================================
340 void LineArrowProperties::assignUsed( const LineArrowProperties& rSourceProps )
342 moArrowType.assignIfUsed( rSourceProps.moArrowType );
343 moArrowWidth.assignIfUsed( rSourceProps.moArrowWidth );
344 moArrowLength.assignIfUsed( rSourceProps.moArrowLength );
347 // ============================================================================
349 void LineProperties::assignUsed( const LineProperties& rSourceProps )
351 maStartArrow.assignUsed( rSourceProps.maStartArrow );
352 maEndArrow.assignUsed( rSourceProps.maEndArrow );
353 maLineFill.assignUsed( rSourceProps.maLineFill );
354 if( !rSourceProps.maCustomDash.empty() )
355 maCustomDash = rSourceProps.maCustomDash;
356 moLineWidth.assignIfUsed( rSourceProps.moLineWidth );
357 moPresetDash.assignIfUsed( rSourceProps.moPresetDash );
358 moLineCompound.assignIfUsed( rSourceProps.moLineCompound );
359 moLineCap.assignIfUsed( rSourceProps.moLineCap );
360 moLineJoint.assignIfUsed( rSourceProps.moLineJoint );
363 void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
364 const GraphicHelper& rGraphicHelper, sal_Int32 nPhClr ) const
366 // line fill type must exist, otherwise ignore other properties
367 if( maLineFill.moFillType.has() )
369 // line style (our core only supports none and solid)
370 drawing::LineStyle eLineStyle = (maLineFill.moFillType.get() == XML_noFill) ? drawing::LineStyle_NONE : drawing::LineStyle_SOLID;
372 // convert line width from EMUs to 1/100mm
373 sal_Int32 nLineWidth = convertEmuToHmm( moLineWidth.get( 0 ) );
375 // create line dash from preset dash token (not for invisible line)
376 if( (eLineStyle != drawing::LineStyle_NONE) && (moPresetDash.differsFrom( XML_solid ) || (!moPresetDash && !maCustomDash.empty())) )
378 LineDash aLineDash;
379 aLineDash.Style = lclGetDashStyle( moLineCap.get( XML_rnd ) );
381 // convert preset dash or custom dash
382 if( moPresetDash.has() )
383 lclConvertPresetDash( aLineDash, moPresetDash.get() );
384 else
385 lclConvertCustomDash( aLineDash, maCustomDash );
387 // convert relative dash/dot length to absolute length
388 sal_Int32 nBaseLineWidth = ::std::max< sal_Int32 >( nLineWidth, 35 );
389 aLineDash.DotLen *= nBaseLineWidth;
390 aLineDash.DashLen *= nBaseLineWidth;
391 aLineDash.Distance *= nBaseLineWidth;
393 if( rPropMap.setProperty( SHAPEPROP_LineDash, aLineDash ) )
394 eLineStyle = drawing::LineStyle_DASH;
397 // set final line style property
398 rPropMap.setProperty( SHAPEPROP_LineStyle, eLineStyle );
400 // line joint type
401 if( moLineJoint.has() )
402 rPropMap.setProperty( SHAPEPROP_LineJoint, lclGetLineJoint( moLineJoint.get() ) );
404 // line width in 1/100mm
405 rPropMap.setProperty( SHAPEPROP_LineWidth, nLineWidth );
407 // line color and transparence
408 Color aLineColor = maLineFill.getBestSolidColor();
409 if( aLineColor.isUsed() )
411 rPropMap.setProperty( SHAPEPROP_LineColor, aLineColor.getColor( rGraphicHelper, nPhClr ) );
412 if( aLineColor.hasTransparency() )
413 rPropMap.setProperty( SHAPEPROP_LineTransparency, aLineColor.getTransparency() );
416 // line markers
417 lclPushMarkerProperties( rPropMap, maStartArrow, nLineWidth, false );
418 lclPushMarkerProperties( rPropMap, maEndArrow, nLineWidth, true );
422 // ============================================================================
424 } // namespace drawingml
425 } // namespace oox
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */