Bump version to 6.4-15
[LibreOffice.git] / slideshow / source / engine / slide / targetpropertiescreator.cxx
blobc76fd6a1b1a4b4cdf5f1e8d136955b8e71aeeaeb
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 <com/sun/star/uno/XComponentContext.hpp>
21 #include <com/sun/star/lang/XTypeProvider.hpp>
22 #include <com/sun/star/animations/XIterateContainer.hpp>
23 #include <com/sun/star/presentation/ParagraphTarget.hpp>
24 #include <com/sun/star/registry/XRegistryKey.hpp>
25 #include <com/sun/star/drawing/XShape.hpp>
26 #include <com/sun/star/animations/AnimationNodeType.hpp>
27 #include <com/sun/star/animations/XAnimate.hpp>
28 #include <comphelper/sequence.hxx>
30 #include <unordered_map>
31 #include <vector>
33 #include "targetpropertiescreator.hxx"
34 #include <tools.hxx>
36 namespace slideshow
38 namespace internal
40 namespace
42 // Vector containing all properties for a given shape
43 typedef ::std::vector< beans::NamedValue > VectorOfNamedValues;
45 /** The hash map key
47 This key contains both XShape reference and a paragraph
48 index, as we somehow have to handle shape and paragraph
49 targets with the same data structure.
51 struct ShapeHashKey
53 /// Shape target
54 uno::Reference< drawing::XShape > mxRef;
56 /** Paragraph index.
58 If this is a pure shape target, mnParagraphIndex is
59 set to -1.
61 sal_Int16 mnParagraphIndex;
63 /// Comparison needed for unordered_map
64 bool operator==( const ShapeHashKey& rRHS ) const
66 return mxRef == rRHS.mxRef && mnParagraphIndex == rRHS.mnParagraphIndex;
70 // A hash functor for ShapeHashKey objects
71 struct ShapeKeyHasher
73 ::std::size_t operator()( const ShapeHashKey& rKey ) const
75 // TODO(P2): Maybe a better hash function would be to
76 // spread mnParagraphIndex to 32 bit: a0b0c0d0e0... Hakmem
77 // should have a formula.
79 // Yes it has:
80 // x = (x & 0x0000FF00) << 8) | (x >> 8) & 0x0000FF00 | x & 0xFF0000FF;
81 // x = (x & 0x00F000F0) << 4) | (x >> 4) & 0x00F000F0 | x & 0xF00FF00F;
82 // x = (x & 0x0C0C0C0C) << 2) | (x >> 2) & 0x0C0C0C0C | x & 0xC3C3C3C3;
83 // x = (x & 0x22222222) << 1) | (x >> 1) & 0x22222222 | x & 0x99999999;
85 // Costs about 17 cycles on a RISC machine with infinite
86 // instruction level parallelism (~42 basic
87 // instructions). Thus I truly doubt this pays off...
88 return reinterpret_cast< ::std::size_t >(rKey.mxRef.get()) ^ (rKey.mnParagraphIndex << 16);
92 // A hash map which maps a XShape to the corresponding vector of initial properties
93 typedef std::unordered_map< ShapeHashKey, VectorOfNamedValues, ShapeKeyHasher > XShapeHash;
96 class NodeFunctor
98 public:
99 explicit NodeFunctor(
100 XShapeHash& rShapeHash,
101 bool bInitial )
102 : mrShapeHash( rShapeHash ),
103 mxTargetShape(),
104 mnParagraphIndex( -1 ),
105 mbInitial( bInitial)
109 NodeFunctor( XShapeHash& rShapeHash,
110 const uno::Reference< drawing::XShape >& rTargetShape,
111 sal_Int16 nParagraphIndex,
112 bool bInitial) :
113 mrShapeHash( rShapeHash ),
114 mxTargetShape( rTargetShape ),
115 mnParagraphIndex( nParagraphIndex ),
116 mbInitial( bInitial )
120 void operator()( const uno::Reference< animations::XAnimationNode >& xNode ) const
122 if( !xNode.is() )
124 OSL_FAIL( "AnimCore: NodeFunctor::operator(): invalid XAnimationNode" );
125 return;
128 uno::Reference< drawing::XShape > xTargetShape( mxTargetShape );
129 sal_Int16 nParagraphIndex( mnParagraphIndex );
131 switch( xNode->getType() )
133 case animations::AnimationNodeType::ITERATE:
135 // extract target shape from iterate node
136 // (will override the target for all children)
138 uno::Reference< animations::XIterateContainer > xIterNode( xNode,
139 uno::UNO_QUERY );
141 // TODO(E1): I'm not too sure what to expect here...
142 if( !xIterNode->getTarget().hasValue() )
144 OSL_FAIL( "animcore: NodeFunctor::operator(): no target on ITERATE node" );
145 return;
148 xTargetShape.set( xIterNode->getTarget(),
149 uno::UNO_QUERY );
151 if( !xTargetShape.is() )
153 css::presentation::ParagraphTarget aTarget;
155 // no shape provided. Maybe a ParagraphTarget?
156 if( !(xIterNode->getTarget() >>= aTarget) )
158 OSL_FAIL( "animcore: NodeFunctor::operator(): could not extract any "
159 "target information" );
160 return;
163 xTargetShape = aTarget.Shape;
164 nParagraphIndex = aTarget.Paragraph;
166 if( !xTargetShape.is() )
168 OSL_FAIL( "animcore: NodeFunctor::operator(): invalid shape in ParagraphTarget" );
169 return;
172 [[fallthrough]];
174 case animations::AnimationNodeType::PAR:
175 case animations::AnimationNodeType::SEQ:
177 /// forward bInitial
178 NodeFunctor aFunctor( mrShapeHash,
179 xTargetShape,
180 nParagraphIndex,
181 mbInitial );
182 if( !for_each_childNode( xNode, aFunctor ) )
184 OSL_FAIL( "AnimCore: NodeFunctor::operator(): child node iteration failed, "
185 "or extraneous container nodes encountered" );
188 break;
190 case animations::AnimationNodeType::CUSTOM:
191 case animations::AnimationNodeType::ANIMATE:
192 case animations::AnimationNodeType::ANIMATEMOTION:
193 case animations::AnimationNodeType::ANIMATECOLOR:
194 case animations::AnimationNodeType::ANIMATETRANSFORM:
195 case animations::AnimationNodeType::TRANSITIONFILTER:
196 case animations::AnimationNodeType::AUDIO:
197 /*default:
198 // ignore this node, no valuable content for now.
199 break;*/
201 case animations::AnimationNodeType::SET:
203 // evaluate set node content
204 uno::Reference< animations::XAnimate > xAnimateNode( xNode,
205 uno::UNO_QUERY );
207 if( !xAnimateNode.is() )
208 break; // invalid node
210 // determine target shape (if any)
211 ShapeHashKey aTarget;
212 if( xTargetShape.is() )
214 // override target shape with parent-supplied
215 aTarget.mxRef = xTargetShape;
216 aTarget.mnParagraphIndex = nParagraphIndex;
218 else
220 // no parent-supplied target, retrieve
221 // node target
222 if( xAnimateNode->getTarget() >>= aTarget.mxRef )
224 // pure shape target - set paragraph
225 // index to magic
226 aTarget.mnParagraphIndex = -1;
228 else
230 // not a pure shape target - maybe a
231 // ParagraphTarget?
232 presentation::ParagraphTarget aUnoTarget;
234 if( !(xAnimateNode->getTarget() >>= aUnoTarget) )
236 OSL_FAIL( "AnimCore: NodeFunctor::operator(): unknown target type encountered" );
237 break;
240 aTarget.mxRef = aUnoTarget.Shape;
241 aTarget.mnParagraphIndex = aUnoTarget.Paragraph;
245 if( !aTarget.mxRef.is() )
247 OSL_FAIL( "AnimCore: NodeFunctor::operator(): Found target, but XShape is NULL" );
248 break; // invalid target XShape
251 // check whether we already have an entry for
252 // this target (we only take the first set
253 // effect for every shape) - but keep going if
254 // we're requested the final state (which
255 // eventually gets overwritten in the
256 // unordered list, see tdf#96083)
257 if( mbInitial && mrShapeHash.find( aTarget ) != mrShapeHash.end() )
258 break; // already an entry in existence for given XShape
260 // if this is an appear effect, hide shape
261 // initially. This is currently the only place
262 // where a shape effect influences shape
263 // attributes outside it's effective duration.
264 bool bVisible( false );
265 if( xAnimateNode->getAttributeName().equalsIgnoreAsciiCase("visibility") )
268 uno::Any aAny( xAnimateNode->getTo() );
270 // try to extract bool value
271 if( !(aAny >>= bVisible) )
273 // try to extract string
274 OUString aString;
275 if( aAny >>= aString )
277 // we also take the strings "true" and "false",
278 // as well as "on" and "off" here
279 if( aString.equalsIgnoreAsciiCase("true") ||
280 aString.equalsIgnoreAsciiCase("on") )
282 bVisible = true;
284 if( aString.equalsIgnoreAsciiCase("false") ||
285 aString.equalsIgnoreAsciiCase("off") )
287 bVisible = false;
293 // if initial anim sets shape visible, set it
294 // to invisible. If we're asked for the final
295 // state, don't do anything obviously
296 if(mbInitial)
297 bVisible = !bVisible;
299 // target is set the 'visible' value,
300 // so we should record the opposite value
301 mrShapeHash.emplace(
302 aTarget,
303 VectorOfNamedValues(
305 beans::NamedValue(
306 //xAnimateNode->getAttributeName(),
307 "visibility",
308 uno::makeAny( bVisible ) ) ) );
309 break;
314 private:
315 XShapeHash& mrShapeHash;
316 uno::Reference< drawing::XShape > mxTargetShape;
317 sal_Int16 const mnParagraphIndex;
319 // get initial or final state
320 bool const mbInitial;
324 uno::Sequence< animations::TargetProperties > TargetPropertiesCreator::createTargetProperties
326 const uno::Reference< animations::XAnimationNode >& xRootNode,
327 bool bInitial
328 ) //throw (uno::RuntimeException, std::exception)
330 // scan all nodes for visibility changes, and record first
331 // 'visibility=true' for each shape
332 XShapeHash aShapeHash( 101 );
334 NodeFunctor aFunctor(
335 aShapeHash,
336 bInitial );
338 // TODO(F1): Maybe limit functor application to main sequence
339 // alone (CL said something that shape visibility is only
340 // affected by effects in the main sequence for PPT).
342 // OTOH, client code can pass us only the main sequence (which
343 // it actually does right now, for the slideshow implementation).
344 aFunctor( xRootNode );
346 // output to result sequence
347 uno::Sequence< animations::TargetProperties > aRes( aShapeHash.size() );
349 ::std::size_t nCurrIndex(0);
350 for( const auto& rIter : aShapeHash )
352 animations::TargetProperties& rCurrProps( aRes[ nCurrIndex++ ] );
354 if( rIter.first.mnParagraphIndex == -1 )
356 rCurrProps.Target <<= rIter.first.mxRef;
358 else
360 rCurrProps.Target <<=
361 presentation::ParagraphTarget(
362 rIter.first.mxRef,
363 rIter.first.mnParagraphIndex );
366 rCurrProps.Properties = ::comphelper::containerToSequence( rIter.second );
369 return aRes;
372 } // namespace internal
373 } // namespace slideshow
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */