10bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu/*
20bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * Copyright 2011 The Android Open Source Project
30bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *
40bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * Redistribution and use in source and binary forms, with or without
50bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * modification, are permitted provided that the following conditions
60bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * are met:
70bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *  * Redistributions of source code must retain the above copyright
80bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *    notice, this list of conditions and the following disclaimer.
90bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *  * Redistributions in binary form must reproduce the above copyright
100bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *    notice, this list of conditions and the following disclaimer in the
110bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *    documentation and/or other materials provided with the distribution.
120bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu *
130bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
140bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
150bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
160bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
170bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
180bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
190bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
200bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
210bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
220bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
230bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
240bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu */
250bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
26d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik#define LOG_TAG "VideoLayerManager"
27d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik#define LOG_NDEBUG 1
28d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik
290bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#include "config.h"
300bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#include "VideoLayerManager.h"
3117dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu
32d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik#include "AndroidLog.h"
3300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu#include "RenderSkinMediaButton.h"
3400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu#include "SkCanvas.h"
35d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu#include <wtf/CurrentTime.h>
360bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
370bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#if USE(ACCELERATED_COMPOSITING)
380bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
39d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu// The animation of the play/pause icon will last for PLAY_PAUSE_ICON_SHOW_TIME
40d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu// seconds.
41d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu#define PLAY_PAUSE_ICON_SHOW_TIME 1
42d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu
430bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Define the max sum of all the video's sizes.
440bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Note that video_size = width * height. If there is no compression, then the
450bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// maximum memory consumption could be 4 * video_size.
460bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Setting this to 2M, means that maximum memory consumption of all the
470bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// screenshots would not be above 8M.
480bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#define MAX_VIDEOSIZE_SUM 2097152
490bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
5017dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu// We don't preload the video data, so we don't have the exact size yet.
5117dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu// Assuming 16:9 by default, this will be corrected after video prepared.
5217dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu#define DEFAULT_VIDEO_ASPECT_RATIO 1.78
5317dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu
5400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu#define VIDEO_TEXTURE_NUMBER 5
5500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu#define VIDEO_BUTTON_SIZE 64
5600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
570bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhunamespace WebCore {
580bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
590bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui ZhuVideoLayerManager::VideoLayerManager()
6000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    : m_currentTimeStamp(0)
6100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_createdTexture(false)
6200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_posterTextureId(0)
6300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_spinnerOuterTextureId(0)
6400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_spinnerInnerTextureId(0)
6500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_playTextureId(0)
6600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_pauseTextureId(0)
6700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    , m_buttonRect(0, 0, VIDEO_BUTTON_SIZE, VIDEO_BUTTON_SIZE)
680bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
6900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu}
7000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
7100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhuint VideoLayerManager::getButtonSize()
7200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu{
7300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    return VIDEO_BUTTON_SIZE;
7400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu}
7500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
763718b58e4da76b7025aa5316a51264c5e38f2569John ReckGLuint VideoLayerManager::createTextureFromImage(RenderSkinMediaButton::MediaButton buttonType)
7700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu{
7800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    SkRect rect = SkRect(m_buttonRect);
7900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    SkBitmap bitmap;
8000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    bitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
8100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    bitmap.allocPixels();
8200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    bitmap.eraseColor(0);
8300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
8400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    SkCanvas canvas(bitmap);
8500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
863718b58e4da76b7025aa5316a51264c5e38f2569John Reck    RenderSkinMediaButton::Draw(&canvas, m_buttonRect, buttonType, true, false);
8700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
8800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    GLuint texture;
8900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    glGenTextures(1, &texture);
9000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
9100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    GLUtils::createTextureWithBitmap(texture, bitmap);
9200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    bitmap.reset();
9300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    return texture;
9400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu}
9500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
9600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu// Should be called at the VideoLayerAndroid::drawGL to make sure we allocate
9700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu// the GL resources lazily.
9800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhuvoid VideoLayerManager::initGLResourcesIfNeeded()
9900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu{
10000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    if (!m_createdTexture) {
101d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik        ALOGD("Reinit GLResource for VideoLayer");
10200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        initGLResources();
10300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    }
10400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu}
10500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
10600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhuvoid VideoLayerManager::initGLResources()
10700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu{
10800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    GLUtils::checkGlError("before initGLResources()");
1092ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu    m_spinnerOuterTextureId =
1102ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu        createTextureFromImage(RenderSkinMediaButton::SPINNER_OUTER);
1112ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu    m_spinnerInnerTextureId =
1122ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu        createTextureFromImage(RenderSkinMediaButton::SPINNER_INNER);
1132ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu    m_posterTextureId =
1142ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu        createTextureFromImage(RenderSkinMediaButton::VIDEO);
1152ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu    m_playTextureId = createTextureFromImage(RenderSkinMediaButton::PLAY);
1162ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu    m_pauseTextureId = createTextureFromImage(RenderSkinMediaButton::PAUSE);
1172ac76fe4e18c3325c8b3bb8f9435fdc7b96c0acaTeng-Hui Zhu
11800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    m_createdTexture = !GLUtils::checkGlError("initGLResources()");
11900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    return;
12000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu}
12100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
12200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhuvoid VideoLayerManager::cleanupGLResources()
12300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu{
12400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    if (m_createdTexture) {
12500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        GLuint videoTextures[VIDEO_TEXTURE_NUMBER] = { m_spinnerOuterTextureId,
12600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu            m_spinnerInnerTextureId, m_posterTextureId, m_playTextureId,
12700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu            m_pauseTextureId };
12800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
12900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        glDeleteTextures(VIDEO_TEXTURE_NUMBER, videoTextures);
13000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        m_createdTexture = false;
13100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    }
13200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    // Delete the texture in retired mode, but have not hit draw call to be
13300144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    // removed.
13400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    deleteUnusedTextures();
13500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
13600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    // Go over the registered GL textures (screen shot textures) and delete them.
13700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
13800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    InfoIterator end = m_videoLayerInfoMap.end();
13900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it) {
14000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        // The map include every video has been played, so their textureId can
14100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        // be deleted already, like hitting onTrimMemory multiple times.
14200144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        if (it->second->textureId) {
143d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik            ALOGV("delete texture from the map %d", it->second->textureId);
14400144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu            glDeleteTextures(1, &it->second->textureId);
14500144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu            // Set the textureID to 0 to show the video icon.
14600144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu            it->second->textureId = 0;
14700144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu        }
14800144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    }
14900144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu
15000144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    GLUtils::checkGlError("cleanupGLResources()");
15100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    return;
1520bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
1530bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
1540bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Getting TextureId for GL draw call, in the UI thread.
1550bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui ZhuGLuint VideoLayerManager::getTextureId(const int layerId)
1560bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
1570bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
1580bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    GLuint result = 0;
1590bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId))
1600bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        result = m_videoLayerInfoMap.get(layerId)->textureId;
1610bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return result;
1620bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
1630bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
16417dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu// Getting the aspect ratio for GL draw call, in the UI thread.
16517dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhufloat VideoLayerManager::getAspectRatio(const int layerId)
16617dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu{
16717dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
16817dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu    float result = 0;
16917dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId))
17017dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu        result = m_videoLayerInfoMap.get(layerId)->aspectRatio;
17117dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu    return result;
17217dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu}
17317dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu
1740bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Getting matrix for GL draw call, in the UI thread.
1750bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui ZhuGLfloat* VideoLayerManager::getMatrix(const int layerId)
1760bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
1770bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
1780bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    GLfloat* result = 0;
1790bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId))
1800bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        result = m_videoLayerInfoMap.get(layerId)->surfaceMatrix;
1810bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return result;
1820bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
1830bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
1840bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhuint VideoLayerManager::getTotalMemUsage()
1850bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
1860bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    int sum = 0;
1870bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    InfoIterator end = m_videoLayerInfoMap.end();
1880bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it)
1890bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        sum += it->second->videoSize;
1900bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return sum;
1910bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
1920bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
1930bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// When the video start, we know its texture info, so we register when we
1940bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// recieve the setSurfaceTexture call, this happens on UI thread.
1950bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhuvoid VideoLayerManager::registerTexture(const int layerId, const GLuint textureId)
1960bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
1970bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
1980bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // If the texture has been registered, then early return.
1990bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (m_videoLayerInfoMap.get(layerId)) {
2000bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        GLuint oldTextureId = m_videoLayerInfoMap.get(layerId)->textureId;
2010bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        if (oldTextureId != textureId)
2020bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            removeLayerInternal(layerId);
2030bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        else
2040bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            return;
2050bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    }
2060bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // The old info is deleted and now complete the new info and store it.
2070bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    VideoLayerInfo* pInfo = new VideoLayerInfo();
2080bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    pInfo->textureId = textureId;
2090bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    memset(pInfo->surfaceMatrix, 0, sizeof(pInfo->surfaceMatrix));
2100bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    pInfo->videoSize = 0;
21117dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu    pInfo->aspectRatio = DEFAULT_VIDEO_ASPECT_RATIO;
2120bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    m_currentTimeStamp++;
2130bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    pInfo->timeStamp = m_currentTimeStamp;
214d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    pInfo->lastIconShownTime = 0;
215d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    pInfo->iconState = Registered;
2160bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2170bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    m_videoLayerInfoMap.add(layerId, pInfo);
218d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik    ALOGV("GL texture %d regisered for layerId %d", textureId, layerId);
2190bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2200bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return;
2210bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
2220bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2230bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Only when the video is prepared, we got the video size. So we should update
2240bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// the size for the video accordingly.
2250bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// This is called from webcore thread, from MediaPlayerPrivateAndroid.
22617dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhuvoid VideoLayerManager::updateVideoLayerSize(const int layerId, const int size,
22717dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu                                             const float ratio)
2280bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
2290bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
2300bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId)) {
2310bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId);
23217dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu        if (pInfo) {
2330bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            pInfo->videoSize = size;
23417dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu            pInfo->aspectRatio = ratio;
23517dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu        }
2360bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    }
2370bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2380bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // If the memory usage is out of bound, then just delete the oldest ones.
2390bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // Because we only recycle the texture before the current timestamp, the
2400bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // current video's texture will not be deleted.
2410bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    while (getTotalMemUsage() > MAX_VIDEOSIZE_SUM)
2420bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        if (!recycleTextureMem())
2430bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            break;
2440bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return;
2450bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
2460bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2470bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// This is called only from UI thread, at drawGL time.
2480bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhuvoid VideoLayerManager::updateMatrix(const int layerId, const GLfloat* matrix)
2490bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
2500bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
2510bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId)) {
2520bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        // If the existing video layer's matrix is matching the incoming one,
2530bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        // then skip the update.
2540bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId);
2550bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        ASSERT(matrix);
2560bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        if (pInfo && !memcmp(matrix, pInfo->surfaceMatrix, sizeof(pInfo->surfaceMatrix)))
2570bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            return;
2580bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        memcpy(pInfo->surfaceMatrix, matrix, sizeof(pInfo->surfaceMatrix));
2590bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    } else {
260d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik        ALOGV("Error: should not reach here, the layerId %d should exist!", layerId);
2610bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        ASSERT(false);
2620bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    }
2630bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return;
2640bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
2650bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2660bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// This is called on the webcore thread, save the GL texture for recycle in
2670bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// the retired queue. They will be deleted in deleteUnusedTextures() in the UI
2680bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// thread.
2690bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// Return true when we found one texture to retire.
2700bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhubool VideoLayerManager::recycleTextureMem()
2710bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
2720bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // Find the oldest texture int the m_videoLayerInfoMap, put it in m_retiredTextures
2730bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    int oldestTimeStamp = m_currentTimeStamp;
2740bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    int oldestLayerId = -1;
2750bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2760bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    InfoIterator end = m_videoLayerInfoMap.end();
2770bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#ifdef DEBUG
278d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik    ALOGV("VideoLayerManager::recycleTextureMem m_videoLayerInfoMap contains");
2790bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it)
280d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik        ALOGV("  layerId %d, textureId %d, videoSize %d, timeStamp %d ",
281d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik              it->first, it->second->textureId, it->second->videoSize, it->second->timeStamp);
2820bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#endif
2830bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it) {
2840bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        if (it->second->timeStamp < oldestTimeStamp) {
2850bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            oldestTimeStamp = it->second->timeStamp;
2860bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            oldestLayerId = it->first;
2870bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        }
2880bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    }
2890bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2900bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    bool foundTextureToRetire = (oldestLayerId != -1);
2910bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (foundTextureToRetire)
2920bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        removeLayerInternal(oldestLayerId);
2930bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2940bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return foundTextureToRetire;
2950bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
2960bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
2970bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// This is only called in the UI thread, b/c glDeleteTextures need to be called
2980bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// on the right context.
2990bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhuvoid VideoLayerManager::deleteUnusedTextures()
3000bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
3010bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    m_retiredTexturesLock.lock();
3020bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    int size = m_retiredTextures.size();
3030bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (size > 0) {
3040bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        GLuint* textureNames = new GLuint[size];
3050bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        int index = 0;
3060bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        Vector<GLuint>::const_iterator end = m_retiredTextures.end();
3070bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        for (Vector<GLuint>::const_iterator it = m_retiredTextures.begin();
3080bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu             it != end; ++it) {
3090bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            GLuint textureName = *it;
3100bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            if (textureName) {
3110bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu                textureNames[index] = textureName;
3120bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu                index++;
313d487c56b47c747d3e331ee1892e4c0473363afd2Chris Craik                ALOGV("GL texture %d will be deleted", textureName);
3140bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            }
3150bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        }
3160bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        glDeleteTextures(size, textureNames);
3170bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        delete textureNames;
3180bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        m_retiredTextures.clear();
3190bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    }
3200bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    m_retiredTexturesLock.unlock();
32100144be011338276839a08a66ae79b14629b268bTeng-Hui Zhu    GLUtils::checkGlError("deleteUnusedTextures");
3220bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return;
3230bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
3240bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
3250bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// This can be called in the webcore thread in the media player's dtor.
3260bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhuvoid VideoLayerManager::removeLayer(const int layerId)
3270bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
3280bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
3290bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    removeLayerInternal(layerId);
3300bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
3310bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
3320bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// This can be called on both UI and webcore thread. Since this is a private
3330bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// function, it is up to the public function to handle the lock for
3340bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu// m_videoLayerInfoMap.
3350bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhuvoid VideoLayerManager::removeLayerInternal(const int layerId)
3360bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu{
3370bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    // Delete the layerInfo corresponding to this layerId and remove from the map.
3380bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId)) {
3390bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        GLuint textureId = m_videoLayerInfoMap.get(layerId)->textureId;
3400bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        if (textureId) {
3410bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            // Buffer up the retired textures in either UI or webcore thread,
3420bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            // will be purged at deleteUnusedTextures in the UI thread.
3430bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            m_retiredTexturesLock.lock();
3440bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            m_retiredTextures.append(textureId);
3450bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu            m_retiredTexturesLock.unlock();
3460bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        }
3470bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        delete m_videoLayerInfoMap.get(layerId);
3480bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu        m_videoLayerInfoMap.remove(layerId);
3490bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    }
3500bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu    return;
3510bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
3520bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu
353d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhudouble VideoLayerManager::drawIcon(const int layerId, IconType type)
354d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu{
355d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    // When ratio 0 is returned, the Icon should not be drawn.
356d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    double ratio = 0;
357d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu
358d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    android::Mutex::Autolock lock(m_videoLayerInfoMapLock);
359d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    if (m_videoLayerInfoMap.contains(layerId)) {
360d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId);
361d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        // If this is state switching moment, reset the time and state
362d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        if ((type == PlayIcon && pInfo->iconState != PlayIconShown)
36317dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu            || (type == PauseIcon && pInfo->iconState != PauseIconShown)) {
364d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu            pInfo->lastIconShownTime = WTF::currentTime();
365d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu            pInfo->iconState = (type == PlayIcon) ? PlayIconShown : PauseIconShown;
366d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        }
367d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu
368d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        // After switching the state, we calculate the ratio depending on the
369d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        // time interval.
370d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        if ((type == PlayIcon && pInfo->iconState == PlayIconShown)
371d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu            || (type == PauseIcon && pInfo->iconState == PauseIconShown)) {
372d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu            double delta = WTF::currentTime() - pInfo->lastIconShownTime;
373d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu            ratio = 1.0 - (delta / PLAY_PAUSE_ICON_SHOW_TIME);
374d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        }
375d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    }
376d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu
37717dd0d4d7d8ec66c8fb4acb5c580b38d9465d272Teng-Hui Zhu    if (ratio > 1 || ratio < 0)
378d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu        ratio = 0;
379d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu    return ratio;
380d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu}
381d649883ce629c0de432e075254b517a50685792eTeng-Hui Zhu
3820bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu}
3830bc8a6f1de48da432733e2bd21c5c793b7a0393dTeng-Hui Zhu#endif // USE(ACCELERATED_COMPOSITING)
384