summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Roard <nicolas@android.com>2010-02-02 13:11:32 +0000
committerNicolas Roard <nicolas@android.com>2010-05-07 12:03:08 -0700
commit7f493d591dfd3492d5916ca301a4dbcd61554a06 (patch)
tree864427fa2b9161070fd7a9df626ad83ffadeec2b
parent8e37eff9e07e986e0314f08ed2e079fb8356e831 (diff)
downloadexternal_webkit-7f493d591dfd3492d5916ca301a4dbcd61554a06.zip
external_webkit-7f493d591dfd3492d5916ca301a4dbcd61554a06.tar.gz
external_webkit-7f493d591dfd3492d5916ca301a4dbcd61554a06.tar.bz2
Implement the audio tag in webkit -- the corresponding java CL is https://android-git.corp.google.com/g/#change,41406
Change-Id: Ief37a7d9879308f0749fcd569e82fddc3f989a8a
-rw-r--r--CleanSpec.mk1
-rw-r--r--WebCore/Android.derived.mk2
-rw-r--r--WebCore/css/mediaControlsAndroid.css134
-rw-r--r--WebCore/html/HTMLMediaElement.cpp6
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.cpp94
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.h14
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp3
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h8
-rw-r--r--WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h68
-rw-r--r--WebKit/Android.mk1
-rw-r--r--WebKit/android/RenderSkinAndroid.cpp2
-rw-r--r--WebKit/android/RenderSkinMediaButton.cpp171
-rw-r--r--WebKit/android/RenderSkinMediaButton.h61
-rw-r--r--WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp543
-rw-r--r--WebKit/android/jni/WebCoreJniOnLoad.cpp6
15 files changed, 830 insertions, 284 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 02b4dea..ebb3f75 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -52,6 +52,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_int
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/WebCore/Android.derived.mk b/WebCore/Android.derived.mk
index c4ae2f1..398c63f 100644
--- a/WebCore/Android.derived.mk
+++ b/WebCore/Android.derived.mk
@@ -111,7 +111,7 @@ $(GEN): $(LOCAL_BISON)
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 12b93ef..e5594ae 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<HTMLVideoElement*>(this)->poster();
diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp
index 7085bf4..ab93167 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<HTMLMediaElement*>(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<MediaControlPlayButtonElement*>(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 8a9a264..9a7f7b3 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -204,6 +204,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 1ca4576..f067cc9 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -143,6 +143,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; }
@@ -254,6 +259,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..b97691f 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,77 @@
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<TimeRanges> buffered() const;
+ virtual float maxTimeSeekable() const { return 0; }
+ virtual PassRefPtr<TimeRanges> 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<String>&);
- static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static void getSupportedTypes(HashSet<String>&) { }
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs) {
+ return MediaPlayer::IsNotSupported;
+ }
MediaPlayerPrivate(MediaPlayer *);
- void createJavaPlayerIfNeeded();
+ virtual void createJavaPlayerIfNeeded() { }
MediaPlayer* m_player;
String m_url;
diff --git a/WebKit/Android.mk b/WebKit/Android.mk
index 2c12ed3..47f37ca 100644
--- a/WebKit/Android.mk
+++ b/WebKit/Android.mk
@@ -31,6 +31,7 @@ LOCAL_SRC_FILES := \
android/RenderSkinAndroid.cpp \
android/RenderSkinButton.cpp \
android/RenderSkinCombo.cpp \
+ android/RenderSkinMediaButton.cpp \
android/RenderSkinRadio.cpp \
android/TimeCounter.cpp \
\
diff --git a/WebKit/android/RenderSkinAndroid.cpp b/WebKit/android/RenderSkinAndroid.cpp
index 31c327a..00f2b96 100644
--- a/WebKit/android/RenderSkinAndroid.cpp
+++ b/WebKit/android/RenderSkinAndroid.cpp
@@ -29,6 +29,7 @@
#include "RenderSkinAndroid.h"
#include "RenderSkinButton.h"
#include "RenderSkinCombo.h"
+#include "RenderSkinMediaButton.h"
#include "RenderSkinRadio.h"
#include "SkImageDecoder.h"
@@ -46,6 +47,7 @@ void RenderSkinAndroid::Init(android::AssetManager* am, String drawableDirectory
{
RenderSkinButton::Init(am, drawableDirectory);
RenderSkinCombo::Init(am, drawableDirectory);
+ RenderSkinMediaButton::Init(am, drawableDirectory);
RenderSkinRadio::Init(am, drawableDirectory);
}
diff --git a/WebKit/android/RenderSkinMediaButton.cpp b/WebKit/android/RenderSkinMediaButton.cpp
new file mode 100644
index 0000000..149be4e
--- /dev/null
+++ b/WebKit/android/RenderSkinMediaButton.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "CString.h"
+#include "android_graphics.h"
+#include "Document.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "RenderSkinMediaButton.h"
+#include "SkCanvas.h"
+#include "SkNinePatch.h"
+#include "SkRect.h"
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+struct PatchData {
+ const char* name;
+ int8_t outset, margin;
+};
+
+static const PatchData gFiles[] =
+ {
+ { "btn_media_player.9.png", 0, 0 }, // DEFAULT BGD BUTTON
+ { "ic_media_pause.png", 0, 0}, // PAUSE
+ { "ic_media_play.png", 0, 0 }, // PLAY
+ { "ic_media_pause.png", 0, 0 }, // MUTE
+ { "ic_media_rew.png", 0, 0 }, // REWIND
+ { "ic_media_ff.png", 0, 0 }, // FORWARD
+ { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
+ { "btn_media_player_pressed.9.png", 0, 0 }, // SLIDER_TRACK
+ { "btn_media_player.9.png", 0, 0 } // SLIDER_THUMB
+ };
+
+static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
+static bool gDecoded;
+static bool gHighRes;
+
+namespace WebCore {
+
+void RenderSkinMediaButton::Init(android::AssetManager* am, String drawableDirectory)
+{
+ static bool gInited;
+ if (gInited)
+ return;
+
+ gInited = true;
+ gDecoded = true;
+ gHighRes = drawableDirectory[drawableDirectory.length() - 5] == 'h';
+ for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) {
+ String path = drawableDirectory + gFiles[i].name;
+ if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) {
+ gDecoded = false;
+ LOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
+ break;
+ }
+ }
+}
+
+void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonType)
+{
+ // If we failed to decode, do nothing. This way the browser still works,
+ // and webkit will still draw the label and layout space for us.
+ if (!gDecoded) {
+ return;
+ }
+
+ bool drawsNinePatch = true;
+ bool drawsImage = true;
+ bool drawsBackgroundColor = false;
+
+ int ninePatchIndex = 0;
+ int imageIndex = 0;
+
+ SkRect bounds(r);
+ SkScalar imageMargin = 8;
+ SkPaint paint;
+ SkColor backgroundColor = SkColorSetARGB(255, 200, 200, 200);
+ SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100);
+
+ switch (buttonType) {
+ case PAUSE:
+ case PLAY:
+ case MUTE:
+ case REWIND:
+ case FORWARD:
+ {
+ imageIndex = buttonType + 1;
+ drawsBackgroundColor = true;
+ paint.setColor(backgroundColor);
+ break;
+ }
+ case BACKGROUND_SLIDER:
+ {
+ drawsImage = false;
+ drawsNinePatch = false;
+ drawsBackgroundColor = true;
+ paint.setColor(backgroundColor);
+ break;
+ }
+ case SLIDER_TRACK:
+ {
+ drawsImage = false;
+ drawsNinePatch = false;
+ drawsBackgroundColor = true;
+ paint.setColor(trackBackgroundColor);
+ bounds.fTop += 8;
+ bounds.fBottom -= 8;
+ break;
+ }
+ case SLIDER_THUMB:
+ {
+ drawsImage = false;
+ ninePatchIndex = buttonType + 1;
+ break;
+ }
+ default:
+ drawsImage = false;
+ drawsNinePatch = false;
+ }
+
+ if (drawsBackgroundColor) {
+ canvas->drawRect(r, paint);
+ }
+
+ if (drawsNinePatch) {
+ const PatchData& pd = gFiles[ninePatchIndex];
+ int marginValue = pd.margin + pd.outset;
+
+ SkIRect margin;
+ margin.set(marginValue, marginValue, marginValue, marginValue);
+ SkNinePatch::DrawNine(canvas, bounds, gButton[0], margin);
+ }
+
+ if (drawsImage) {
+ SkScalar SIZE = gButton[imageIndex].width();
+ SkScalar width = r.width();
+ SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE);
+ int saveScaleCount = canvas->save();
+ canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin);
+ canvas->scale(scale, scale);
+ canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint);
+ canvas->restoreToCount(saveScaleCount);
+ }
+}
+
+} //WebCore
diff --git a/WebKit/android/RenderSkinMediaButton.h b/WebKit/android/RenderSkinMediaButton.h
new file mode 100644
index 0000000..b4e99f4
--- /dev/null
+++ b/WebKit/android/RenderSkinMediaButton.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef RenderSkinMediaButton_h
+#define RenderSkinMediaButton_h
+
+#include "RenderSkinAndroid.h"
+
+class SkCanvas;
+
+namespace WebCore {
+class IntRect;
+class RenderSkinMediaButton
+{
+public:
+ /**
+ * Initialize the class before use. Uses the AssetManager to initialize any
+ * bitmaps the class may use.
+ */
+ static void Init(android::AssetManager*, String drawableDirectory);
+ /**
+ * Draw the skin to the canvas, using the rectangle for its bounds and the
+ * State to determine which skin to use, i.e. focused or not focused.
+ */
+ static void Draw(SkCanvas* , const IntRect& , int buttonType);
+ /**
+ * Button types
+ */
+ enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB };
+ /**
+ * Slider dimensions
+ */
+ static int sliderThumbWidth() { return 10; }
+ static int sliderThumbHeight() { return 30; }
+
+};
+
+} // WebCore
+#endif // RenderSkinMediaButton_h
diff --git a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
index bfb5305..7c0bb24 100644
--- a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
@@ -30,7 +30,6 @@
#include "GraphicsContext.h"
#include "SkiaUtils.h"
-#include "TimeRanges.h"
#include "WebCoreJni.h"
#include "WebViewCore.h"
@@ -44,16 +43,22 @@ using namespace android;
namespace WebCore {
static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy";
+static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio";
struct MediaPlayerPrivate::JavaGlue
{
jobject m_javaProxy;
- jmethodID m_getInstance;
jmethodID m_play;
jmethodID m_teardown;
- jmethodID m_loadPoster;
jmethodID m_seek;
jmethodID m_pause;
+ // Audio
+ jmethodID m_newInstance;
+ jmethodID m_setDataSource;
+ jmethodID m_getMaxTimeSeekable;
+ // Video
+ jmethodID m_getInstance;
+ jmethodID m_loadPoster;
};
MediaPlayerPrivate::~MediaPlayerPrivate()
@@ -65,7 +70,6 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
env->DeleteGlobalRef(m_glue->m_javaProxy);
}
}
-
delete m_glue;
}
@@ -74,29 +78,6 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
registrar(create, getSupportedTypes, supportsType);
}
-void MediaPlayerPrivate::load(const String& url)
-{
- // Just save the URl.
- m_url = url;
-}
-
-void MediaPlayerPrivate::cancelLoad()
-{
-}
-
-void MediaPlayerPrivate::play()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env || !m_glue->m_javaProxy || !m_url.length())
- return;
-
- m_paused = false;
- jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length());
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl);
- env->DeleteLocalRef(jUrl);
- checkException(env);
-}
-
void MediaPlayerPrivate::pause()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -108,22 +89,6 @@ void MediaPlayerPrivate::pause()
checkException(env);
}
-IntSize MediaPlayerPrivate::naturalSize() const
-{
- return m_naturalSize;
-}
-
-bool MediaPlayerPrivate::hasAudio() const
-{
- // TODO
- return false;
-}
-
-bool MediaPlayerPrivate::hasVideo() const
-{
- return m_hasVideo;
-}
-
void MediaPlayerPrivate::setVisible(bool visible)
{
m_isVisible = visible;
@@ -131,99 +96,19 @@ void MediaPlayerPrivate::setVisible(bool visible)
createJavaPlayerIfNeeded();
}
-float MediaPlayerPrivate::duration() const
-{
- return m_duration;
-}
-
-float MediaPlayerPrivate::currentTime() const
-{
- return m_currentTime;
-}
-
void MediaPlayerPrivate::seek(float time)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env || !m_glue->m_javaProxy || !m_url.length())
+ if (!env || !m_url.length())
return;
- m_currentTime = time;
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
+ if (m_glue->m_javaProxy) {
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
+ m_currentTime = time;
+ }
checkException(env);
}
-bool MediaPlayerPrivate::seeking() const
-{
- return false;
-}
-
-void MediaPlayerPrivate::setEndTime(float)
-{
-}
-
-void MediaPlayerPrivate::setRate(float)
-{
-}
-
-bool MediaPlayerPrivate::paused() const
-{
- return m_paused;
-}
-
-void MediaPlayerPrivate::setVolume(float)
-{
-}
-
-MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
-{
- return m_networkState;
-}
-
-MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
-{
- return m_readyState;
-}
-
-float MediaPlayerPrivate::maxTimeSeekable() const
-{
- return 0;
-}
-
-PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
-{
- return TimeRanges::create();
-}
-
-int MediaPlayerPrivate::dataRate() const
-{
- return 0;
-}
-
-unsigned MediaPlayerPrivate::totalBytes() const
-{
- return 0;
-}
-
-unsigned MediaPlayerPrivate::bytesLoaded() const
-{
- return 0;
-}
-
-void MediaPlayerPrivate::setSize(const IntSize&)
-{
-}
-
-void MediaPlayerPrivate::setPoster(const String& url)
-{
- m_posterUrl = url;
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
- return;
- // Send the poster
- jstring jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
- env->DeleteLocalRef(jUrl);
-}
void MediaPlayerPrivate::prepareToPlay() {
// We are about to start playing. Since our Java VideoView cannot
@@ -237,45 +122,6 @@ void MediaPlayerPrivate::prepareToPlay() {
m_player->readyStateChanged();
}
-void MediaPlayerPrivate::paint(GraphicsContext* ctxt, const IntRect& r)
-{
- if (ctxt->paintingDisabled())
- return;
-
- if (!m_isVisible)
- return;
-
- if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
- return;
-
- SkCanvas* canvas = ctxt->platformContext()->mCanvas;
- // We paint with the following rules in mind:
- // - only downscale the poster, never upscale
- // - maintain the natural aspect ratio of the poster
- // - the poster should be centered in the target rect
- float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
- int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
- int posterHeight = posterWidth / originalRatio;
- int posterX = ((r.width() - posterWidth) / 2) + r.x();
- int posterY = ((r.height() - posterHeight) / 2) + r.y();
- IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
- canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
-}
-
-MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
-{
- return new MediaPlayerPrivate(player);
-}
-
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
-{
-}
-
-MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
-{
- return MediaPlayer::IsNotSupported;
-}
-
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player),
m_glue(0),
@@ -290,72 +136,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
m_naturalSizeUnknown(true),
m_isVisible(false)
{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env)
- return;
-
- jclass clazz = env->FindClass(g_ProxyJavaClass);
- if (!clazz)
- return;
-
- m_glue = new JavaGlue;
- m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
- m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;)V");
- m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
- m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
- m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
- m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
- m_glue->m_javaProxy = NULL;
- env->DeleteLocalRef(clazz);
- // An exception is raised if any of the above fails.
- checkException(env);
-}
-
-void MediaPlayerPrivate::createJavaPlayerIfNeeded()
-{
- // Check if we have been already created.
- if (m_glue->m_javaProxy)
- return;
-
- FrameView* frameView = m_player->frameView();
- if (!frameView)
- return;
-
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env)
- return;
-
- jclass clazz = env->FindClass(g_ProxyJavaClass);
- if (!clazz)
- return;
-
- WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView);
- ASSERT(webViewCore);
-
- // Get the HTML5VideoViewProxy instance
- jobject obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this);
- m_glue->m_javaProxy = env->NewGlobalRef(obj);
- // Send the poster
- jstring jUrl = 0;
- if (m_posterUrl.length())
- jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
- // Sending a NULL jUrl allows the Java side to try to load the default poster.
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
- if (jUrl)
- env->DeleteLocalRef(jUrl);
- // Clean up.
- env->DeleteLocalRef(obj);
- env->DeleteLocalRef(clazz);
- checkException(env);
-}
-
-void MediaPlayerPrivate::onPrepared(int duration, int width, int height) {
- m_duration = duration / 1000.0f;
- m_naturalSize = IntSize(width, height);
- m_naturalSizeUnknown = false;
- m_hasVideo = true;
- m_player->durationChanged();
- m_player->sizeChanged();
}
void MediaPlayerPrivate::onEnded() {
@@ -368,25 +148,268 @@ void MediaPlayerPrivate::onEnded() {
m_readyState = MediaPlayer::HaveNothing;
}
-void MediaPlayerPrivate::onPosterFetched(SkBitmap* poster) {
- m_poster = poster;
- if (m_naturalSizeUnknown) {
- // We had to fake the size at startup, or else our paint
- // method would not be called. If we haven't yet received
- // the onPrepared event, update the intrinsic size to the size
- // of the poster. That will be overriden when onPrepare comes.
- // In case of an error, we should report the poster size, rather
- // than our initial fake value.
- m_naturalSize = IntSize(poster->width(), poster->height());
- m_player->sizeChanged();
- }
-}
-
void MediaPlayerPrivate::onTimeupdate(int position) {
m_currentTime = position / 1000.0f;
m_player->timeChanged();
}
+class MediaPlayerVideoPrivate : public MediaPlayerPrivate {
+public:
+ void load(const String& url) { m_url = url; }
+ void play() {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length() || !m_glue->m_javaProxy)
+ return;
+
+ m_paused = false;
+ jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length());
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl);
+ env->DeleteLocalRef(jUrl);
+
+ checkException(env);
+ }
+ bool canLoadPoster() const { return true; }
+ void setPoster(const String& url) {
+ m_posterUrl = url;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
+ return;
+ // Send the poster
+ jstring jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
+ env->DeleteLocalRef(jUrl);
+ }
+ void paint(GraphicsContext* ctxt, const IntRect& r) {
+ if (ctxt->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
+ return;
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ // We paint with the following rules in mind:
+ // - only downscale the poster, never upscale
+ // - maintain the natural aspect ratio of the poster
+ // - the poster should be centered in the target rect
+ float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
+ int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
+ int posterHeight = posterWidth / originalRatio;
+ int posterX = ((r.width() - posterWidth) / 2) + r.x();
+ int posterY = ((r.height() - posterHeight) / 2) + r.y();
+ IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
+ canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
+ }
+
+ void onPosterFetched(SkBitmap* poster) {
+ m_poster = poster;
+ if (m_naturalSizeUnknown) {
+ // We had to fake the size at startup, or else our paint
+ // method would not be called. If we haven't yet received
+ // the onPrepared event, update the intrinsic size to the size
+ // of the poster. That will be overriden when onPrepare comes.
+ // In case of an error, we should report the poster size, rather
+ // than our initial fake value.
+ m_naturalSize = IntSize(poster->width(), poster->height());
+ m_player->sizeChanged();
+ }
+ }
+
+ void onPrepared(int duration, int width, int height) {
+ m_duration = duration / 1000.0f;
+ m_naturalSize = IntSize(width, height);
+ m_naturalSizeUnknown = false;
+ m_hasVideo = true;
+ m_player->durationChanged();
+ m_player->sizeChanged();
+ }
+
+ bool hasAudio() { return false; } // do not display the audio UI
+ bool hasVideo() { return m_hasVideo; }
+
+ MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClass);
+
+ if (!clazz)
+ return;
+
+ m_glue = new JavaGlue;
+ m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
+ m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
+ m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;)V");
+
+ m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
+ m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
+ m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
+ m_glue->m_javaProxy = NULL;
+ env->DeleteLocalRef(clazz);
+ // An exception is raised if any of the above fails.
+ checkException(env);
+ }
+
+ void createJavaPlayerIfNeeded() {
+ // Check if we have been already created.
+ if (m_glue->m_javaProxy)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClass);
+
+ if (!clazz)
+ return;
+
+ jobject obj = NULL;
+
+ FrameView* frameView = m_player->frameView();
+ if (!frameView)
+ return;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView);
+ ASSERT(webViewCore);
+
+ // Get the HTML5VideoViewProxy instance
+ obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this);
+ m_glue->m_javaProxy = env->NewGlobalRef(obj);
+ // Send the poster
+ jstring jUrl = 0;
+ if (m_posterUrl.length())
+ jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
+ // Sending a NULL jUrl allows the Java side to try to load the default poster.
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
+ if (jUrl)
+ env->DeleteLocalRef(jUrl);
+
+ // Clean up.
+ if (obj)
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(clazz);
+ checkException(env);
+ }
+};
+
+class MediaPlayerAudioPrivate : public MediaPlayerPrivate {
+public:
+ void load(const String& url) {
+ m_url = url;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ createJavaPlayerIfNeeded();
+
+ if (!m_glue->m_javaProxy)
+ return;
+
+ jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length());
+ // start loading the data asynchronously
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl);
+ env->DeleteLocalRef(jUrl);
+ checkException(env);
+ }
+
+ void play() {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ createJavaPlayerIfNeeded();
+
+ if (!m_glue->m_javaProxy)
+ return;
+
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play);
+ checkException(env);
+ }
+
+ bool hasAudio() { return true; }
+
+ float maxTimeSeekable() const {
+ if (m_glue->m_javaProxy) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (env) {
+ float maxTime = env->CallFloatMethod(m_glue->m_javaProxy,
+ m_glue->m_getMaxTimeSeekable);
+ checkException(env);
+ return maxTime;
+ }
+ }
+ return 0;
+ }
+
+ MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
+
+ if (!clazz)
+ return;
+
+ m_glue = new JavaGlue;
+ m_glue->m_newInstance = env->GetMethodID(clazz, "<init>", "(I)V");
+ m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V");
+ m_glue->m_play = env->GetMethodID(clazz, "play", "()V");
+ m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F");
+ m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
+ m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
+ m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
+ m_glue->m_javaProxy = NULL;
+ env->DeleteLocalRef(clazz);
+ // An exception is raised if any of the above fails.
+ checkException(env);
+ }
+
+ void createJavaPlayerIfNeeded() {
+ // Check if we have been already created.
+ if (m_glue->m_javaProxy)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
+
+ if (!clazz)
+ return;
+
+ jobject obj = NULL;
+
+ // Get the HTML5Audio instance
+ obj = env->NewObject(clazz, m_glue->m_newInstance, this);
+ m_glue->m_javaProxy = env->NewGlobalRef(obj);
+
+ // Clean up.
+ if (obj)
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(clazz);
+ checkException(env);
+ }
+
+ void onPrepared(int duration, int width, int height) {
+ m_duration = duration / 1000.0f;
+ m_player->durationChanged();
+ m_player->sizeChanged();
+ m_player->prepareToPlay();
+ }
+};
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ if (player->mediaElementType() == MediaPlayer::Video)
+ return new MediaPlayerVideoPrivate(player);
+ return new MediaPlayerAudioPrivate(player);
+}
+
}
namespace android {
@@ -416,6 +439,13 @@ static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointe
player->onPosterFetched(posterNative);
}
+static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer) {
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ //TODO: player->onBuffering(percent);
+ }
+}
+
static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer) {
if (pointer) {
WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
@@ -437,11 +467,28 @@ static JNINativeMethod g_MediaPlayerMethods[] = {
(void*) OnTimeupdate },
};
-int register_mediaplayer(JNIEnv* env)
+static JNINativeMethod g_MediaAudioPlayerMethods[] = {
+ { "nativeOnBuffering", "(II)V",
+ (void*) OnBuffering },
+ { "nativeOnEnded", "(I)V",
+ (void*) OnEnded },
+ { "nativeOnPrepared", "(IIII)V",
+ (void*) OnPrepared },
+ { "nativeOnTimeupdate", "(II)V",
+ (void*) OnTimeupdate },
+};
+
+int register_mediaplayer_video(JNIEnv* env)
{
return jniRegisterNativeMethods(env, g_ProxyJavaClass,
g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods));
}
+int register_mediaplayer_audio(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio,
+ g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods));
+}
+
}
#endif // VIDEO
diff --git a/WebKit/android/jni/WebCoreJniOnLoad.cpp b/WebKit/android/jni/WebCoreJniOnLoad.cpp
index b5bf9dd..86248db 100644
--- a/WebKit/android/jni/WebCoreJniOnLoad.cpp
+++ b/WebKit/android/jni/WebCoreJniOnLoad.cpp
@@ -82,7 +82,8 @@ extern int register_webstorage(JNIEnv*);
extern int register_geolocation_permissions(JNIEnv*);
extern int register_mock_geolocation(JNIEnv*);
#if ENABLE(VIDEO)
-extern int register_mediaplayer(JNIEnv*);
+extern int register_mediaplayer_audio(JNIEnv*);
+extern int register_mediaplayer_video(JNIEnv*);
#endif
}
@@ -107,7 +108,8 @@ static RegistrationMethod gWebCoreRegMethods[] = {
{ "GeolocationPermissions", android::register_geolocation_permissions },
{ "MockGeolocation", android::register_mock_geolocation },
#if ENABLE(VIDEO)
- { "HTML5VideoViewProxy", android::register_mediaplayer },
+ { "HTML5Audio", android::register_mediaplayer_audio },
+ { "HTML5VideoViewProxy", android::register_mediaplayer_video },
#endif
};