OSDN Git Service

Merge "WebView animation support"
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / MediaTexture.cpp
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "config.h"
17 #include "MediaTexture.h"
18 #include "TilesManager.h"
19 #include "GLUtils.h"
20 #include "MediaListener.h"
21
22 #if USE(ACCELERATED_COMPOSITING)
23
24 #include <android/native_window.h>
25 #include <gui/SurfaceTexture.h>
26 #include <gui/SurfaceTextureClient.h>
27 #include <wtf/CurrentTime.h>
28 #include <JNIUtility.h>
29 #include "WebCoreJni.h"
30
31 #define LAYER_DEBUG
32 #undef LAYER_DEBUG
33
34 #ifdef DEBUG
35
36 #include <cutils/log.h>
37 #include <wtf/text/CString.h>
38
39 #undef XLOG
40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "MediaTexture", __VA_ARGS__)
41
42 #else
43
44 #undef XLOG
45 #define XLOG(...)
46
47 #endif // DEBUG
48
49 namespace WebCore {
50
51 MediaTexture::MediaTexture(jobject webViewRef) : android::LightRefBase<MediaTexture>()
52 {
53     if (webViewRef) {
54         JNIEnv* env = JSC::Bindings::getJNIEnv();
55         m_weakWebViewRef = env->NewWeakGlobalRef(webViewRef);
56     } else {
57         m_weakWebViewRef = 0;
58     }
59
60     m_textureId = 0;
61     m_dimensions.setEmpty();
62     m_newWindowRequest = false;
63     m_newWindowReady = false;
64     m_mediaListener = new MediaListener(m_weakWebViewRef);
65 }
66
67 MediaTexture::~MediaTexture()
68 {
69     releaseNativeWindow();
70     if (m_textureId)
71         glDeleteTextures(1, &m_textureId);
72     if (m_weakWebViewRef) {
73         JNIEnv* env = JSC::Bindings::getJNIEnv();
74         env->DeleteWeakGlobalRef(m_weakWebViewRef);
75     }
76 }
77
78 void MediaTexture::initNativeWindowIfNeeded()
79 {
80     {
81         android::Mutex::Autolock lock(m_mediaLock);
82
83         if(!m_newWindowRequest)
84             return;
85
86         // reuse an existing texture if possible
87         if (!m_textureId)
88             glGenTextures(1, &m_textureId);
89
90         m_surfaceTexture = new android::SurfaceTexture(m_textureId);
91         m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture);
92
93         //setup callback
94         m_mediaListener->resetFrameAvailable();
95         m_surfaceTexture->setFrameAvailableListener(m_mediaListener);
96
97         m_newWindowRequest = false;
98         m_newWindowReady = true;
99     }
100     m_newMediaRequestCond.signal();
101 }
102
103 void MediaTexture::drawContent(const TransformationMatrix& matrix)
104 {
105     android::Mutex::Autolock lock(m_mediaLock);
106
107     if(!m_surfaceTexture.get() || m_dimensions.isEmpty()
108             || !m_mediaListener->isFrameAvailable())
109         return;
110
111     m_surfaceTexture->updateTexImage();
112
113     sp<GraphicBuffer> buf = m_surfaceTexture->getCurrentBuffer();
114
115     PixelFormat f = buf->getPixelFormat();
116     // only attempt to use alpha blending if alpha channel exists
117     bool forceAlphaBlending = !(
118         PIXEL_FORMAT_RGBX_8888 == f ||
119         PIXEL_FORMAT_RGB_888 == f ||
120         PIXEL_FORMAT_RGB_565 == f ||
121         PIXEL_FORMAT_RGB_332 == f);
122
123     TilesManager::instance()->shader()->drawLayerQuad(matrix, m_dimensions,
124                                                       m_textureId, 1.0f,
125                                                       forceAlphaBlending,
126                                                       GL_TEXTURE_EXTERNAL_OES);
127 }
128
129 void MediaTexture::drawVideo(const TransformationMatrix& matrix, const SkRect& parentBounds)
130 {
131     android::Mutex::Autolock lock(m_mediaLock);
132
133     if(!m_surfaceTexture.get() || m_dimensions.isEmpty()
134             || !m_mediaListener->isFrameAvailable())
135         return;
136
137     m_surfaceTexture->updateTexImage();
138
139     float surfaceMatrix[16];
140     m_surfaceTexture->getTransformMatrix(surfaceMatrix);
141
142     SkRect dimensions = m_dimensions;
143     dimensions.offset(parentBounds.fLeft, parentBounds.fTop);
144
145 #ifdef DEBUG
146     if (!parentBounds.contains(dimensions)) {
147         XLOG("The video exceeds is parent's bounds.");
148     }
149 #endif // DEBUG
150
151     TilesManager::instance()->shader()->drawVideoLayerQuad(matrix, surfaceMatrix,
152             dimensions, m_textureId);
153 }
154
155 ANativeWindow* MediaTexture::requestNewWindow()
156 {
157     android::Mutex::Autolock lock(m_mediaLock);
158
159     // the window was not ready before the timeout so return it this time
160     if (m_newWindowReady) {
161         m_newWindowReady = false;
162         return m_surfaceTextureClient.get();
163     }
164     // we only allow for one texture, so if one already exists return null
165     else if (m_surfaceTextureClient.get()) {
166         return 0;
167     }
168
169     m_newWindowRequest = true;
170
171     // post an inval message to the UI thread to fulfill the request
172     if (m_weakWebViewRef) {
173         JNIEnv* env = JSC::Bindings::getJNIEnv();
174         jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
175         if (localWebViewRef) {
176             jclass wvClass = env->GetObjectClass(localWebViewRef);
177             jmethodID postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V");
178             env->CallVoidMethod(localWebViewRef, postInvalMethod);
179             env->DeleteLocalRef(wvClass);
180             env->DeleteLocalRef(localWebViewRef);
181         }
182         checkException(env);
183     }
184
185     //block until the request can be fulfilled or we time out
186     bool timedOut = false;
187     while (m_newWindowRequest && !timedOut) {
188         int ret = m_newMediaRequestCond.waitRelative(m_mediaLock, 500000000); // .5 sec
189         timedOut = ret == TIMED_OUT;
190     }
191
192     if (m_surfaceTextureClient.get())
193         m_newWindowReady = false;
194
195     return m_surfaceTextureClient.get();
196 }
197
198 ANativeWindow* MediaTexture::getNativeWindow()
199 {
200     android::Mutex::Autolock lock(m_mediaLock);
201     return m_surfaceTextureClient.get();
202 }
203
204 void MediaTexture::releaseNativeWindow()
205 {
206     android::Mutex::Autolock lock(m_mediaLock);
207     m_dimensions.setEmpty();
208
209     if (m_surfaceTexture.get())
210         m_surfaceTexture->setFrameAvailableListener(0);
211
212     // clear the strong pointer references
213     m_surfaceTextureClient.clear();
214     m_surfaceTexture.clear();
215 }
216
217 void MediaTexture::setDimensions(const SkRect& dimensions)
218 {
219     android::Mutex::Autolock lock(m_mediaLock);
220     m_dimensions = dimensions;
221 }
222
223 } // namespace WebCore
224
225 #endif // USE(ACCELERATED_COMPOSITING)