OSDN Git Service

Improving HTML5 video controls
authorNicolas Roard <nicolasroard@google.com>
Mon, 14 Mar 2011 20:23:18 +0000 (13:23 -0700)
committerNicolas Roard <nicolasroard@google.com>
Tue, 15 Mar 2011 02:07:36 +0000 (19:07 -0700)
- correct support for the fullscreen button
- change the controls to be 48px high
- auto-hide the controls, touching the video makes them appear again

bug:2126902
Change-Id: Idd2b720034de3d5d432c9ea62d9045934c46f6c1

WebCore/css/mediaControlsAndroid.css
WebCore/platform/android/RenderThemeAndroid.cpp
WebCore/platform/android/RenderThemeAndroid.h
WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h
WebCore/rendering/RenderMedia.cpp
WebCore/rendering/RenderMedia.h
WebKit/android/RenderSkinMediaButton.cpp
WebKit/android/RenderSkinMediaButton.h
WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp

index f33c7d5..77f8b08 100644 (file)
@@ -27,7 +27,7 @@
 
 audio {
     width: 200px;
-    height: 32px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel {
@@ -40,26 +40,26 @@ audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel {
     width: 100%;
     z-index: 0;
     overflow: hidden;
-    height: 32px;
+    height: 48px;
     text-align: right;
 }
 
 video:-webkit-full-page-media::-webkit-media-controls-panel {
-    bottom: -32px;
+    bottom: -48px;
 }
 
 audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button {
     -webkit-appearance: media-mute-button;
     display: -webkit-box;
-    width: 32px;
-    height: 32px;
+    width: 48px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button {
     -webkit-appearance: media-play-button;
     display: -webkit-box;
-    width: 32px;
-    height: 32px;
+    width: 48px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container {
@@ -70,7 +70,7 @@ audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-
     -webkit-box-pack: end;
     -webkit-box-flex: 1;
     -webkit-user-select: none;
-    height: 32px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display {
@@ -85,8 +85,8 @@ audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline {
     -webkit-appearance: media-slider;
     display: -webkit-box;
     -webkit-box-flex: 1;
-    height: 32px;
-    padding: 0px 2px;
+    height: 48px;
+    padding: 0px 0px;
 }
 
 audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container {
@@ -100,22 +100,22 @@ audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volum
 audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button {
     -webkit-appearance: media-seek-back-button;
     display: -webkit-box;
-    width: 32px;
-    height: 32px;
+    width: 48px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button {
     -webkit-appearance: media-seek-forward-button;
     display: -webkit-box;
-    width: 32px;
-    height: 32px;
+    width: 48px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button {
-    -webkit-appearance: media-play-button;
+    -webkit-appearance: media-fullscreen-button;
     display: -webkit-box;
-    width: 32px;
-    height: 32px;
+    width: 48px;
+    height: 48px;
 }
 
 audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button {
@@ -129,6 +129,6 @@ audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-co
 audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-media-controls-toggle-closed-captions-button {
     -webkit-appearance: media-toggle-closed-captions-button;
     display: -webkit-box;
-    width: 32px;
-    height: 32px
+    width: 48px;
+    height: 48px
 }
index 5253219..5a0bfb8 100644 (file)
@@ -262,12 +262,12 @@ bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element*
       }
 }
 
-bool paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
+bool RenderThemeAndroid::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
 {
       bool translucent = false;
       if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag))
           translucent = true;
-      RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent);
+      RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FULLSCREEN, translucent);
       return false;
 }
 
index 74820f2..8314a9c 100644 (file)
@@ -81,13 +81,16 @@ protected:
     virtual String extraMediaControlsStyleSheet();
     virtual void adjustSliderThumbSize(RenderObject* o) const;
     virtual bool shouldRenderMediaControlPart(ControlPart part, Element* e);
-    bool paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
-    bool paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
-    bool paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
-    bool paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
-    bool paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
-    bool paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
+    virtual bool paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r);
     virtual bool paintMediaControlsBackground(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect);
+    virtual double mediaControlsFadeInDuration() { return 0.5; }
+    virtual double mediaControlsFadeOutDuration() { return 0.5; }
 #endif
 
     virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&);
index 66b35dd..6948799 100644 (file)
@@ -50,8 +50,9 @@ public:
 
     virtual IntSize naturalSize() const { return m_naturalSize; }
 
-    virtual bool hasAudio() const { return false; }
-    virtual bool hasVideo() const { return false; }
+    virtual bool supportsFullscreen() const = 0;
+    virtual bool hasAudio() const = 0;
+    virtual bool hasVideo() const = 0;
 
     virtual void setVisible(bool);
 
index 49a536c..f19ca96 100644 (file)
 #include <wtf/CurrentTime.h>
 #include <wtf/MathExtras.h>
 
+#if PLATFORM(ANDROID)
+#define TOUCH_DELAY 4
+#endif
+
 using namespace std;
 
 namespace WebCore {
@@ -57,6 +61,9 @@ RenderMedia::RenderMedia(HTMLMediaElement* video)
     , m_opacityAnimationDuration(0)
     , m_opacityAnimationFrom(0)
     , m_opacityAnimationTo(1.0f)
+#if PLATFORM(ANDROID)
+    , m_lastTouch(0)
+#endif
 {
     setImageResource(RenderImageResource::create());
 }
@@ -70,6 +77,9 @@ RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
     , m_opacityAnimationDuration(0)
     , m_opacityAnimationFrom(0)
     , m_opacityAnimationTo(1.0f)
+#if PLATFORM(ANDROID)
+    , m_lastTouch(0)
+#endif
 {
     setImageResource(RenderImageResource::create());
     setIntrinsicSize(intrinsicSize);
@@ -456,7 +466,14 @@ void RenderMedia::updateControlVisibility()
     // Don't fade if the media element is not visible
     if (style()->visibility() != VISIBLE)
         return;
-    
+
+#if PLATFORM(ANDROID)
+    if (WTF::currentTime() - m_lastTouch > TOUCH_DELAY)
+        m_mouseOver = false;
+    else
+        m_mouseOver = true;
+#endif
+
     bool shouldHideController = !m_mouseOver && !media->canPlay();
 
     // Do fading manually, css animations don't work with shadow trees
@@ -535,6 +552,11 @@ void RenderMedia::updateVolumeSliderContainer(bool visible)
 
 void RenderMedia::forwardEvent(Event* event)
 {
+#if PLATFORM(ANDROID)
+    if (event->isMouseEvent())
+        m_lastTouch = WTF::currentTime();
+#endif
+
     if (event->isMouseEvent() && m_controlsShadowRoot) {
         MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
         IntPoint point(mouseEvent->absoluteLocation());
index aa725ff..65fdc7d 100644 (file)
@@ -151,6 +151,9 @@ private:
     double m_opacityAnimationDuration;
     float m_opacityAnimationFrom;
     float m_opacityAnimationTo;
+#if PLATFORM(ANDROID)
+    double m_lastTouch;
+#endif
 };
 
 inline RenderMedia* toRenderMedia(RenderObject* object)
index f9da7cf..c3ab80f 100644 (file)
@@ -51,6 +51,7 @@ static const PatchData gFiles[] =
         { "ic_media_pause.png", 0, 0 }, // MUTE
         { "ic_media_rew.png", 0, 0 }, // REWIND
         { "ic_media_ff.png", 0, 0 }, // FORWARD
+        { "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN
         { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
         { "scrubber_track_holo_dark.9.png", 0, 0 },  // SLIDER_TRACK
         { "scrubber_control_holo.png", 0, 0 }      // SLIDER_THUMB
@@ -113,6 +114,7 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
     case MUTE:
     case REWIND:
     case FORWARD:
+    case FULLSCREEN:
     {
          imageIndex = buttonType + 1;
          paint.setColor(backgroundColor);
index 124db32..bde31eb 100644 (file)
@@ -48,7 +48,7 @@ public:
     /**
      * Button types
      */
-    enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB };
+    enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, FULLSCREEN, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB };
     /**
      * Slider dimensions
      */
index 8f84c2f..4cc9cf4 100644 (file)
@@ -103,6 +103,7 @@ void MediaPlayerPrivate::pause()
         return;
 
     m_paused = true;
+    m_player->playbackStateChanged();
     env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_pause);
     checkException(env);
 }
@@ -162,6 +163,7 @@ void MediaPlayerPrivate::onEnded()
     m_currentTime = duration();
     m_player->timeChanged();
     m_paused = true;
+    m_player->playbackStateChanged();
     m_hasVideo = false;
     m_networkState = MediaPlayer::Idle;
 }
@@ -169,6 +171,7 @@ void MediaPlayerPrivate::onEnded()
 void MediaPlayerPrivate::onPaused()
 {
     m_paused = true;
+    m_player->playbackStateChanged();
     m_hasVideo = false;
     m_networkState = MediaPlayer::Idle;
     m_player->playbackStateChanged();
@@ -207,6 +210,7 @@ public:
             return;
 
         m_paused = false;
+        m_player->playbackStateChanged();
 
         if (m_currentTime == duration())
             m_currentTime = 0;
@@ -284,9 +288,9 @@ public:
         m_player->sizeChanged();
     }
 
-    bool hasAudio() { return false; } // do not display the audio UI
-    bool hasVideo() { return m_hasVideo; }
-    bool suppportsFullscreen() { return true; }
+    virtual bool hasAudio() const { return false; } // do not display the audio UI
+    virtual bool hasVideo() const { return m_hasVideo; }
+    virtual bool supportsFullscreen() const { return true; }
 
     MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
     {
@@ -394,13 +398,14 @@ public:
             return;
 
         m_paused = false;
+        m_player->playbackStateChanged();
         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play);
         checkException(env);
     }
 
-    bool hasAudio() { return true; }
-    bool hasVideo() { return false; }
-    bool suppportsFullscreen() { return false; }
+    virtual bool hasAudio() const { return true; }
+    virtual bool hasVideo() const { return false; }
+    virtual bool supportsFullscreen() const { return false; }
 
     float maxTimeSeekable() const
     {