From 3d57c253bfa22c17c5f38a70e162a6115a1809b6 Mon Sep 17 00:00:00 2001 From: Nicolas Roard Date: Tue, 2 Feb 2010 13:11:32 +0000 Subject: Implement the audio tag in webkit -- the corresponding java CL is https://android-git.corp.google.com/g/#change,41406 Cherry pick to Gingerbread, DO NOT MERGE! Bug:3101402 Change-Id: Idbfb0efcc777f9354fcf88df32105ca9e50a24cd --- WebCore/Android.derived.mk | 2 +- WebCore/css/mediaControlsAndroid.css | 134 +++++++++++++++++++++ WebCore/html/HTMLMediaElement.cpp | 6 + WebCore/platform/android/RenderThemeAndroid.cpp | 94 +++++++++++++++ WebCore/platform/android/RenderThemeAndroid.h | 14 ++- WebCore/platform/graphics/MediaPlayer.cpp | 3 + WebCore/platform/graphics/MediaPlayer.h | 8 ++ .../graphics/android/MediaPlayerPrivateAndroid.h | 64 +++++----- 8 files changed, 292 insertions(+), 33 deletions(-) create mode 100644 WebCore/css/mediaControlsAndroid.css (limited to 'WebCore') diff --git a/WebCore/Android.derived.mk b/WebCore/Android.derived.mk index c678e60..cb6f902 100644 --- a/WebCore/Android.derived.mk +++ b/WebCore/Android.derived.mk @@ -102,7 +102,7 @@ LOCAL_GENERATED_SOURCES += $(GEN) # user agent style sheets -style_sheets := $(LOCAL_PATH)/css/html.css $(LOCAL_PATH)/css/quirks.css $(LOCAL_PATH)/css/view-source.css $(LOCAL_PATH)/css/mediaControls.css +style_sheets := $(LOCAL_PATH)/css/html.css $(LOCAL_PATH)/css/quirks.css $(LOCAL_PATH)/css/view-source.css $(LOCAL_PATH)/css/mediaControls.css $(LOCAL_PATH)/css/mediaControlsAndroid.css ifeq ($(ENABLE_SVG), true) style_sheets := $(style_sheets) $(LOCAL_PATH)/css/svg.css endif diff --git a/WebCore/css/mediaControlsAndroid.css b/WebCore/css/mediaControlsAndroid.css new file mode 100644 index 0000000..82f4bd3 --- /dev/null +++ b/WebCore/css/mediaControlsAndroid.css @@ -0,0 +1,134 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* media controls */ + +audio { + width: 200px; + height: 32px; +} + +audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel { + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: center; + -webkit-user-select: none; + position: absolute; + bottom: 0; + width: 100%; + z-index: 0; + overflow: hidden; + height: 32px; + text-align: right; +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + bottom: -32px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + -webkit-appearance: media-mute-button; + display: -webkit-box; + width: 32px; + height: 32px; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + -webkit-appearance: media-play-button; + display: -webkit-box; + width: 32px; + height: 32px; +} + +audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container { + -webkit-appearance: media-controls-background; + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: center; + -webkit-box-pack: end; + -webkit-box-flex: 1; + -webkit-user-select: none; + height: 32px; +} + +audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display { + display: none; +} + +audio::-webkit-media-controls-time-remaining-display, video::-webkit-media-controls-time-remaining-display { + display: none; +} + +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; +} + +audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container { + display: none; +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + display: none; +} + +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; +} + +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; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + -webkit-appearance: media-fullscreen-button; + display: -webkit-box; + width: 32px; + height: 32px; +} + +audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button { + display: none; +} + +audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-controls-return-to-realtime-button { + display: none; +} + +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 +} diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index 279aac7..bee91ae 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -591,6 +591,12 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content updateVolume(); m_player->load(m_currentSrc, contentType); +#if PLATFORM(ANDROID) + if (isVideo()) + m_player->setMediaElementType(MediaPlayer::Video); + else + m_player->setMediaElementType(MediaPlayer::Audio); +#endif if (isVideo() && m_player->canLoadPoster()) { KURL posterUrl = static_cast(this)->poster(); diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp index 4c5cff5..b1d0431 100644 --- a/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/WebCore/platform/android/RenderThemeAndroid.cpp @@ -34,11 +34,16 @@ #include "HTMLSelectElement.h" #include "Node.h" #include "PlatformGraphicsContext.h" +#if ENABLE(VIDEO) +#include "RenderMediaControls.h" +#endif #include "RenderSkinAndroid.h" #include "RenderSkinButton.h" #include "RenderSkinCombo.h" +#include "RenderSkinMediaButton.h" #include "RenderSkinRadio.h" #include "SkCanvas.h" +#include "UserAgentStyleSheets.h" namespace WebCore { @@ -225,6 +230,95 @@ bool RenderThemeAndroid::paintButton(RenderObject* obj, const RenderObject::Pain return false; } +#if ENABLE(VIDEO) + +String RenderThemeAndroid::extraMediaControlsStyleSheet() +{ + return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet)); +} + +bool RenderThemeAndroid::shouldRenderMediaControlPart(ControlPart part, Element* e) +{ + HTMLMediaElement* mediaElement = static_cast(e); + switch (part) { + case MediaMuteButtonPart: + return false; + case MediaSeekBackButtonPart: + case MediaSeekForwardButtonPart: + return true; + case MediaRewindButtonPart: + return mediaElement->movieLoadType() != MediaPlayer::LiveStream; + case MediaReturnToRealtimeButtonPart: + return mediaElement->movieLoadType() == MediaPlayer::LiveStream; + case MediaFullscreenButtonPart: + return mediaElement->supportsFullscreen(); + case MediaToggleClosedCaptionsButtonPart: + return mediaElement->hasClosedCaptions(); + default: + return true; + } +} + +bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::MUTE); + return false; +} + +bool RenderThemeAndroid::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + if (MediaControlPlayButtonElement* btn = static_cast(o->node())) { + if (btn->displayType() == MediaPlayButton) + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY); + else + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PAUSE); + return false; + } + return true; +} + +bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::REWIND); + return false; +} + +bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FORWARD); + return false; +} + +bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::BACKGROUND_SLIDER); + return false; +} + +bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_TRACK); + return false; +} + +bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_THUMB); + return false; +} + +void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const +{ + static const int sliderThumbWidth = RenderSkinMediaButton::sliderThumbWidth(); + static const int sliderThumbHeight = RenderSkinMediaButton::sliderThumbHeight(); + if (o->style()->appearance() == MediaSliderThumbPart) { + o->style()->setWidth(Length(sliderThumbWidth, Fixed)); + o->style()->setHeight(Length(sliderThumbHeight, Fixed)); + } +} + +#endif + bool RenderThemeAndroid::paintRadio(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect) { RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false); diff --git a/WebCore/platform/android/RenderThemeAndroid.h b/WebCore/platform/android/RenderThemeAndroid.h index ae1213c..3d7ac77 100644 --- a/WebCore/platform/android/RenderThemeAndroid.h +++ b/WebCore/platform/android/RenderThemeAndroid.h @@ -77,6 +77,19 @@ protected: virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void setCheckboxSize(RenderStyle*) const; +#if ENABLE(VIDEO) + virtual String extraMediaControlsStyleSheet(); + virtual void adjustSliderThumbSize(RenderObject* o) const; + virtual bool shouldRenderMediaControlPart(ControlPart part, Element* e); + bool paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r); + bool paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r); + bool paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r); + bool paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r); + bool paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r); + bool paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r); + virtual bool paintMediaControlsBackground(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect); +#endif + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void setRadioSize(RenderStyle*) const; @@ -113,4 +126,3 @@ private: } // namespace WebCore #endif // RenderThemeAndroid_h - diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index 2b09885..b527981 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -201,6 +201,9 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client) , m_muted(false) , m_preservesPitch(true) , m_autobuffer(false) +#if PLATFORM(ANDROID) + , m_mediaElementType(Video) +#endif #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_playerProxy(0) #endif diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 40ed8ae..54bf9ec 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -139,6 +139,11 @@ public: IntSize naturalSize(); bool hasVideo() const; bool hasAudio() const; +#if PLATFORM(ANDROID) + enum MediaElementType { Video, Audio }; + void setMediaElementType(MediaElementType type) { m_mediaElementType = type; } + MediaElementType mediaElementType() { return m_mediaElementType; } +#endif void setFrameView(FrameView* frameView) { m_frameView = frameView; } FrameView* frameView() { return m_frameView; } @@ -250,6 +255,9 @@ private: bool m_muted; bool m_preservesPitch; bool m_autobuffer; +#if PLATFORM(ANDROID) + MediaElementType m_mediaElementType; +#endif #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private #endif diff --git a/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h b/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h index 19bfcd1..0f38034 100644 --- a/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h +++ b/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, The Android Open Source Project + * Copyright 2009,2010 The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,73 +31,75 @@ class SkBitmap; #include "MediaPlayerPrivate.h" +#include "TimeRanges.h" namespace WebCore { class MediaPlayerPrivate : public MediaPlayerPrivateInterface { public: - ~MediaPlayerPrivate(); + virtual ~MediaPlayerPrivate(); static void registerMediaEngine(MediaEngineRegistrar); - virtual void load(const String& url); - virtual void cancelLoad(); + virtual void load(const String& url) = 0; + virtual void cancelLoad() { } - virtual void play(); + virtual void play() = 0; virtual void pause(); - virtual IntSize naturalSize() const; + virtual IntSize naturalSize() const { return m_naturalSize; } - virtual bool hasAudio() const; - virtual bool hasVideo() const; + virtual bool hasAudio() const { return false; } + virtual bool hasVideo() const { return false; } virtual void setVisible(bool); - virtual float duration() const; + virtual float duration() const { return m_duration; } - virtual float currentTime() const; + virtual float currentTime() const { return m_currentTime; }; virtual void seek(float time); - virtual bool seeking() const; + virtual bool seeking() const { return false; } - virtual void setEndTime(float time); + virtual void setEndTime(float time) { } - virtual void setRate(float); - virtual bool paused() const; + virtual void setRate(float) { } + virtual bool paused() const { return m_paused; } - virtual void setVolume(float); + virtual void setVolume(float) { } - virtual MediaPlayer::NetworkState networkState() const; - virtual MediaPlayer::ReadyState readyState() const; + virtual MediaPlayer::NetworkState networkState() const { return m_networkState; } + virtual MediaPlayer::ReadyState readyState() const { return m_readyState; } - virtual float maxTimeSeekable() const; - virtual PassRefPtr buffered() const; + virtual float maxTimeSeekable() const { return 0; } + virtual PassRefPtr buffered() const { return TimeRanges::create(); } - virtual int dataRate() const; + virtual int dataRate() const { return 0; } virtual bool totalBytesKnown() const { return totalBytes() > 0; } - virtual unsigned totalBytes() const; - virtual unsigned bytesLoaded() const; + virtual unsigned totalBytes() const { return 0; } + virtual unsigned bytesLoaded() const { return 0; } - virtual void setSize(const IntSize&); + virtual void setSize(const IntSize&) { } - virtual bool canLoadPoster() const { return true; } - virtual void setPoster(const String&); + virtual bool canLoadPoster() const { return false; } + virtual void setPoster(const String&) { } virtual void prepareToPlay(); - virtual void paint(GraphicsContext*, const IntRect&); + virtual void paint(GraphicsContext*, const IntRect&) { } - void onPrepared(int duration, int width, int height); + virtual void onPrepared(int duration, int width, int height) { } void onEnded(); - void onPosterFetched(SkBitmap*); + virtual void onPosterFetched(SkBitmap*) { } + void onBuffering(int percent); void onTimeupdate(int position); -private: +protected: // Android-specific methods and fields. static MediaPlayerPrivateInterface* create(MediaPlayer* player); - static void getSupportedTypes(HashSet&); + static void getSupportedTypes(HashSet&) { } static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); MediaPlayerPrivate(MediaPlayer *); - void createJavaPlayerIfNeeded(); + virtual void createJavaPlayerIfNeeded() { } MediaPlayer* m_player; String m_url; -- cgit v1.1