Bug 36664 - Add animation to progress element
Summary: Add animation to progress element
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: 528+ (Nightly build)
Hardware: PC OS X 10.5
: P2 Normal
Assignee: Yael
: 36224 (view as bug list)
Depends on:
Blocks: 36224
  Show dependency treegraph
Reported: 2010-03-26 09:19 PDT by Yael
Modified: 2010-04-01 07:58 PDT (History)
2 users (show)

See Also:

Patch for animation. (18.17 KB, patch)
2010-03-26 11:02 PDT, Yael
koivisto: review-
Details | Formatted Diff | Diff
Adress Antti's comments in #4 (19.72 KB, patch)
2010-03-30 06:53 PDT, Yael
no flags Details | Formatted Diff | Diff
Patch (10.56 KB, patch)
2010-03-30 12:26 PDT, Yael
no flags Details | Formatted Diff | Diff
Patch updated based on comment #8. (11.98 KB, patch)
2010-03-31 09:00 PDT, Yael
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yael 2010-03-26 09:19:57 PDT
Indeterminate progress bar should animate, and on Mac OS even determinate progress bar should animate.
Add a timer and capability to animate the progress bar when needed.
Comment 1 Yael 2010-03-26 11:02:37 PDT
Created attachment 51763 [details]
Patch for animation.

Add a timer to control the animation of the progress bar.
Remove an obsolete function RenderTheme::getNumberOfPixelsForProgressPosition.
Comment 2 Alexey Proskuryakov 2010-03-26 11:42:17 PDT
What stops the animation when the page goes into b/f cache?
Comment 3 Yael 2010-03-26 11:46:59 PDT
(In reply to comment #2)
> What stops the animation when the page goes into b/f cache?

RenderObject::willRenderContents() will return false when the document is in cache, and animation will not start again.
Comment 4 Antti Koivisto 2010-03-29 08:42:23 PDT
Comment on attachment 51763 [details]
Patch for animation.

Looks generally good. I think you should consider doing animations in other way than incrementing frame counter (see below) so r- for now.

> -bool RenderThemeQt::getNumberOfPixelsForProgressPosition(double position, int& progressSize) const
> +double RenderThemeQt::animationIntervalForProgressBar(bool determinate) const
>  {
> -    progressSize = 65536 * position;
> -    return false;
> +    // FIXME: Use hardcoded value until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed.
> +    // Use the value from windows style which is 10 fps.
> +    if (determinate)
> +        return -1;
> +    return 0.1;
>  }

Either 0 (real interval can't be 0) or std::numeric_limits<double>::infinity() would be more natural ways to signal "no animation interval" than slightly random -1.

> -    // Helper method for optimizing the paint area of the progress bar.
> -    // If supported, it returns number of pixels needed to draw the progress bar up to the progress position.
> -    // progressSize is the value that is passed back to RenderTheme during drawing.
> -    virtual bool getNumberOfPixelsForProgressPosition(double position, int& progressSize) const;
> +    // Returns the interval for the progress bar animation, or -1 if no animation is required.
> +    virtual double animationIntervalForProgressBar(bool determinate) const;
>  #endif

Enums are generally preferred over magic bools since it is hard to tell what is going on from the call site.

> > ===================================================================
> --- WebCore/rendering/RenderObject.h	(revision 56630)
> +++ WebCore/rendering/RenderObject.h	(working copy)
> @@ -788,6 +788,8 @@ protected:
>      void paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*);
>      void addPDFURLRect(GraphicsContext*, const IntRect&);
> +    bool willRenderContents();
> +
>      virtual IntRect viewRect() const;

Could be public and next to willRenderImage() in the header

> +void RenderProgress::animationFrameTimerFired(Timer<RenderProgress>*)
> +{
> +    m_animationFrame++;

Usually animation in WebKit is tracked in terms of progress on timeline. Doing animation by increment frame count is not optimal. If you increase the animation frame rate it will also cause the animation to run faster. RenderMedia fade is an example of this type of animation in an existing similar type of control element.

> +    repaintRectangle(contentBoxRect());
> +
> +    IntRect r(contentBoxRect());
> +}

This line does nothing.
Comment 5 Yael 2010-03-30 06:53:21 PDT
Created attachment 52030 [details]
Adress Antti's comments in #4
Comment 6 Antti Koivisto 2010-03-30 09:00:43 PDT
Some stuff I said in IRC about possible ways to clarify responsibilities between theme and the renderer.

[18:39] anttik: so how about this
[18:42] anttik: RenderProgress will have animating state
[18:43] anttik: which is independent of whether the animation is currently happening (since that depends on if it is visible or not)
[18:44] anttik: when entering animating state it records the start time
[18:44] anttik: animationProgress() is calculated from start time, duration and current time
[18:45] anttik: and is used as input for rendering
[18:47] anttik: if in animating state it will restart the animation timer on paint()
[18:48] anttik: actual changes in the progress bar state will trigger changes in and out of the animating state
[18:49] anttik: possibly querying style if a given progress bar state needs animation or not
[18:51] anttik: so paint() will have if (m_animating) m_startOneShot(m_repeatInterval)
[18:51] anttik: and start/stopAnimation() will do state transitions
[18:51] anttik: m_animationTimer.startOneShot()
[18:53] anttik: that should lead to a clear split of responsibility
[18:53] anttik: does that sound stupid?
Comment 7 Yael 2010-03-30 12:26:29 PDT
Created attachment 52069 [details]

Update the design as siggested on IRC (comment #6).
Some changes 
- Renamed startAnimation() to updateAnimationState() because it is not starting the animation timer anymore.
- Removed the check RenderObject::willRenderContents() because when a page is in the b/f cache, paint() is not called, so the timer will not start.
Comment 8 Antti Koivisto 2010-03-31 05:19:26 PDT
Comment on attachment 52069 [details]

Looks pretty good, a few comments:

> -bool RenderThemeQt::getNumberOfPixelsForProgressPosition(double position, int& progressSize) const
> +bool RenderThemeQt::animationIntervalAndDurationForProgressBar(RenderProgress* renderProgress, double& interval, double& duration) const

The style is to name functions that return values in parameters get* -> getAnimationIntervalAndDurationForProgressBar. Alternatively use multiple functions with single return value.

It would be better to return all values as parameters. Now it is unclear what the separate bool return means. I'm not sure if it is really needed either, 0 duration could signal the same thing (==don't animate).

+    m_animationTimer.stop();

No need to add destructor for this, the timer will get deleted and stop automatically.

> +double RenderProgress::animationProgress()
> +{
> +    return m_animating ? (fmod((currentTime() - m_animationStartTime), m_animationDuration) / m_animationInterval) : 0;
> +}

Dividing by m_animationInterval is bit strange and seems to tie to the specific way the theme is implemented. It would be better to divide by m_animationDuration to get 0-1 progress range. The paint position can then be calculated in the theme by progress * option.rect.width().

> +void RenderProgress::updateAnimationState()
> +{
> +    m_animationTimer.stop();
> +    m_animating = theme()->animationIntervalAndDurationForProgressBar(this, m_animationInterval, m_animationDuration);
> +    if (m_animating)
> +        m_animationStartTime = currentTime();
> +}

Should this also start the timer if the state changed? Stopping the timer seems wrong if the state did not change.

>      double m_position;
> +    double m_animationStartTime;
> +    double m_animationInterval;

m_animationRepeatInterval perhaps?
Comment 9 Yael 2010-03-31 09:00:05 PDT
Created attachment 52177 [details]
Patch updated based on comment #8.
Comment 10 Antti Koivisto 2010-03-31 09:41:32 PDT
Comment on attachment 52177 [details]
Patch updated based on comment #8.

Nice, r=me

> +    m_animationTimer.stop();
> +    if (m_animating) {
> +        m_animationStartTime = currentTime();
> +        m_animationTimer.startOneShot(m_animationRepeatInterval);
> +    }

That could be


(it is ok to start active timer again)
Comment 11 Yael 2010-03-31 10:08:46 PDT
Landed in r56850.
Comment 12 Yael 2010-04-01 07:58:05 PDT
*** Bug 36224 has been marked as a duplicate of this bug. ***