OSDN Git Service

Support drawing paused and loading image as GL texture
authorTeng-Hui Zhu <ztenghui@google.com>
Fri, 18 Mar 2011 22:41:20 +0000 (15:41 -0700)
committerTeng-Hui Zhu <ztenghui@google.com>
Mon, 21 Mar 2011 17:36:34 +0000 (10:36 -0700)
bug:4142131

Change-Id: I871924cb7587077f50fdf4f9a00056f795a8daea

WebCore/platform/graphics/android/VideoLayerAndroid.cpp
WebCore/platform/graphics/android/VideoLayerAndroid.h
WebKit/android/RenderSkinMediaButton.cpp
WebKit/android/RenderSkinMediaButton.h
WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp

index 697281c..32e518d 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "VideoLayerAndroid.h"
 
+#include "RenderSkinMediaButton.h"
 #include "TilesManager.h"
 #include <GLES2/gl2.h>
 #include <gui/SurfaceTexture.h>
 #endif // DEBUG
 
 namespace WebCore {
-GLuint VideoLayerAndroid::m_pauseTextureId = 0;
-bool VideoLayerAndroid::m_createdPauseTexture = false;
+
+GLuint VideoLayerAndroid::m_spinnerOuterTextureId = 0;
+GLuint VideoLayerAndroid::m_spinnerInnerTextureId = 0;
+GLuint VideoLayerAndroid::m_posterTextureId = 0;
+GLuint VideoLayerAndroid::m_backgroundTextureId = 0;
+bool VideoLayerAndroid::m_createdTexture = false;
+
+double VideoLayerAndroid::m_rotateDegree = 0;
+
+const IntRect VideoLayerAndroid::buttonRect(0, 0, IMAGESIZE, IMAGESIZE);
 
 VideoLayerAndroid::VideoLayerAndroid()
     : LayerAndroid((RenderLayer*)0)
@@ -67,21 +76,56 @@ void VideoLayerAndroid::init()
     // m_surfaceTexture is only useful on UI thread, no need to copy.
     // And it will be set at setBaseLayer timeframe
 
-    // m_useSurfTex will be true only after the player is prepared
-    m_useSurfTex = false;
+    m_playerState = INITIALIZED;
     m_textureId = 0;
 }
 
 // We can use this function to set the Layer to point to surface texture.
 void VideoLayerAndroid::setSurfaceTexture(sp<SurfaceTexture> texture,
-                                          int textureName, bool useSurfTex)
+                                          int textureName, PlayerState playerState)
 {
     m_surfaceTexture = texture;
     m_textureId = textureName;
-    m_useSurfTex = useSurfTex;
+
+    m_playerState = playerState;
+}
+
+GLuint VideoLayerAndroid::createSpinnerInnerTexture()
+{
+    return createTextureFromImage(RenderSkinMediaButton::SPINNER_INNER);
+}
+
+GLuint VideoLayerAndroid::createSpinnerOuterTexture()
+{
+    return createTextureFromImage(RenderSkinMediaButton::SPINNER_OUTER);
 }
 
-GLuint VideoLayerAndroid::createPauseTexture()
+GLuint VideoLayerAndroid::createPosterTexture()
+{
+    return createTextureFromImage(RenderSkinMediaButton::VIDEO);
+}
+
+GLuint VideoLayerAndroid::createTextureFromImage(int buttonType)
+{
+    SkRect rect = SkRect(buttonRect);
+    SkBitmap bitmap;
+    bitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+    bitmap.allocPixels();
+    bitmap.eraseColor(0);
+
+    SkCanvas canvas(bitmap);
+    canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
+    RenderSkinMediaButton::Draw(&canvas, buttonRect, buttonType, true);
+
+    GLuint texture;
+    glGenTextures(1, &texture);
+
+    GLUtils::createTextureWithBitmap(texture, bitmap);
+    bitmap.reset();
+    return texture;
+}
+
+GLuint VideoLayerAndroid::createBackgroundTexture()
 {
     GLuint texture;
     glGenTextures(1, &texture);
@@ -103,28 +147,70 @@ GLuint VideoLayerAndroid::createPauseTexture()
 
 bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
 {
-    // Lazy allocated the paused texture.
-    if (!m_createdPauseTexture) {
-        m_pauseTextureId = createPauseTexture();
-        m_createdPauseTexture = true;
+    // Lazily allocated the textures.
+    if (!m_createdTexture) {
+        m_backgroundTextureId = createBackgroundTexture();
+        m_spinnerOuterTextureId = createSpinnerOuterTexture();
+        m_spinnerInnerTextureId = createSpinnerInnerTexture();
+        m_posterTextureId = createPosterTexture();
+        m_createdTexture = true;
     }
 
     SkRect rect = SkRect::MakeSize(getSize());
     GLfloat surfaceMatrix[16];
 
-    // Draw the paused image or the Video
-    if (!m_surfaceTexture.get() || !m_useSurfTex) {
-        TransformationMatrix identity;
-        GLUtils::toGLMatrix(surfaceMatrix, identity);
+    SkRect innerRect = SkRect(buttonRect);
+    if (innerRect.contains(rect))
+        innerRect = rect;
+
+    innerRect.offset((rect.width() - IMAGESIZE) / 2 , (rect.height() - IMAGESIZE) / 2);
+
+    // Draw the poster image, the progressing image or the Video depending
+    // on the player's state.
+    if (m_playerState == PREPARING) {
+        // Show the progressing animation, with two rotating circles
         TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), rect,
-                                                          m_pauseTextureId,
+                                                          m_backgroundTextureId,
                                                           0.5, true);
-    } else {
+
+        TransformationMatrix addReverseRotation;
+        TransformationMatrix addRotation = drawTransform();
+        addRotation.translate(innerRect.fLeft, innerRect.fTop);
+        addRotation.translate(IMAGESIZE / 2, IMAGESIZE / 2);
+        addReverseRotation = addRotation;
+        addRotation.rotate(m_rotateDegree);
+        addRotation.translate(-IMAGESIZE / 2, -IMAGESIZE / 2);
+
+        SkRect size = SkRect::MakeWH(innerRect.width(), innerRect.height());
+        TilesManager::instance()->shader()->drawLayerQuad(addRotation, size,
+                                                          m_spinnerOuterTextureId,
+                                                          1, true);
+
+        addReverseRotation.rotate(-m_rotateDegree);
+        addReverseRotation.translate(-IMAGESIZE / 2, -IMAGESIZE / 2);
+
+        TilesManager::instance()->shader()->drawLayerQuad(addReverseRotation, size,
+                                                          m_spinnerInnerTextureId,
+                                                          1, true);
+
+        m_rotateDegree += ROTATESTEP;
+
+    } else if (m_playerState == PLAYING && m_surfaceTexture.get()) {
+        // Show the real video.
         m_surfaceTexture->updateTexImage();
         m_surfaceTexture->getTransformMatrix(surfaceMatrix);
         TilesManager::instance()->shader()->drawVideoLayerQuad(drawTransform(),
                                                                surfaceMatrix,
                                                                rect, m_textureId);
+    } else {
+        // Show the poster
+        TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), rect,
+                                                          m_backgroundTextureId,
+                                                          0.5, true);
+
+        TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), innerRect,
+                                                          m_posterTextureId,
+                                                          1, true);
     }
 
     return drawChildrenGL(glWebViewState, matrix);
index d291dda..eac565e 100644 (file)
@@ -38,6 +38,14 @@ class SurfaceTexture;
 
 namespace WebCore {
 
+// state get from UI thread to decide which image to draw.
+// PREPARING should be the progressing image
+// PLAYING will be the Video (Surface Texture).
+// Otherwise will draw a static image.
+// NOTE: These values are matching the ones in HTML5VideoView.java
+// Please keep them in sync when changed here.
+typedef enum {INITIALIZED, PREPARING, PREPARED, PLAYING} PlayerState;
+
 class VideoLayerAndroid : public LayerAndroid {
 
 public:
@@ -49,22 +57,36 @@ public:
 
     // The following 3 functions are called in UI thread only.
     virtual bool drawGL(GLWebViewState*, SkMatrix& matrix);
-    void setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, bool updateTexture);
-    GLuint createPauseTexture();
+    void setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, PlayerState playerState);
+    GLuint createBackgroundTexture();
+    GLuint createSpinnerOuterTexture();
+    GLuint createSpinnerInnerTexture();
+    GLuint createPosterTexture();
 
 private:
+    GLuint createTextureFromImage(int buttonType);
     void init();
     // Surface texture for showing the video is actually allocated in Java side
     // and passed into this native code.
     GLuint m_textureId;
     sp<android::SurfaceTexture> m_surfaceTexture;
-    bool m_useSurfTex;
 
-    // Texture for showing the paused image will be created at native side.
+    PlayerState m_playerState;
+
+    // Texture for showing the static image will be created at native side.
     // TODO: instead using a shared texture, we could make a texture pool to
     // show different screen shots for different videos
-    static GLuint m_pauseTextureId;
-    static bool m_createdPauseTexture;
+    static bool m_createdTexture;
+    static GLuint m_backgroundTextureId;
+    static GLuint m_posterTextureId;
+    static GLuint m_spinnerOuterTextureId;
+    static GLuint m_spinnerInnerTextureId;
+
+    static double m_rotateDegree;
+
+    static const int ROTATESTEP = 12;
+    static const int IMAGESIZE = 64;
+    static const IntRect buttonRect;
 };
 
 } // namespace WebCore
index 6a11eda..745fa88 100644 (file)
@@ -54,9 +54,12 @@ static const PatchData gFiles[] =
         { "ic_media_rew.png", 0, 0 }, // REWIND
         { "ic_media_ff.png", 0, 0 }, // FORWARD
         { "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN
+        { "spinner_76_outer_holo.png", 0, 0 }, // SPINNER_OUTER
+        { "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER
+        { "ic_media_video_poster.png", 0, 0 }, // VIDEO
         { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
-        { "scrubber_track_holo_dark.9.png", 0, 0 },  // SLIDER_TRACK
-        { "scrubber_control_holo.png", 0, 0 }      // SLIDER_THUMB
+        { "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK
+        { "scrubber_control_holo.png", 0, 0 } // SLIDER_THUMB
     };
 
 static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
@@ -124,6 +127,14 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
          paint.setColor(backgroundColor);
          break;
     }
+    case SPINNER_OUTER:
+    case SPINNER_INNER:
+    case VIDEO:
+    {
+         drawsBackgroundColor = false;
+         imageIndex = buttonType + 1;
+         break;
+    }
     case BACKGROUND_SLIDER:
     {
          drawsBackgroundColor = false;
@@ -200,4 +211,4 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
     }
 }
 
-} //WebCore
+} // WebCore
index 026f538..6aa9c4e 100644 (file)
@@ -34,8 +34,7 @@ namespace WebCore {
 class IntRect;
 class RenderObject;
 
-class RenderSkinMediaButton
-{
+class RenderSkinMediaButton {
 public:
     /**
      * Initialize the class before use. Uses the AssetManager to initialize any
@@ -51,7 +50,7 @@ public:
     /**
      * Button types
      */
-    enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, FULLSCREEN, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB };
+    enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, FULLSCREEN, SPINNER_OUTER, SPINNER_INNER , VIDEO, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB };
     /**
      * Slider dimensions
      */
index 4cc9cf4..d61b0dd 100644 (file)
@@ -567,7 +567,7 @@ static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer)
 // Return value: true when the video layer is found.
 static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex,
                                int baseLayer, int videoLayerId,
-                               int textureName, bool updateTexture) {
+                               int textureName, int playerState) {
     if (!surfTex)
         return false;
 
@@ -590,7 +590,7 @@ static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex,
         return false;
 
     // Set the SurfaceTexture to the layer we found
-    videoLayer->setSurfaceTexture(texture, textureName, updateTexture);
+    videoLayer->setSurfaceTexture(texture, textureName, static_cast<PlayerState>(playerState));
     return true;
 }
 
@@ -607,7 +607,7 @@ static JNINativeMethod g_MediaPlayerMethods[] = {
         (void*) OnPaused },
     { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V",
         (void*) OnPosterFetched },
-    { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIIZ)Z",
+    { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z",
         (void*) SendSurfaceTexture },
     { "nativeOnTimeupdate", "(II)V",
         (void*) OnTimeupdate },