OSDN Git Service

Implement the audio tag in webkit -- the corresponding java CL is https://android...
authorNicolas Roard <nicolas@android.com>
Tue, 2 Feb 2010 13:11:32 +0000 (13:11 +0000)
committerBen Murdoch <benm@google.com>
Mon, 18 Oct 2010 12:07:05 +0000 (13:07 +0100)
Cherry pick to Gingerbread, DO NOT MERGE!

Bug:3101402
Change-Id: Idbfb0efcc777f9354fcf88df32105ca9e50a24cd

15 files changed:
CleanSpec.mk
WebCore/Android.derived.mk
WebCore/css/mediaControlsAndroid.css [new file with mode: 0644]
WebCore/html/HTMLMediaElement.cpp
WebCore/platform/android/RenderThemeAndroid.cpp
WebCore/platform/android/RenderThemeAndroid.h
WebCore/platform/graphics/MediaPlayer.cpp
WebCore/platform/graphics/MediaPlayer.h
WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h
WebKit/Android.mk
WebKit/android/RenderSkinAndroid.cpp
WebKit/android/RenderSkinMediaButton.cpp [new file with mode: 0644]
WebKit/android/RenderSkinMediaButton.h [new file with mode: 0644]
WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
WebKit/android/jni/WebCoreJniOnLoad.cpp

index cf1cd55..ebb3f75 100644 (file)
@@ -50,6 +50,9 @@ $(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/STATIC_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)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
index c678e60..cb6f902 100644 (file)
@@ -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 (file)
index 0000000..82f4bd3
--- /dev/null
@@ -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
+}
index 279aac7..bee91ae 100644 (file)
@@ -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();
index 4c5cff5..b1d0431 100644 (file)
 #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);
index ae1213c..3d7ac77 100644 (file)
@@ -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
-
index 2b09885..b527981 100644 (file)
@@ -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
index 40ed8ae..54bf9ec 100644 (file)
@@ -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
index 19bfcd1..0f38034 100644 (file)
@@ -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
 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 void getSupportedTypes(HashSet<String>&) { }
     static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
 
     MediaPlayerPrivate(MediaPlayer *);
-    void createJavaPlayerIfNeeded();
+    virtual void createJavaPlayerIfNeeded() { }
 
     MediaPlayer* m_player;
     String m_url;
index 2c12ed3..47f37ca 100644 (file)
@@ -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 \
        \
index d148262..00f2b96 100644 (file)
@@ -29,6 +29,7 @@
 #include "RenderSkinAndroid.h"
 #include "RenderSkinButton.h"
 #include "RenderSkinCombo.h"
+#include "RenderSkinMediaButton.h"
 #include "RenderSkinRadio.h"
 #include "SkImageDecoder.h"
 
@@ -45,7 +46,8 @@ RenderSkinAndroid::RenderSkinAndroid()
 void RenderSkinAndroid::Init(android::AssetManager* am, String drawableDirectory)
 {
     RenderSkinButton::Init(am, drawableDirectory);
-    RenderSkinCombo::Init(am);
+    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 (file)
index 0000000..149be4e
--- /dev/null
@@ -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 (file)
index 0000000..b4e99f4
--- /dev/null
@@ -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
index 3767516..b066511 100644 (file)
@@ -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,40 +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)
 {
     if (WebViewCore::supportsMimeType(type))
@@ -292,72 +143,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() {
@@ -370,25 +155,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 {
@@ -418,6 +446,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);
@@ -439,11 +474,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
index b5bf9dd..86248db 100644 (file)
@@ -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
 };