Add animation to progress element
https://bugs.webkit.org/show_bug.cgi?id=36664

Reviewed by Antti Koivisto.

Add a timer to control the animation. The timer is started after painting
or a state change in the progress bar, to prevent animation from running
when the progress bar is not visible.

* html/HTMLProgressElement.cpp:
* platform/qt/RenderThemeQt.cpp:
* platform/qt/RenderThemeQt.h:
* rendering/RenderProgress.cpp:
* rendering/RenderProgress.h:
* rendering/RenderTheme.cpp:
* rendering/RenderTheme.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@56850 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 4cc3c34..8a68678 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,37 @@
+2010-03-31  Yael Aharon  <yael.aharon@nokia.com>
+
+        Reviewed by Antti Koivisto.
+
+        Add animation to progress element
+        https://bugs.webkit.org/show_bug.cgi?id=36664
+
+        Add a timer to control the animation. The timer is started after painting
+        or a state change in the progress bar, to prevent animation from running
+        when the progress bar is not visible.
+
+        * html/HTMLProgressElement.cpp:
+        (WebCore::HTMLProgressElement::createRenderer):
+        * manual-tests/dom: Added.
+        * manual-tests/dom/progressbar.html: Added.
+        * platform/qt/RenderThemeQt.cpp:
+        (WebCore::RenderThemeQt::animationRepeatIntervalForProgressBar):
+        (WebCore::RenderThemeQt::animationDurationForProgressBar):
+        (WebCore::RenderThemeQt::paintProgressBar):
+        * platform/qt/RenderThemeQt.h:
+        * rendering/RenderProgress.cpp:
+        (WebCore::RenderProgress::RenderProgress):
+        (WebCore::RenderProgress::layout):
+        (WebCore::RenderProgress::updateFromElement):
+        (WebCore::RenderProgress::animationProgress):
+        (WebCore::RenderProgress::animationTimerFired):
+        (WebCore::RenderProgress::paint):
+        (WebCore::RenderProgress::updateAnimationState):
+        * rendering/RenderProgress.h:
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::animationRepeatIntervalForProgressBar):
+        (WebCore::RenderTheme::animationDurationForProgressBar):
+        * rendering/RenderTheme.h:
+
 2010-03-31  Pavel Feldman  <pfeldman@chromium.org>
 
         Not reviewed. Rolling out r56829 since it broke chromium layout tests.
diff --git a/WebCore/html/HTMLProgressElement.cpp b/WebCore/html/HTMLProgressElement.cpp
index 132fcde..6fa8043 100644
--- a/WebCore/html/HTMLProgressElement.cpp
+++ b/WebCore/html/HTMLProgressElement.cpp
@@ -45,7 +45,7 @@
     return adoptRef(new HTMLProgressElement(tagName, document, form));
 }
 
-RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle* style)
+RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle*)
 {
     return new (arena) RenderProgress(this);
 }
diff --git a/WebCore/manual-tests/dom/progressbar.html b/WebCore/manual-tests/dom/progressbar.html
new file mode 100644
index 0000000..95e64f2
--- /dev/null
+++ b/WebCore/manual-tests/dom/progressbar.html
@@ -0,0 +1,8 @@
+<html><body>
+<h1>Indeterminate progress bar</h1>
+This is an example of <progress value=7 max=10></progress> a determinate progress bar.<br>
+This is an example of <progress></progress> an indeterminate progress bar.<br>
+This is an example of <progress dir=rtl value=7 max=10></progress> a right-to-left determinate progress bar.<br>
+This is an example of <progress dir=rtl></progress> a right-to-left indeterminate progress bar.<br>
+
+</body></html>
diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp
index 38c12ae..5ee372b 100644
--- a/WebCore/platform/qt/RenderThemeQt.cpp
+++ b/WebCore/platform/qt/RenderThemeQt.cpp
@@ -653,10 +653,26 @@
 }
 
 #if ENABLE(PROGRESS_TAG)
-bool RenderThemeQt::getNumberOfPixelsForProgressPosition(double position, int& progressSize) const
+double RenderThemeQt::animationRepeatIntervalForProgressBar(RenderProgress* renderProgress) const
 {
-    progressSize = 65536 * position;
-    return false;
+    if (renderProgress->position() >= 0)
+        return 0;
+
+    // FIXME: Use hard-coded value until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed.
+    // Use the value from windows style which is 10 fps.
+    return 0.1;
+}
+
+double RenderThemeQt::animationDurationForProgressBar(RenderProgress* renderProgress) const
+{
+    if (renderProgress->position() >= 0)
+        return 0;
+
+    QStyleOptionProgressBarV2 option;
+    option.rect.setSize(renderProgress->size());
+    // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed,
+    // we simulate one square animating across the progress bar.
+    return (option.rect.width() / qStyle()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option)) * animationRepeatIntervalForProgressBar(renderProgress);
 }
 
 void RenderThemeQt::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
@@ -686,7 +702,19 @@
     option.rect.moveTo(QPoint(0, 0));
     option.rect.setSize(r.size());
 
-    p.drawControl(QStyle::CE_ProgressBar, option);
+    if (option.progress < 0) {
+        // FIXME: Until http://bugreports.qt.nokia.com/browse/QTBUG-9171 is fixed,
+        // we simulate one square animating across the progress bar.
+        p.drawControl(QStyle::CE_ProgressBarGroove, option);
+        int chunkWidth = qStyle()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option);
+        QColor color = (option.palette.highlight() == option.palette.background()) ? option.palette.color(QPalette::Active, QPalette::Highlight) : option.palette.color(QPalette::Highlight);
+        if (renderProgress->style()->direction() == RTL)
+            p.painter->fillRect(option.rect.right() - chunkWidth  - renderProgress->animationProgress() * option.rect.width(), 0, chunkWidth, option.rect.height(), color);
+        else
+            p.painter->fillRect(renderProgress->animationProgress() * option.rect.width(), 0, chunkWidth, option.rect.height(), color);
+    } else
+        p.drawControl(QStyle::CE_ProgressBar, option);
+
     p.painter->translate(-topLeft);
 
     return false;
diff --git a/WebCore/platform/qt/RenderThemeQt.h b/WebCore/platform/qt/RenderThemeQt.h
index 121b078..d046914 100644
--- a/WebCore/platform/qt/RenderThemeQt.h
+++ b/WebCore/platform/qt/RenderThemeQt.h
@@ -34,6 +34,9 @@
 
 namespace WebCore {
 
+#if ENABLE(PROGRESS_TAG)
+class RenderProgress;
+#endif
 class RenderStyle;
 class HTMLMediaElement;
 class ScrollbarThemeQt;
@@ -128,10 +131,10 @@
     virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
 
 #if ENABLE(PROGRESS_TAG)
-    // 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 repeat interval of the animation for the progress bar.
+    virtual double animationRepeatIntervalForProgressBar(RenderProgress* renderProgress) const;
+    // Returns the duration of the animation for the progress bar.
+    virtual double animationDurationForProgressBar(RenderProgress* renderProgress) const;
 #endif
 
 #if ENABLE(VIDEO)
diff --git a/WebCore/rendering/RenderProgress.cpp b/WebCore/rendering/RenderProgress.cpp
index 6d92187..6ee066d 100644
--- a/WebCore/rendering/RenderProgress.cpp
+++ b/WebCore/rendering/RenderProgress.cpp
@@ -35,6 +35,11 @@
 RenderProgress::RenderProgress(HTMLProgressElement* element)
     : RenderBlock(element)
     , m_position(-1)
+    , m_animationStartTime(0)
+    , m_animationRepeatInterval(0)
+    , m_animationDuration(0)
+    , m_animating(false)
+    , m_animationTimer(this, &RenderProgress::animationTimerFired)
 {
 }
 
@@ -49,6 +54,8 @@
 
     m_overflow.clear();
 
+    updateAnimationState();
+
     repainter.repaintAfterLayout();
 
     setNeedsLayout(false);
@@ -61,8 +68,47 @@
         return;
     m_position = element->position();
 
+    updateAnimationState();
+
     repaint();
 }
 
+double RenderProgress::animationProgress()
+{
+    return m_animating ? (fmod((currentTime() - m_animationStartTime), m_animationDuration) / m_animationDuration) : 0;
+}
+
+void RenderProgress::animationTimerFired(Timer<RenderProgress>*)
+{
+    repaint();
+}
+
+void RenderProgress::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+    if (paintInfo.phase == PaintPhaseBlockBackground) {
+        if (!m_animationTimer.isActive() && m_animating)
+            m_animationTimer.startOneShot(m_animationRepeatInterval);
+    }
+
+    RenderBlock::paint(paintInfo, tx, ty);
+}
+
+void RenderProgress::updateAnimationState()
+{
+    m_animationDuration = theme()->animationDurationForProgressBar(this);
+    m_animationRepeatInterval = theme()->animationRepeatIntervalForProgressBar(this);
+
+    bool animating = m_animationDuration > 0;
+    if (animating == m_animating)
+        return;
+
+    m_animating = animating;
+    if (m_animating) {
+        m_animationStartTime = currentTime();
+        m_animationTimer.startOneShot(m_animationRepeatInterval);
+    } else
+        m_animationTimer.stop();
+}
+
 } // namespace WebCore
 #endif
diff --git a/WebCore/rendering/RenderProgress.h b/WebCore/rendering/RenderProgress.h
index a2e823c..767ed37 100644
--- a/WebCore/rendering/RenderProgress.h
+++ b/WebCore/rendering/RenderProgress.h
@@ -32,13 +32,24 @@
 public:
     RenderProgress(HTMLProgressElement*);
     double position() { return m_position; }
+    double animationProgress();
 
 private:
     virtual const char* renderName() const { return "RenderProgress"; }
     virtual bool isProgress() const { return true; }
     virtual void layout();
     virtual void updateFromElement();
+    virtual void paint(PaintInfo&, int tx, int ty);
+
+    void animationTimerFired(Timer<RenderProgress>*);
+    void updateAnimationState();
+
     double m_position;
+    double m_animationStartTime;
+    double m_animationRepeatInterval;
+    double m_animationDuration;
+    bool m_animating;
+    Timer<RenderProgress> m_animationTimer;
 };
 
 inline RenderProgress* toRenderProgress(RenderObject* object)
diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp
index 7c284a6..1d0411a 100644
--- a/WebCore/rendering/RenderTheme.cpp
+++ b/WebCore/rendering/RenderTheme.cpp
@@ -840,10 +840,14 @@
 }
 
 #if ENABLE(PROGRESS_TAG)
-bool RenderTheme::getNumberOfPixelsForProgressPosition(double , int& progressSize) const
+double RenderTheme::animationRepeatIntervalForProgressBar(RenderProgress*) const
 {
-    progressSize = 0;
-    return false;
+    return 0;
+}
+
+double RenderTheme::animationDurationForProgressBar(RenderProgress*) const
+{
+    return 0;
 }
 
 void RenderTheme::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const
diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h
index fbdf910..5f65d7f 100644
--- a/WebCore/rendering/RenderTheme.h
+++ b/WebCore/rendering/RenderTheme.h
@@ -39,6 +39,9 @@
 class Element;
 class PopupMenu;
 class RenderMenuList;
+#if ENABLE(PROGRESS_TAG)
+class RenderProgress;
+#endif
 class CSSStyleSheet;
 
 class RenderTheme : public RefCounted<RenderTheme> {
@@ -170,10 +173,10 @@
     virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return 0; };
 
 #if ENABLE(PROGRESS_TAG)
-    // 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 repeat interval of the animation for the progress bar.
+    virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const;
+    // Returns the duration of the animation for the progress bar.
+    virtual double animationDurationForProgressBar(RenderProgress*) const;
 #endif
 
 #if ENABLE(VIDEO)