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 : :
21 : : #include <canvas/debug.hxx>
22 : : #include <tools/diagnose_ex.h>
23 : : #include <tools/helpers.hxx>
24 : : #include <canvas/elapsedtime.hxx>
25 : : #include <basegfx/polygon/b2dpolygontools.hxx>
26 : :
27 : : #include <comphelper/anytostring.hxx>
28 : : #include <cppuhelper/exc_hlp.hxx>
29 : :
30 : : #include <rtl/math.hxx>
31 : : #include <vcl/metric.hxx>
32 : : #include <vcl/canvastools.hxx>
33 : : #include <vcl/metaact.hxx>
34 : : #include <com/sun/star/beans/XPropertySet.hpp>
35 : : #include <com/sun/star/drawing/TextAnimationKind.hpp>
36 : : #include <com/sun/star/drawing/TextAnimationDirection.hpp>
37 : : #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
38 : : #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
39 : : #include <com/sun/star/drawing/HomogenMatrix3.hpp>
40 : : #include <com/sun/star/awt/Rectangle.hpp>
41 : :
42 : : #include "activity.hxx"
43 : : #include "wakeupevent.hxx"
44 : : #include "eventqueue.hxx"
45 : : #include "drawshapesubsetting.hxx"
46 : : #include "drawshape.hxx"
47 : : #include "shapesubset.hxx"
48 : : #include "shapeattributelayerholder.hxx"
49 : : #include "slideshowcontext.hxx"
50 : : #include "tools.hxx"
51 : : #include "gdimtftools.hxx"
52 : : #include "eventmultiplexer.hxx"
53 : : #include "intrinsicanimationactivity.hxx"
54 : : #include "intrinsicanimationeventhandler.hxx"
55 : :
56 : : #include <boost/weak_ptr.hpp>
57 : : #include <boost/enable_shared_from_this.hpp>
58 : : #include <boost/noncopyable.hpp>
59 : : #include <vector>
60 : :
61 : : using namespace com::sun::star;
62 : : using namespace ::slideshow::internal;
63 : :
64 : : namespace {
65 : :
66 : : class ScrollTextAnimNode
67 : : {
68 : : sal_uInt32 mnDuration; // single duration
69 : : sal_uInt32 mnRepeat; // 0 -> endless
70 : : double mfStart;
71 : : double mfStop;
72 : : sal_uInt32 mnFrequency; // in ms
73 : : // forth and back change at mnRepeat%2:
74 : : bool mbAlternate;
75 : :
76 : : public:
77 : 0 : ScrollTextAnimNode(
78 : : sal_uInt32 nDuration, sal_uInt32 nRepeat, double fStart, double fStop,
79 : : sal_uInt32 nFrequency, bool bAlternate)
80 : : : mnDuration(nDuration),
81 : : mnRepeat(nRepeat),
82 : : mfStart(fStart),
83 : : mfStop(fStop),
84 : : mnFrequency(nFrequency),
85 : 0 : mbAlternate(bAlternate)
86 : 0 : {}
87 : :
88 : : sal_uInt32 GetDuration() const { return mnDuration; }
89 : 0 : sal_uInt32 GetRepeat() const { return mnRepeat; }
90 : 0 : sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; }
91 : : double GetStart() const { return mfStart; }
92 : 0 : double GetStop() const { return mfStop; }
93 : 0 : sal_uInt32 GetFrequency() const { return mnFrequency; }
94 : 0 : bool DoAlternate() const { return mbAlternate; }
95 : :
96 : : double GetStateAtRelativeTime(sal_uInt32 nRelativeTime) const;
97 : : };
98 : :
99 : 0 : double ScrollTextAnimNode::GetStateAtRelativeTime(
100 : : sal_uInt32 nRelativeTime) const
101 : : {
102 : : // Avoid division by zero.
103 : 0 : if( mnDuration == 0 )
104 : 0 : return mfStop;
105 : :
106 : 0 : if(mnRepeat)
107 : : {
108 : : // ending
109 : 0 : const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
110 : 0 : sal_uInt32 nFrameTime(nRelativeTime - (nRepeatCount * mnDuration));
111 : :
112 : 0 : if(DoAlternate() && (nRepeatCount + 1L) % 2L)
113 : 0 : nFrameTime = mnDuration - nFrameTime;
114 : :
115 : : return mfStart + ((mfStop - mfStart) *
116 : 0 : (double(nFrameTime) / mnDuration));
117 : : }
118 : : else
119 : : {
120 : : // endless
121 : 0 : sal_uInt32 nFrameTime(nRelativeTime % mnDuration);
122 : :
123 : 0 : if(DoAlternate())
124 : : {
125 : 0 : const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
126 : :
127 : 0 : if((nRepeatCount + 1L) % 2L)
128 : 0 : nFrameTime = mnDuration - nFrameTime;
129 : : }
130 : :
131 : 0 : return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration));
132 : : }
133 : : }
134 : :
135 : : class ActivityImpl : public Activity,
136 : : public boost::enable_shared_from_this<ActivityImpl>,
137 : : private boost::noncopyable
138 : : {
139 : : public:
140 : : virtual ~ActivityImpl();
141 : :
142 : : ActivityImpl(
143 : : SlideShowContext const& rContext,
144 : : boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
145 : : boost::shared_ptr<DrawShape> const& pDrawShape );
146 : :
147 : : bool enableAnimations();
148 : :
149 : : // Disposable:
150 : : virtual void dispose();
151 : : // Activity:
152 : : virtual double calcTimeLag() const;
153 : : virtual bool perform();
154 : : virtual bool isActive() const;
155 : : virtual void dequeued();
156 : : virtual void end();
157 : :
158 : : private:
159 : : void updateShapeAttributes( double fTime,
160 : : basegfx::B2DRectangle const& parentBounds );
161 : :
162 : : // Access to VisibleWhenSTarted flags
163 : 0 : sal_Bool IsVisibleWhenStarted() const { return mbVisibleWhenStarted; }
164 : 0 : sal_Bool IsVisibleWhenStopped() const { return mbVisibleWhenStopped; }
165 : :
166 : : // scroll horizontal? if sal_False, scroll is vertical.
167 : 0 : bool ScrollHorizontal() const {
168 : : return (drawing::TextAnimationDirection_LEFT == meDirection ||
169 : 0 : drawing::TextAnimationDirection_RIGHT == meDirection);
170 : : }
171 : :
172 : : // Access to StepWidth in logical units
173 : : sal_uInt32 GetStepWidthLogic() const;
174 : :
175 : : // is the animation direction opposite?
176 : 0 : bool DoScrollForward() const {
177 : : return (drawing::TextAnimationDirection_RIGHT == meDirection ||
178 : 0 : drawing::TextAnimationDirection_DOWN == meDirection);
179 : : }
180 : :
181 : : // do alternate text directions?
182 : 0 : bool DoAlternate() const { return mbAlternate; }
183 : :
184 : : // do scroll in?
185 : 0 : bool DoScrollIn() const { return mbScrollIn; }
186 : :
187 : : // Scroll helper methods
188 : : void ImpForceScrollTextAnimNodes();
189 : : ScrollTextAnimNode* ImpGetScrollTextAnimNode(
190 : : sal_uInt32 nTime, sal_uInt32& rRelativeTime );
191 : : sal_uInt32 ImpRegisterAgainScrollTextMixerState(
192 : : sal_uInt32 nTime);
193 : :
194 : : // calculate the MixerState value for given time
195 : : double GetMixerState(sal_uInt32 nTime);
196 : :
197 : : ////////////////////////////////////////////////////////////////////
198 : :
199 : : SlideShowContext maContext;
200 : : boost::shared_ptr<WakeupEvent> mpWakeupEvent;
201 : : boost::weak_ptr<DrawShape> mpParentDrawShape;
202 : : DrawShapeSharedPtr mpDrawShape;
203 : : ShapeAttributeLayerHolder maShapeAttrLayer;
204 : : GDIMetaFileSharedPtr mpMetaFile;
205 : : IntrinsicAnimationEventHandlerSharedPtr mpListener;
206 : : canvas::tools::ElapsedTime maTimer;
207 : : double mfRotationAngle;
208 : : bool mbIsShapeAnimated;
209 : : bool mbIsDisposed;
210 : : bool mbIsActive;
211 : : drawing::TextAnimationKind meAnimKind;
212 : :
213 : : // The blink frequency in ms
214 : : sal_uInt32 mnFrequency;
215 : :
216 : : // The repeat count, init to 0L which means endless
217 : : sal_uInt32 mnRepeat;
218 : :
219 : : // Flag to decide if text will be shown when animation has ended
220 : : bool mbVisibleWhenStopped;
221 : : bool mbVisibleWhenStarted;
222 : :
223 : : // Flag decides if TextScroll alternates. Default is sal_False.
224 : : bool mbAlternate;
225 : :
226 : : // Flag to remember if this is a simple scrollin text
227 : : bool mbScrollIn;
228 : :
229 : : // start time for this animation
230 : : sal_uInt32 mnStartTime;
231 : :
232 : : // The AnimationDirection
233 : : drawing::TextAnimationDirection meDirection;
234 : :
235 : : // Get width per Step. Negative means pixel, positive logical units
236 : : sal_Int32 mnStepWidth;
237 : :
238 : : // The single anim steps
239 : : std::vector< ScrollTextAnimNode > maVector;
240 : :
241 : : // the scroll rectangle
242 : : Rectangle maScrollRectangleLogic;
243 : :
244 : : // the paint rectangle
245 : : Rectangle maPaintRectangleLogic;
246 : : };
247 : :
248 : : //////////////////////////////////////////////////////////////////////
249 : :
250 : 0 : class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
251 : : private boost::noncopyable
252 : : {
253 : : public:
254 : 0 : explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) :
255 : 0 : mrActivity( rActivity )
256 : 0 : {}
257 : :
258 : : private:
259 : :
260 : 0 : virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
261 : 0 : virtual bool disableAnimations() { mrActivity.end(); return true; }
262 : :
263 : : ActivityImpl& mrActivity;
264 : : };
265 : :
266 : : //////////////////////////////////////////////////////////////////////
267 : :
268 : 0 : double ActivityImpl::GetMixerState( sal_uInt32 nTime )
269 : : {
270 : 0 : if( meAnimKind == drawing::TextAnimationKind_BLINK )
271 : : {
272 : : // from AInfoBlinkText:
273 : 0 : double fRetval(0.0);
274 : 0 : sal_Bool bDone(sal_False);
275 : 0 : const sal_uInt32 nLoopTime(2 * mnFrequency);
276 : :
277 : 0 : if(mnRepeat)
278 : : {
279 : 0 : const sal_uInt32 nEndTime(mnRepeat * nLoopTime);
280 : :
281 : 0 : if(nTime >= nEndTime)
282 : : {
283 : 0 : if(mbVisibleWhenStopped)
284 : 0 : fRetval = 0.0;
285 : : else
286 : 0 : fRetval = 1.0;
287 : :
288 : 0 : bDone = sal_True;
289 : : }
290 : : }
291 : :
292 : 0 : if(!bDone)
293 : : {
294 : 0 : sal_uInt32 nTimeInLoop(nTime % nLoopTime);
295 : 0 : fRetval = double(nTimeInLoop) / nLoopTime;
296 : : }
297 : :
298 : 0 : return fRetval;
299 : : }
300 : : else
301 : : {
302 : : // from AInfoScrollText:
303 : 0 : double fRetval(0.0);
304 : 0 : ImpForceScrollTextAnimNodes();
305 : :
306 : 0 : if(!maVector.empty())
307 : : {
308 : : sal_uInt32 nRelativeTime;
309 : : ScrollTextAnimNode* pNode =
310 : 0 : ImpGetScrollTextAnimNode(nTime, nRelativeTime);
311 : :
312 : 0 : if(pNode)
313 : : {
314 : : // use node
315 : 0 : fRetval = pNode->GetStateAtRelativeTime(nRelativeTime);
316 : : }
317 : : else
318 : : {
319 : : // end of animation, take last entry's end
320 : 0 : fRetval = maVector[maVector.size() - 1L].GetStop();
321 : : }
322 : : }
323 : :
324 : 0 : return fRetval;
325 : : }
326 : : }
327 : :
328 : : // Access to StepWidth in logical units
329 : 0 : sal_uInt32 ActivityImpl::GetStepWidthLogic() const
330 : : {
331 : : // #i69847# Assuming higher DPI
332 : 0 : sal_uInt32 const PIXEL_TO_LOGIC = 30;
333 : :
334 : 0 : sal_uInt32 nRetval(0L);
335 : :
336 : 0 : if(mnStepWidth < 0L)
337 : : {
338 : : // is in pixels, convert to logical units
339 : 0 : nRetval = (-mnStepWidth * PIXEL_TO_LOGIC);
340 : : }
341 : 0 : else if(mnStepWidth > 0L)
342 : : {
343 : : // is in logical units
344 : 0 : nRetval = mnStepWidth;
345 : : }
346 : :
347 : 0 : if(0L == nRetval)
348 : : {
349 : : // step 1 pixel, canned value
350 : :
351 : : // with very high DPIs like in PDF export, this can
352 : : // still get zero. for that cases, set a default, too (taken
353 : : // from ainfoscrolltext.cxx)
354 : 0 : nRetval = 100L;
355 : : }
356 : :
357 : 0 : return nRetval;
358 : : }
359 : :
360 : 0 : void ActivityImpl::ImpForceScrollTextAnimNodes()
361 : : {
362 : 0 : if(maVector.empty())
363 : : {
364 : : // prepare values
365 : : sal_uInt32 nLoopTime;
366 : : double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic;
367 : 0 : double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0;
368 : : double fZeroRelative, fOneRelative, fInitRelative;
369 : :
370 : 0 : if(ScrollHorizontal())
371 : : {
372 : 0 : if(DoAlternate())
373 : : {
374 : 0 : if(maPaintRectangleLogic.GetWidth() >
375 : 0 : maScrollRectangleLogic.GetWidth())
376 : : {
377 : 0 : fZeroLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
378 : 0 : fOneLogicAlternate = maScrollRectangleLogic.Left();
379 : : }
380 : : else
381 : : {
382 : 0 : fZeroLogicAlternate = maScrollRectangleLogic.Left();
383 : 0 : fOneLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
384 : : }
385 : : }
386 : :
387 : 0 : fZeroLogic = maScrollRectangleLogic.Left() - maPaintRectangleLogic.GetWidth();
388 : 0 : fOneLogic = maScrollRectangleLogic.Right();
389 : 0 : fInitLogic = maPaintRectangleLogic.Left();
390 : : }
391 : : else
392 : : {
393 : 0 : if(DoAlternate())
394 : : {
395 : 0 : if(maPaintRectangleLogic.GetHeight() > maScrollRectangleLogic.GetHeight())
396 : : {
397 : 0 : fZeroLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
398 : 0 : fOneLogicAlternate = maScrollRectangleLogic.Top();
399 : : }
400 : : else
401 : : {
402 : 0 : fZeroLogicAlternate = maScrollRectangleLogic.Top();
403 : 0 : fOneLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
404 : : }
405 : : }
406 : :
407 : 0 : fZeroLogic = maScrollRectangleLogic.Top() - maPaintRectangleLogic.GetHeight();
408 : 0 : fOneLogic = maScrollRectangleLogic.Bottom();
409 : 0 : fInitLogic = maPaintRectangleLogic.Top();
410 : : }
411 : :
412 : 0 : fDistanceLogic = fOneLogic - fZeroLogic;
413 : 0 : fInitRelative = (fInitLogic - fZeroLogic) / fDistanceLogic;
414 : :
415 : 0 : if(DoAlternate())
416 : : {
417 : : fZeroRelative =
418 : 0 : (fZeroLogicAlternate - fZeroLogic) / fDistanceLogic;
419 : : fOneRelative =
420 : 0 : (fOneLogicAlternate - fZeroLogic) / fDistanceLogic;
421 : : }
422 : : else
423 : : {
424 : 0 : fZeroRelative = 0.0;
425 : 0 : fOneRelative = 1.0;
426 : : }
427 : :
428 : 0 : if(mnStartTime)
429 : : {
430 : : // Start time loop
431 : : ScrollTextAnimNode aStartNode(
432 : 0 : mnStartTime, 1L, 0.0, 0.0, mnStartTime, false);
433 : 0 : maVector.push_back(aStartNode);
434 : : }
435 : :
436 : 0 : if(IsVisibleWhenStarted())
437 : : {
438 : : double fRelativeStartValue, fRelativeEndValue,fRelativeDistance;
439 : :
440 : 0 : if(DoScrollForward())
441 : : {
442 : 0 : fRelativeStartValue = fInitRelative;
443 : 0 : fRelativeEndValue = fOneRelative;
444 : 0 : fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
445 : : }
446 : : else
447 : : {
448 : 0 : fRelativeStartValue = fInitRelative;
449 : 0 : fRelativeEndValue = fZeroRelative;
450 : 0 : fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
451 : : }
452 : :
453 : : const double fNumberSteps =
454 : 0 : (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
455 : 0 : nLoopTime = FRound(fNumberSteps * mnFrequency);
456 : :
457 : : // init loop
458 : : ScrollTextAnimNode aInitNode(
459 : : nLoopTime, 1L,
460 : : fRelativeStartValue, fRelativeEndValue,
461 : 0 : mnFrequency, false);
462 : 0 : maVector.push_back(aInitNode);
463 : : }
464 : :
465 : : // prepare main loop values
466 : : {
467 : : double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
468 : :
469 : 0 : if(DoScrollForward())
470 : : {
471 : 0 : fRelativeStartValue = fZeroRelative;
472 : 0 : fRelativeEndValue = fOneRelative;
473 : 0 : fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
474 : : }
475 : : else
476 : : {
477 : 0 : fRelativeStartValue = fOneRelative;
478 : 0 : fRelativeEndValue = fZeroRelative;
479 : 0 : fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
480 : : }
481 : :
482 : : const double fNumberSteps =
483 : 0 : (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
484 : 0 : nLoopTime = FRound(fNumberSteps * mnFrequency);
485 : :
486 : 0 : if(0L == mnRepeat)
487 : : {
488 : 0 : if(!DoScrollIn())
489 : : {
490 : : // endless main loop
491 : : ScrollTextAnimNode aMainNode(
492 : : nLoopTime, 0L,
493 : : fRelativeStartValue, fRelativeEndValue,
494 : 0 : mnFrequency, DoAlternate());
495 : 0 : maVector.push_back(aMainNode);
496 : : }
497 : : }
498 : : else
499 : : {
500 : 0 : sal_uInt32 nNumRepeat(mnRepeat);
501 : :
502 : 0 : if(DoAlternate() && (nNumRepeat + 1L) % 2L)
503 : 0 : nNumRepeat += 1L;
504 : :
505 : : // ending main loop
506 : : ScrollTextAnimNode aMainNode(
507 : : nLoopTime, nNumRepeat,
508 : : fRelativeStartValue, fRelativeEndValue,
509 : 0 : mnFrequency, DoAlternate());
510 : 0 : maVector.push_back(aMainNode);
511 : : }
512 : : }
513 : :
514 : 0 : if(IsVisibleWhenStopped())
515 : : {
516 : : double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
517 : :
518 : 0 : if(DoScrollForward())
519 : : {
520 : 0 : fRelativeStartValue = fZeroRelative;
521 : 0 : fRelativeEndValue = fInitRelative;
522 : 0 : fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
523 : : }
524 : : else
525 : : {
526 : 0 : fRelativeStartValue = fOneRelative;
527 : 0 : fRelativeEndValue = fInitRelative;
528 : 0 : fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
529 : : }
530 : :
531 : : const double fNumberSteps =
532 : 0 : (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
533 : 0 : nLoopTime = FRound(fNumberSteps * mnFrequency);
534 : :
535 : : // exit loop
536 : : ScrollTextAnimNode aExitNode(
537 : : nLoopTime, 1L,
538 : 0 : fRelativeStartValue, fRelativeEndValue, mnFrequency, false);
539 : 0 : maVector.push_back(aExitNode);
540 : : }
541 : : }
542 : 0 : }
543 : :
544 : 0 : ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode(
545 : : sal_uInt32 nTime, sal_uInt32& rRelativeTime )
546 : : {
547 : 0 : ScrollTextAnimNode* pRetval = 0L;
548 : 0 : ImpForceScrollTextAnimNodes();
549 : :
550 : 0 : if(!maVector.empty())
551 : : {
552 : 0 : rRelativeTime = nTime;
553 : :
554 : 0 : for(sal_uInt32 a(0L); !pRetval && a < maVector.size(); a++)
555 : : {
556 : 0 : ScrollTextAnimNode & rNode = maVector[a];
557 : 0 : if(!rNode.GetRepeat())
558 : : {
559 : : // endless loop, use it
560 : 0 : pRetval = &rNode;
561 : : }
562 : 0 : else if(rNode.GetFullTime() > rRelativeTime)
563 : : {
564 : : // ending node
565 : 0 : pRetval = &rNode;
566 : : }
567 : : else
568 : : {
569 : : // look at next
570 : 0 : rRelativeTime -= rNode.GetFullTime();
571 : : }
572 : : }
573 : : }
574 : :
575 : 0 : return pRetval;
576 : : }
577 : :
578 : 0 : sal_uInt32 ActivityImpl::ImpRegisterAgainScrollTextMixerState(sal_uInt32 nTime)
579 : : {
580 : 0 : sal_uInt32 nRetval(0L);
581 : 0 : ImpForceScrollTextAnimNodes();
582 : :
583 : 0 : if(!maVector.empty())
584 : : {
585 : : sal_uInt32 nRelativeTime;
586 : 0 : ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime);
587 : :
588 : 0 : if(pNode)
589 : : {
590 : : // take register time
591 : 0 : nRetval = pNode->GetFrequency();
592 : : }
593 : : }
594 : : else
595 : : {
596 : : // #i38135# not initialized, return default
597 : 0 : nRetval = mnFrequency;
598 : : }
599 : :
600 : 0 : return nRetval;
601 : : }
602 : :
603 : 0 : void ActivityImpl::updateShapeAttributes(
604 : : double fTime, basegfx::B2DRectangle const& parentBounds )
605 : : {
606 : : OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
607 : 0 : if( meAnimKind == drawing::TextAnimationKind_NONE )
608 : 0 : return;
609 : :
610 : : double const fMixerState = GetMixerState(
611 : 0 : static_cast<sal_uInt32>(fTime * 1000.0) );
612 : :
613 : 0 : if( meAnimKind == drawing::TextAnimationKind_BLINK )
614 : : {
615 : : // show/hide text:
616 : 0 : maShapeAttrLayer.get()->setVisibility( fMixerState < 0.5 );
617 : : }
618 : 0 : else if(mpMetaFile) // scroll mode:
619 : : {
620 : : //
621 : : // keep care: the below code is highly sensible to changes...
622 : : //
623 : :
624 : : // rectangle of the pure text:
625 : 0 : double const fPaintWidth = maPaintRectangleLogic.GetWidth();
626 : 0 : double const fPaintHeight = maPaintRectangleLogic.GetHeight();
627 : : // rectangle where the scrolling takes place (-> clipping):
628 : 0 : double const fScrollWidth = maScrollRectangleLogic.GetWidth();
629 : 0 : double const fScrollHeight = maScrollRectangleLogic.GetHeight();
630 : :
631 : 0 : basegfx::B2DPoint pos, clipPos;
632 : :
633 : 0 : if(ScrollHorizontal())
634 : : {
635 : 0 : double const fOneEquiv( fScrollWidth );
636 : 0 : double const fZeroEquiv( -fPaintWidth );
637 : :
638 : 0 : pos.setX( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
639 : :
640 : 0 : clipPos.setX( -pos.getX() );
641 : 0 : clipPos.setY( -pos.getY() );
642 : :
643 : : // #i69844# Compensation for text-wider-than-shape case
644 : 0 : if( fPaintWidth > fScrollWidth )
645 : 0 : pos.setX( pos.getX() + (fPaintWidth-fScrollWidth) / 2.0 );
646 : : }
647 : : else
648 : : {
649 : : // scroll vertical:
650 : 0 : double const fOneEquiv( fScrollHeight );
651 : 0 : double const fZeroEquiv( -fPaintHeight );
652 : :
653 : 0 : pos.setY( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
654 : :
655 : 0 : clipPos.setX( -pos.getX() );
656 : 0 : clipPos.setY( -pos.getY() );
657 : :
658 : : // #i69844# Compensation for text-higher-than-shape case
659 : 0 : if( fPaintHeight > fScrollHeight )
660 : 0 : pos.setY( pos.getY() + (fPaintHeight-fScrollHeight) / 2.0 );
661 : : }
662 : :
663 : : basegfx::B2DPolygon clipPoly(
664 : : basegfx::tools::createPolygonFromRect(
665 : : basegfx::B2DRectangle( clipPos.getX(),
666 : : clipPos.getY(),
667 : 0 : clipPos.getX() + fScrollWidth,
668 : 0 : clipPos.getY() + fScrollHeight ) ) );
669 : :
670 : 0 : if( !::basegfx::fTools::equalZero( mfRotationAngle ))
671 : : {
672 : 0 : maShapeAttrLayer.get()->setRotationAngle( mfRotationAngle );
673 : 0 : double const fRotate = (mfRotationAngle * M_PI / 180.0);
674 : 0 : basegfx::B2DHomMatrix aTransform;
675 : : // position:
676 : 0 : aTransform.rotate( fRotate );
677 : 0 : pos *= aTransform;
678 : : }
679 : :
680 : 0 : pos += parentBounds.getCenter();
681 : 0 : maShapeAttrLayer.get()->setPosition( pos );
682 : 0 : maShapeAttrLayer.get()->setClip( basegfx::B2DPolyPolygon(clipPoly) );
683 : : }
684 : : }
685 : :
686 : 0 : bool ActivityImpl::perform()
687 : : {
688 : 0 : if( !isActive() )
689 : 0 : return false;
690 : :
691 : 0 : ENSURE_OR_RETURN_FALSE(
692 : : mpDrawShape,
693 : : "ActivityImpl::perform(): still active, but NULL draw shape" );
694 : :
695 : 0 : DrawShapeSharedPtr const pParentDrawShape( mpParentDrawShape );
696 : 0 : if( !pParentDrawShape )
697 : 0 : return false; // parent has vanished
698 : :
699 : 0 : if( pParentDrawShape->isVisible() )
700 : : {
701 : 0 : if( !mbIsShapeAnimated )
702 : : {
703 : 0 : mpDrawShape->setVisibility(true); // shape may be initially hidden
704 : 0 : maContext.mpSubsettableShapeManager->enterAnimationMode( mpDrawShape );
705 : 0 : maTimer.reset();
706 : 0 : mbIsShapeAnimated = true;
707 : : }
708 : : // update attributes related to current time:
709 : : basegfx::B2DRectangle const parentBounds(
710 : 0 : pParentDrawShape->getBounds() );
711 : :
712 : 0 : const double nCurrTime( maTimer.getElapsedTime() );
713 : 0 : updateShapeAttributes( nCurrTime, parentBounds );
714 : :
715 : : const sal_uInt32 nFrequency(
716 : : ImpRegisterAgainScrollTextMixerState(
717 : 0 : static_cast<sal_uInt32>(nCurrTime * 1000.0)) );
718 : :
719 : 0 : if(nFrequency)
720 : : {
721 : 0 : mpWakeupEvent->start();
722 : : mpWakeupEvent->setNextTimeout(
723 : 0 : std::max(0.1,nFrequency/1000.0) );
724 : 0 : maContext.mrEventQueue.addEvent( mpWakeupEvent );
725 : :
726 : 0 : if( mpDrawShape->isContentChanged() )
727 : 0 : maContext.mpSubsettableShapeManager->notifyShapeUpdate( mpDrawShape );
728 : : }
729 : : // else: finished, not need to wake up again.
730 : : }
731 : : else
732 : : {
733 : : // busy-wait, until parent shape gets visible
734 : 0 : mpWakeupEvent->start();
735 : 0 : mpWakeupEvent->setNextTimeout( 2.0 );
736 : : }
737 : :
738 : : // don't reinsert, WakeupEvent will perform that after the given timeout:
739 : 0 : return false;
740 : : }
741 : :
742 : 0 : ActivityImpl::ActivityImpl(
743 : : SlideShowContext const& rContext,
744 : : boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
745 : : boost::shared_ptr<DrawShape> const& pParentDrawShape )
746 : : : maContext(rContext),
747 : : mpWakeupEvent(pWakeupEvent),
748 : : mpParentDrawShape(pParentDrawShape),
749 : 0 : mpListener( new IntrinsicAnimationListener(*this) ),
750 : 0 : maTimer(rContext.mrEventQueue.getTimer()),
751 : : mbIsShapeAnimated(false),
752 : : mbIsDisposed(false),
753 : : mbIsActive(true),
754 : : meAnimKind(drawing::TextAnimationKind_NONE),
755 : 0 : mnStartTime(0L)
756 : : {
757 : : // get doctreenode:
758 : 0 : sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes(
759 : 0 : DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH );
760 : :
761 : : DocTreeNode scrollTextNode(
762 : 0 : pParentDrawShape->getTreeNode(
763 : 0 : 0, DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ));
764 : : // xxx todo: remove this hack
765 : 0 : if( nNodes > 1 )
766 : : scrollTextNode.setEndIndex(
767 : 0 : pParentDrawShape->getTreeNode(
768 : : nNodes - 1,
769 : 0 : DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ).getEndIndex());
770 : :
771 : : // TODO(Q3): Doing this manually, instead of using
772 : : // ShapeSubset. This is because of lifetime issues (ShapeSubset
773 : : // generates circular references to parent shape)
774 : : mpDrawShape = boost::dynamic_pointer_cast<DrawShape>(
775 : 0 : maContext.mpSubsettableShapeManager->getSubsetShape(
776 : : pParentDrawShape,
777 : 0 : scrollTextNode ));
778 : :
779 : 0 : mpMetaFile = mpDrawShape->forceScrollTextMetaFile();
780 : :
781 : : // make scroll text invisible for slide transition bitmaps
782 : 0 : mpDrawShape->setVisibility(false);
783 : :
784 : 0 : basegfx::B2DRectangle aScrollRect, aPaintRect;
785 : 0 : ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
786 : : aPaintRect,
787 : : mpMetaFile ),
788 : : "ActivityImpl::ActivityImpl(): Could not extract "
789 : : "scroll anim rectangles from mtf" );
790 : :
791 : : maScrollRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
792 : 0 : aScrollRect );
793 : : maPaintRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
794 : 0 : aPaintRect );
795 : :
796 : 0 : maShapeAttrLayer.createAttributeLayer(mpDrawShape);
797 : :
798 : 0 : uno::Reference<drawing::XShape> const xShape( mpDrawShape->getXShape() );
799 : 0 : uno::Reference<beans::XPropertySet> const xProps( xShape, uno::UNO_QUERY_THROW );
800 : :
801 : 0 : getPropertyValue( meAnimKind, xProps, OUSTR("TextAnimationKind") );
802 : : OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
803 : 0 : mbAlternate = (meAnimKind == drawing::TextAnimationKind_ALTERNATE);
804 : 0 : mbScrollIn = (meAnimKind == drawing::TextAnimationKind_SLIDE);
805 : :
806 : : // adopted from in AInfoBlinkText::ImplInit():
807 : 0 : sal_Int16 nRepeat(0);
808 : 0 : getPropertyValue( nRepeat, xProps, OUSTR("TextAnimationCount") );
809 : 0 : mnRepeat = nRepeat;
810 : :
811 : 0 : if(mbAlternate)
812 : : {
813 : : // force visible when started for scroll-forth-and-back, because
814 : : // slide has been coming in with visible text in the middle:
815 : 0 : mbVisibleWhenStarted = true;
816 : : }
817 : : else
818 : : {
819 : : getPropertyValue( mbVisibleWhenStarted, xProps,
820 : 0 : OUSTR("TextAnimationStartInside") );
821 : : }
822 : :
823 : : // set visible when stopped
824 : : getPropertyValue( mbVisibleWhenStopped, xProps,
825 : 0 : OUSTR("TextAnimatiogonStopInside") );
826 : : // rotation:
827 : : getPropertyValue( mfRotationAngle, xProps,
828 : 0 : OUSTR("RotateAngle") );
829 : 0 : mfRotationAngle /= -100.0; // (switching direction)
830 : :
831 : : // set frequency
832 : 0 : sal_Int16 nDelay(0);
833 : 0 : getPropertyValue( nDelay, xProps, OUSTR("TextAnimationDelay") );
834 : : // set delay if not automatic
835 : : mnFrequency = (nDelay ? nDelay :
836 : : // default:
837 : : meAnimKind == drawing::TextAnimationKind_BLINK
838 : 0 : ? 250L : 50L );
839 : :
840 : : // adopted from in AInfoScrollText::ImplInit():
841 : :
842 : : // If it is a simple m_bScrollIn, reset some parameters
843 : 0 : if( DoScrollIn() )
844 : : {
845 : : // most parameters are set correctly from the dialog logic, but
846 : : // eg VisisbleWhenStopped is grayed out and needs to be corrected here.
847 : 0 : mbVisibleWhenStopped = true;
848 : 0 : mbVisibleWhenStarted = false;
849 : 0 : mnRepeat = 0L;
850 : : }
851 : :
852 : : // Get animation direction
853 : 0 : getPropertyValue( meDirection, xProps, OUSTR("TextAnimationDirection") );
854 : :
855 : : // Get step width. Negative means pixel, positive logical units
856 : 0 : getPropertyValue( mnStepWidth, xProps, OUSTR("TextAnimationAmount") );
857 : :
858 : 0 : maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
859 : 0 : mpListener );
860 : 0 : }
861 : :
862 : 0 : bool ActivityImpl::enableAnimations()
863 : : {
864 : 0 : mbIsActive = true;
865 : : return maContext.mrActivitiesQueue.addActivity(
866 : 0 : shared_from_this() );
867 : : }
868 : :
869 : 0 : ActivityImpl::~ActivityImpl()
870 : : {
871 : 0 : }
872 : :
873 : 0 : void ActivityImpl::dispose()
874 : : {
875 : 0 : if( !mbIsDisposed )
876 : : {
877 : 0 : end();
878 : :
879 : : // only remove subset here, since end() is called on slide end
880 : : // (and we must not spoil the slide preview bitmap with scroll
881 : : // text)
882 : 0 : maShapeAttrLayer.reset();
883 : 0 : if( mpDrawShape )
884 : : {
885 : : // TODO(Q3): Doing this manually, instead of using
886 : : // ShapeSubset. This is because of lifetime issues
887 : : // (ShapeSubset generates circular references to parent
888 : : // shape)
889 : 0 : DrawShapeSharedPtr pParent( mpParentDrawShape.lock() );
890 : 0 : if( pParent )
891 : 0 : maContext.mpSubsettableShapeManager->revokeSubset(
892 : : pParent,
893 : 0 : mpDrawShape );
894 : : }
895 : :
896 : 0 : mpMetaFile.reset();
897 : 0 : mpDrawShape.reset();
898 : 0 : mpParentDrawShape.reset();
899 : 0 : mpWakeupEvent.reset();
900 : 0 : maContext.dispose();
901 : 0 : mbIsDisposed = true;
902 : :
903 : 0 : maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
904 : 0 : mpListener );
905 : : }
906 : 0 : }
907 : :
908 : 0 : double ActivityImpl::calcTimeLag() const
909 : : {
910 : 0 : return 0.0;
911 : : }
912 : :
913 : 0 : bool ActivityImpl::isActive() const
914 : : {
915 : 0 : return mbIsActive;
916 : : }
917 : :
918 : 0 : void ActivityImpl::dequeued()
919 : : {
920 : : // not used here
921 : 0 : }
922 : :
923 : 0 : void ActivityImpl::end()
924 : : {
925 : : // not used here
926 : 0 : mbIsActive = false;
927 : :
928 : 0 : if( mbIsShapeAnimated )
929 : : {
930 : 0 : maContext.mpSubsettableShapeManager->leaveAnimationMode( mpDrawShape );
931 : 0 : mbIsShapeAnimated = false;
932 : : }
933 : 0 : }
934 : :
935 : : } // anon namespace
936 : :
937 : : namespace slideshow {
938 : : namespace internal {
939 : :
940 : 0 : boost::shared_ptr<Activity> createDrawingLayerAnimActivity(
941 : : SlideShowContext const& rContext,
942 : : boost::shared_ptr<DrawShape> const& pDrawShape )
943 : : {
944 : 0 : boost::shared_ptr<Activity> pActivity;
945 : :
946 : : try
947 : : {
948 : : boost::shared_ptr<WakeupEvent> const pWakeupEvent(
949 : 0 : new WakeupEvent( rContext.mrEventQueue.getTimer(),
950 : 0 : rContext.mrActivitiesQueue ) );
951 : 0 : pActivity.reset( new ActivityImpl( rContext, pWakeupEvent, pDrawShape ) );
952 : 0 : pWakeupEvent->setActivity( pActivity );
953 : : }
954 : 0 : catch( uno::RuntimeException& )
955 : : {
956 : 0 : throw;
957 : : }
958 : 0 : catch( uno::Exception& )
959 : : {
960 : : // translate any error into empty factory product.
961 : : OSL_FAIL( rtl::OUStringToOString(
962 : : comphelper::anyToString( cppu::getCaughtException() ),
963 : : RTL_TEXTENCODING_UTF8 ).getStr() );
964 : : }
965 : :
966 : 0 : return pActivity;
967 : : }
968 : :
969 : : } // namespace internal
970 : 0 : } // namespace presentation
971 : :
972 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|