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