1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: targetpropertiescreator.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <com/sun/star/uno/XComponentContext.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/lang/XTypeProvider.hpp>
34 #include <com/sun/star/animations/XTargetPropertiesCreator.hpp>
35 #include <com/sun/star/animations/XIterateContainer.hpp>
36 #include <com/sun/star/animations/TargetProperties.hpp>
37 #include <com/sun/star/presentation/ParagraphTarget.hpp>
38 #include <com/sun/star/registry/XRegistryKey.hpp>
39 #include <com/sun/star/lang/XInitialization.hpp>
40 #include <com/sun/star/lang/XServiceName.hpp>
41 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
42 #include <com/sun/star/drawing/XShape.hpp>
43 #include <com/sun/star/animations/AnimationNodeType.hpp>
44 #include <com/sun/star/animations/XAnimate.hpp>
45 #include <cppuhelper/compbase3.hxx>
46 #include <cppuhelper/factory.hxx>
47 #include <cppuhelper/implementationentry.hxx>
48 #include <comphelper/optionalvalue.hxx>
49 #include <comphelper/broadcasthelper.hxx>
50 #include <comphelper/sequence.hxx>
52 #include <animations/animationnodehelper.hxx>
58 using namespace ::com::sun::star
;
60 #define IMPLEMENTATION_NAME "animcore::TargetPropertiesCreator"
61 #define SERVICE_NAME "com.sun.star.animations.TargetPropertiesCreator"
65 typedef ::cppu::WeakComponentImplHelper3
< ::com::sun::star::animations::XTargetPropertiesCreator
,
67 lang::XServiceName
> TargetPropertiesCreator_Base
;
69 class TargetPropertiesCreator
: public ::comphelper::OBaseMutex
,
70 public TargetPropertiesCreator_Base
73 static uno::Reference
< uno::XInterface
> SAL_CALL
createInstance( const uno::Reference
< uno::XComponentContext
>& xContext
) throw ( uno::Exception
)
75 return uno::Reference
< uno::XInterface
>( static_cast<cppu::OWeakObject
*>(new TargetPropertiesCreator( xContext
)) );
78 /// Dispose all internal references
79 virtual void SAL_CALL
disposing();
81 // XTargetPropertiesCreator
82 virtual uno::Sequence
< animations::TargetProperties
> SAL_CALL
createInitialTargetProperties( const uno::Reference
< animations::XAnimationNode
>& rootNode
) throw (uno::RuntimeException
);
85 virtual ::rtl::OUString SAL_CALL
getImplementationName() throw( uno::RuntimeException
);
86 virtual sal_Bool SAL_CALL
supportsService( const ::rtl::OUString
& ServiceName
) throw( uno::RuntimeException
);
87 virtual uno::Sequence
< ::rtl::OUString
> SAL_CALL
getSupportedServiceNames() throw( uno::RuntimeException
);
90 virtual ::rtl::OUString SAL_CALL
getServiceName( ) throw (uno::RuntimeException
);
93 ~TargetPropertiesCreator(); // we're a ref-counted UNO class. _We_ destroy ourselves.
96 // default: disabled copy/assignment
97 TargetPropertiesCreator(const TargetPropertiesCreator
&);
98 TargetPropertiesCreator
& operator=( const TargetPropertiesCreator
& );
100 TargetPropertiesCreator( const uno::Reference
< uno::XComponentContext
>& rxContext
);
103 // --------------------------------------------------------------------
105 uno::Reference
< uno::XInterface
> SAL_CALL
createInstance_TargetPropertiesCreator( const uno::Reference
< uno::XComponentContext
> & rSMgr
) throw (uno::Exception
)
107 return TargetPropertiesCreator::createInstance( rSMgr
);
110 ::rtl::OUString
getImplementationName_TargetPropertiesCreator()
112 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME
) );
115 uno::Sequence
< ::rtl::OUString
> getSupportedServiceNames_TargetPropertiesCreator(void)
117 uno::Sequence
< ::rtl::OUString
> aRet(1);
118 aRet
.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME
) );
122 // --------------------------------------------------------------------
126 // Vector containing all properties for a given shape
127 typedef ::std::vector
< beans::NamedValue
> VectorOfNamedValues
;
131 This key contains both XShape reference and a paragraph
132 index, as we somehow have to handle shape and paragraph
133 targets with the same data structure.
138 uno::Reference
< drawing::XShape
> mxRef
;
142 If this is a pure shape target, mnParagraphIndex is
145 sal_Int16 mnParagraphIndex
;
147 /// Comparison needed for hash_map
148 bool operator==( const ShapeHashKey
& rRHS
) const
150 return mxRef
== rRHS
.mxRef
&& mnParagraphIndex
== rRHS
.mnParagraphIndex
;
154 // A hash map which maps a XShape to the corresponding vector of initial properties
155 typedef ::std::hash_map
< ShapeHashKey
,
157 ::std::size_t (*)(const ShapeHashKey
&) > XShapeHash
;
159 ::std::size_t refhasher( const ShapeHashKey
& rKey
)
161 // TODO(P2): Maybe a better hash function would be to
162 // spread mnParagraphIndex to 32 bit: a0b0c0d0e0... Hakmem
163 // should have a formula.
166 // x = (x & 0x0000FF00) << 8) | (x >> 8) & 0x0000FF00 | x & 0xFF0000FF;
167 // x = (x & 0x00F000F0) << 4) | (x >> 4) & 0x00F000F0 | x & 0xF00FF00F;
168 // x = (x & 0x0C0C0C0C) << 2) | (x >> 2) & 0x0C0C0C0C | x & 0xC3C3C3C3;
169 // x = (x & 0x22222222) << 1) | (x >> 1) & 0x22222222 | x & 0x99999999;
171 // Costs about 17 cycles on a RISC machine with infinite
172 // instruction level parallelism (~42 basic
173 // instructions). Thus I truly doubt this pays off...
174 return reinterpret_cast< ::std::size_t >(rKey
.mxRef
.get()) ^ (rKey
.mnParagraphIndex
<< 16L);
181 explicit NodeFunctor( XShapeHash
& rShapeHash
) :
182 mrShapeHash( rShapeHash
),
184 mnParagraphIndex( -1 )
188 NodeFunctor( XShapeHash
& rShapeHash
,
189 const uno::Reference
< drawing::XShape
>& rTargetShape
,
190 sal_Int16 nParagraphIndex
) :
191 mrShapeHash( rShapeHash
),
192 mxTargetShape( rTargetShape
),
193 mnParagraphIndex( nParagraphIndex
)
197 void operator()( const uno::Reference
< animations::XAnimationNode
>& xNode
) const
202 "AnimCore: NodeFunctor::operator(): invalid XAnimationNode" );
206 uno::Reference
< drawing::XShape
> xTargetShape( mxTargetShape
);
207 sal_Int16
nParagraphIndex( mnParagraphIndex
);
209 switch( xNode
->getType() )
211 case animations::AnimationNodeType::ITERATE
:
213 // extract target shape from iterate node
214 // (will override the target for all children)
215 // --------------------------------------------------
217 uno::Reference
< animations::XIterateContainer
> xIterNode( xNode
,
220 // TODO(E1): I'm not too sure what to expect here...
221 if( !xIterNode
->getTarget().hasValue() )
224 "animcore: NodeFunctor::operator(): no target on ITERATE node" );
228 xTargetShape
.set( xIterNode
->getTarget(),
231 if( !xTargetShape
.is() )
233 ::com::sun::star::presentation::ParagraphTarget aTarget
;
235 // no shape provided. Maybe a ParagraphTarget?
236 if( !(xIterNode
->getTarget() >>= aTarget
) )
239 "animcore: NodeFunctor::operator(): could not extract any "
240 "target information" );
244 xTargetShape
= aTarget
.Shape
;
245 nParagraphIndex
= aTarget
.Paragraph
;
247 if( !xTargetShape
.is() )
250 "animcore: NodeFunctor::operator(): invalid shape in ParagraphTarget" );
255 // FALLTHROUGH intended
256 case animations::AnimationNodeType::PAR
:
257 // FALLTHROUGH intended
258 case animations::AnimationNodeType::SEQ
:
260 NodeFunctor
aFunctor( mrShapeHash
,
263 if( !::anim::for_each_childNode( xNode
,
267 "AnimCore: NodeFunctor::operator(): child node iteration failed, "
268 "or extraneous container nodes encountered" );
273 case animations::AnimationNodeType::CUSTOM
:
274 // FALLTHROUGH intended
275 case animations::AnimationNodeType::ANIMATE
:
276 // FALLTHROUGH intended
277 case animations::AnimationNodeType::ANIMATEMOTION
:
278 // FALLTHROUGH intended
279 case animations::AnimationNodeType::ANIMATECOLOR
:
280 // FALLTHROUGH intended
281 case animations::AnimationNodeType::ANIMATETRANSFORM
:
282 // FALLTHROUGH intended
283 case animations::AnimationNodeType::TRANSITIONFILTER
:
284 // FALLTHROUGH intended
285 case animations::AnimationNodeType::AUDIO
:
286 // FALLTHROUGH intended
288 // ignore this node, no valuable content for now.
291 case animations::AnimationNodeType::SET
:
293 // evaluate set node content
294 uno::Reference
< animations::XAnimate
> xAnimateNode( xNode
,
297 if( !xAnimateNode
.is() )
298 break; // invalid node
300 // determine target shape (if any)
301 ShapeHashKey aTarget
;
302 if( xTargetShape
.is() )
304 // override target shape with parent-supplied
305 aTarget
.mxRef
= xTargetShape
;
306 aTarget
.mnParagraphIndex
= nParagraphIndex
;
310 // no parent-supplied target, retrieve
312 if( (xAnimateNode
->getTarget() >>= aTarget
.mxRef
) )
314 // pure shape target - set paragraph
316 aTarget
.mnParagraphIndex
= -1;
320 // not a pure shape target - maybe a
322 presentation::ParagraphTarget aUnoTarget
;
324 if( !(xAnimateNode
->getTarget() >>= aUnoTarget
) )
327 "AnimCore: NodeFunctor::operator(): unknown target type encountered" );
331 aTarget
.mxRef
= aUnoTarget
.Shape
;
332 aTarget
.mnParagraphIndex
= aUnoTarget
.Paragraph
;
336 if( !aTarget
.mxRef
.is() )
339 "AnimCore: NodeFunctor::operator(): Found target, but XShape is NULL" );
340 break; // invalid target XShape
343 // check whether we already have an entry for
344 // this target (we only take the first set
345 // effect for every shape)
346 XShapeHash::const_iterator aIter
;
347 if( (aIter
=mrShapeHash
.find( aTarget
)) != mrShapeHash
.end() )
348 break; // already an entry in existence for given XShape
350 // if this is an appear effect, hide shape
351 // initially. This is currently the only place
352 // where a shape effect influences shape
353 // attributes outside it's effective duration.
354 if( xAnimateNode
->getAttributeName().equalsIgnoreAsciiCaseAscii("visibility") )
356 sal_Bool
bVisible( sal_False
);
358 uno::Any
aAny( xAnimateNode
->getTo() );
360 // try to extract bool value
361 if( !(aAny
>>= bVisible
) )
363 // try to extract string
364 ::rtl::OUString aString
;
365 if( (aAny
>>= aString
) )
367 // we also take the strings "true" and "false",
368 // as well as "on" and "off" here
369 if( aString
.equalsIgnoreAsciiCaseAscii("true") ||
370 aString
.equalsIgnoreAsciiCaseAscii("on") )
374 if( aString
.equalsIgnoreAsciiCaseAscii("false") ||
375 aString
.equalsIgnoreAsciiCaseAscii("off") )
377 bVisible
= sal_False
;
384 // target is set to 'visible' at the
385 // first relevant effect. Thus, target
386 // must be initially _hidden_, for the
387 // effect to have visible impact.
389 XShapeHash::value_type(
394 xAnimateNode
->getAttributeName(),
395 uno::makeAny( sal_False
) ) ) ) );
404 XShapeHash
& mrShapeHash
;
405 uno::Reference
< drawing::XShape
> mxTargetShape
;
406 sal_Int16 mnParagraphIndex
;
410 // --------------------------------------------------------------------
412 TargetPropertiesCreator::TargetPropertiesCreator( const uno::Reference
< uno::XComponentContext
>& ) :
413 TargetPropertiesCreator_Base( m_aMutex
)
417 TargetPropertiesCreator::~TargetPropertiesCreator()
421 void SAL_CALL
TargetPropertiesCreator::disposing()
423 ::osl::MutexGuard
aGuard( m_aMutex
);
426 // XTargetPropertiesCreator
427 uno::Sequence
< animations::TargetProperties
> SAL_CALL
TargetPropertiesCreator::createInitialTargetProperties
429 const uno::Reference
< animations::XAnimationNode
>& xRootNode
430 ) throw (uno::RuntimeException
)
432 ::osl::MutexGuard
aGuard( m_aMutex
);
434 // scan all nodes for visibility changes, and record first
435 // 'visibility=true' for each shape
436 XShapeHash
aShapeHash( 101,
439 NodeFunctor
aFunctor( aShapeHash
);
441 // TODO(F1): Maybe limit functor application to main sequence
442 // alone (CL said something that shape visibility is only
443 // affected by effects in the main sequence for PPT).
445 // OTOH, client code can pass us only the main sequence (which
446 // it actually does right now, for the slideshow implementation).
447 aFunctor( xRootNode
);
450 // output to result sequence
451 // ----------------------------------------------------------------------
453 uno::Sequence
< animations::TargetProperties
> aRes( aShapeHash
.size() );
455 ::std::size_t nCurrIndex(0);
456 XShapeHash::const_iterator
aCurr( aShapeHash
.begin() );
457 const XShapeHash::const_iterator
aEnd ( aShapeHash
.end() );
458 while( aCurr
!= aEnd
)
460 animations::TargetProperties
& rCurrProps( aRes
[ nCurrIndex
++ ] );
462 if( aCurr
->first
.mnParagraphIndex
== -1 )
464 rCurrProps
.Target
= uno::makeAny( aCurr
->first
.mxRef
);
468 rCurrProps
.Target
= uno::makeAny(
469 presentation::ParagraphTarget(
471 aCurr
->first
.mnParagraphIndex
) );
474 rCurrProps
.Properties
= ::comphelper::containerToSequence( aCurr
->second
);
483 ::rtl::OUString SAL_CALL
TargetPropertiesCreator::getImplementationName() throw( uno::RuntimeException
)
485 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME
) );
488 sal_Bool SAL_CALL
TargetPropertiesCreator::supportsService( const ::rtl::OUString
& ServiceName
) throw( uno::RuntimeException
)
490 return ServiceName
.equalsIgnoreAsciiCaseAscii( SERVICE_NAME
);
493 uno::Sequence
< ::rtl::OUString
> SAL_CALL
TargetPropertiesCreator::getSupportedServiceNames() throw( uno::RuntimeException
)
495 uno::Sequence
< ::rtl::OUString
> aRet(1);
496 aRet
[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME
) );
502 ::rtl::OUString SAL_CALL
TargetPropertiesCreator::getServiceName( ) throw (uno::RuntimeException
)
504 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME
) );
507 } // namespace animcore