OSDN Git Service

Support the screen shot while the video is paused.
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / BaseLayerAndroid.cpp
1 /*
2  * Copyright 2010, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "BaseLayerAndroid.h"
28
29 #if USE(ACCELERATED_COMPOSITING)
30 #include "ClassTracker.h"
31 #include "GLUtils.h"
32 #include "ShaderProgram.h"
33 #include "SkCanvas.h"
34 #include "TilesManager.h"
35 #include <GLES2/gl2.h>
36 #include <wtf/CurrentTime.h>
37 #endif // USE(ACCELERATED_COMPOSITING)
38
39 #ifdef DEBUG
40
41 #include <cutils/log.h>
42 #include <wtf/text/CString.h>
43
44 #undef XLOG
45 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
46
47 #else
48
49 #undef XLOG
50 #define XLOG(...)
51
52 #endif // DEBUG
53
54 namespace WebCore {
55
56 using namespace android;
57
58 BaseLayerAndroid::BaseLayerAndroid()
59 #if USE(ACCELERATED_COMPOSITING)
60     : m_glWebViewState(0),
61       m_color(Color::white)
62 #endif
63 {
64 #ifdef DEBUG_COUNT
65     ClassTracker::instance()->increment("BaseLayerAndroid");
66 #endif
67 }
68
69 BaseLayerAndroid::~BaseLayerAndroid()
70 {
71 #if USE(ACCELERATED_COMPOSITING)
72     if (TilesManager::hardwareAccelerationEnabled())
73         TilesManager::instance()->removeOperationsForBaseLayer(this);
74 #endif
75     m_content.clear();
76 #ifdef DEBUG_COUNT
77     ClassTracker::instance()->decrement("BaseLayerAndroid");
78 #endif
79 }
80
81 void BaseLayerAndroid::setContent(const PictureSet& src)
82 {
83 #if USE(ACCELERATED_COMPOSITING)
84     // FIXME: We lock here because we do not want
85     // to paint and change the m_content concurrently.
86     // We should instead refactor PictureSet to use
87     // an atomic refcounting scheme and use atomic operations
88     // to swap PictureSets.
89     android::Mutex::Autolock lock(m_drawLock);
90 #endif
91     m_content.set(src);
92     // FIXME: We cannot set the size of the base layer because it will screw up
93     // the matrix used.  We need to fix matrix computation for the base layer
94     // and then we can set the size.
95     // setSize(src.width(), src.height());
96 }
97
98 void BaseLayerAndroid::setExtra(SkPicture& src)
99 {
100 #if USE(ACCELERATED_COMPOSITING)
101     android::Mutex::Autolock lock(m_drawLock);
102 #endif
103     m_extra.swap(src);
104 }
105
106 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
107 {
108 #if USE(ACCELERATED_COMPOSITING)
109     android::Mutex::Autolock lock(m_drawLock);
110 #endif
111     if (!m_content.isEmpty())
112         m_content.draw(canvas);
113     // TODO : replace with !m_extra.isEmpty() once such a call exists
114     if (m_extra.width() > 0)
115         m_extra.draw(canvas);
116 }
117
118 #if USE(ACCELERATED_COMPOSITING)
119 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double currentTime)
120 {
121     if (!m_glWebViewState)
122         return false;
123
124     bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0;
125     bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0;
126
127     m_glWebViewState->setViewport(viewport, scale);
128
129     const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
130     XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
131             viewportTileBounds.fTop, scale);
132
133     if (scale == m_glWebViewState->currentScale()
134         || m_glWebViewState->preZoomBounds().isEmpty())
135         m_glWebViewState->setPreZoomBounds(viewportTileBounds);
136
137     bool prepareNextTiledPage = false;
138     // If we have a different scale than the current one, we have to
139     // decide what to do. The current behaviour is to delay an update,
140     // so that we do not slow down zooming unnecessarily.
141     if ((m_glWebViewState->currentScale() != scale && (m_glWebViewState->scaleRequestState() == GLWebViewState::kNoScaleRequest || m_glWebViewState->futureScale() != scale))
142         || m_glWebViewState->scaleRequestState() == GLWebViewState::kWillScheduleRequest) {
143
144         // schedule the new request
145         m_glWebViewState->scheduleUpdate(currentTime, viewportTileBounds, scale);
146
147         // If it's a new request, we will have to prepare the page.
148         if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale)
149             prepareNextTiledPage = true;
150     }
151
152     // If the viewport has changed since we scheduled the request, we also need to prepare.
153     if ((m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale || m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale)
154         && m_glWebViewState->futureViewport() != viewportTileBounds)
155         prepareNextTiledPage = true;
156
157     bool zooming = false;
158     if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
159         prepareNextTiledPage = true;
160         zooming = true;
161     }
162
163     // Display the current page
164     TiledPage* tiledPage = m_glWebViewState->frontPage();
165     tiledPage->setScale(m_glWebViewState->currentScale());
166
167     // Let's prepare the page if needed
168     if (prepareNextTiledPage) {
169         TiledPage* nextTiledPage = m_glWebViewState->backPage();
170         nextTiledPage->setScale(scale);
171         m_glWebViewState->setFutureViewport(viewportTileBounds);
172         m_glWebViewState->lockBaseLayerUpdate();
173         nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
174         // Cancel pending paints for the foreground page
175         TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
176     }
177
178     float transparency = 1;
179     bool doSwap = false;
180
181     // If we fired a request, let's check if it's ready to use
182     if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale) {
183         TiledPage* nextTiledPage = m_glWebViewState->backPage();
184         if (nextTiledPage->ready(viewportTileBounds, m_glWebViewState->futureScale()))
185             m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
186     }
187
188     // If the page is ready, display it. We do a short transition between
189     // the two pages (current one and future one with the new scale factor)
190     if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
191         TiledPage* nextTiledPage = m_glWebViewState->backPage();
192         double transitionTime = (scale < m_glWebViewState->currentScale()) ?
193             m_glWebViewState->zoomOutTransitionTime(currentTime) :
194             m_glWebViewState->zoomInTransitionTime(currentTime);
195
196         float newTilesTransparency = 1;
197         if (scale < m_glWebViewState->currentScale())
198             newTilesTransparency = 1 - m_glWebViewState->zoomOutTransparency(currentTime);
199         else
200             transparency = m_glWebViewState->zoomInTransparency(currentTime);
201
202         nextTiledPage->draw(newTilesTransparency, viewportTileBounds);
203
204         // The transition between the two pages is finished, swap them
205         if (currentTime > transitionTime) {
206             m_glWebViewState->resetTransitionTime();
207             doSwap = true;
208         }
209     }
210
211     const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
212
213     TiledPage* nextTiledPage = m_glWebViewState->backPage();
214     bool needsRedraw = false;
215
216     // We are now using an hybrid model -- during scrolling,
217     // we will display the current tiledPage even if some tiles are
218     // out of date. When standing still on the other hand, we wait until
219     // the back page is ready before swapping the pages, ensuring that the
220     // displayed content is in sync.
221     if (!doSwap && !zooming && !m_glWebViewState->moving()) {
222         if (!tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
223             m_glWebViewState->lockBaseLayerUpdate();
224             nextTiledPage->setScale(m_glWebViewState->currentScale());
225             nextTiledPage->prepare(goingDown, goingLeft, preZoomBounds);
226         }
227         if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
228             nextTiledPage->draw(transparency, preZoomBounds);
229             m_glWebViewState->resetFrameworkInval();
230             m_glWebViewState->unlockBaseLayerUpdate();
231             doSwap = true;
232         } else {
233             tiledPage->draw(transparency, preZoomBounds);
234         }
235     } else {
236         if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
237            m_glWebViewState->resetFrameworkInval();
238
239         // Ask for the tiles and draw -- tiles may be out of date.
240         if (!zooming)
241            m_glWebViewState->unlockBaseLayerUpdate();
242
243         if (!prepareNextTiledPage)
244             tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
245         tiledPage->draw(transparency, preZoomBounds);
246     }
247
248     if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
249         || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
250         needsRedraw = true;
251
252     if (doSwap) {
253         m_glWebViewState->setCurrentScale(scale);
254         m_glWebViewState->swapPages();
255         m_glWebViewState->unlockBaseLayerUpdate();
256     }
257
258     m_glWebViewState->paintExtras();
259     return needsRedraw;
260 }
261 #endif // USE(ACCELERATED_COMPOSITING)
262
263 bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
264                               IntRect& viewRect, SkRect& visibleRect,
265                               IntRect& webViewRect, int titleBarHeight,
266                               IntRect& screenClip, float scale, SkColor color)
267 {
268     bool needsRedraw = false;
269 #if USE(ACCELERATED_COMPOSITING)
270     int left = viewRect.x();
271     int top = viewRect.y();
272     int width = viewRect.width();
273     int height = viewRect.height();
274     XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d - %.2f",
275          left, top, width, height, scale);
276
277     m_glWebViewState->setBackgroundColor(color);
278     glClearColor((float)m_color.red() / 255.0,
279                  (float)m_color.green() / 255.0,
280                  (float)m_color.blue() / 255.0, 1);
281     glClear(GL_COLOR_BUFFER_BIT);
282
283     glViewport(left, top, width, height);
284     ShaderProgram* shader = TilesManager::instance()->shader();
285     if (shader->program() == -1) {
286         XLOG("Reinit shader");
287         shader->init();
288     }
289     glUseProgram(shader->program());
290     glUniform1i(shader->textureSampler(), 0);
291     shader->setViewRect(viewRect);
292     shader->setViewport(visibleRect);
293     shader->setWebViewRect(webViewRect);
294     shader->setTitleBarHeight(titleBarHeight);
295     shader->setScreenClip(screenClip);
296     shader->resetBlending();
297
298     double currentTime = WTF::currentTime();
299     needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime);
300     if (!needsRedraw)
301         m_glWebViewState->resetFrameworkInval();
302
303     if (compositedRoot) {
304         TransformationMatrix ident;
305
306         bool animsRunning = compositedRoot->evaluateAnimations();
307         if (animsRunning)
308             needsRedraw = true;
309
310         compositedRoot->updateFixedLayersPositions(visibleRect);
311         FloatRect clip(0, 0, viewRect.width(), viewRect.height());
312         compositedRoot->updateGLPositions(ident, clip, 1);
313         SkMatrix matrix;
314         matrix.setTranslate(left, top);
315
316         // At this point, the previous LayerAndroid* root has been destroyed,
317         // which will have removed the layers as owners of the textures.
318         // Let's now do a pass to reserve the textures for the current tree;
319         // it will only reserve existing textures, not create them on demand.
320 #ifdef DEBUG
321         TilesManager::instance()->printLayersTextures("reserve");
322 #endif
323         // Get the current scale; if we are zooming, we don't change the scale
324         // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
325         // we change the scaleRequestState. When the state is kReceivedNewScale
326         // we can use the future scale instead of the current scale to request
327         // new textures. After a transition time, the scaleRequestState will be
328         // reset and the current scale will be set to the future scale.
329         float scale = m_glWebViewState->currentScale();
330         if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
331             scale = m_glWebViewState->futureScale();
332         }
333         bool fullSetup = true;
334         if ((m_glWebViewState->previouslyUsedRoot() == compositedRoot) &&
335             (compositedRoot->getScale() == scale) &&
336             (!m_glWebViewState->moving()))
337             fullSetup = false;
338
339         compositedRoot->setScale(scale);
340
341         if (fullSetup) {
342             compositedRoot->computeTextureSize(currentTime);
343             compositedRoot->reserveGLTextures();
344
345 #ifdef DEBUG
346             int size = compositedRoot->countTextureSize();
347             int nbLayers = compositedRoot->nbLayers();
348             XLOG("We are using %d Mb for %d layers", size / 1024 / 1024, nbLayers);
349             compositedRoot->showLayers();
350 #endif
351             // Now that we marked the textures being used, we delete
352             // the unnecessary ones to make space...
353             TilesManager::instance()->cleanupLayersTextures(compositedRoot);
354         }
355         // Clean up GL textures for video layer.
356         TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
357
358         // Finally do another pass to create new textures and schedule
359         // repaints if needed
360         compositedRoot->createGLTextures();
361
362         if (compositedRoot->drawGL(m_glWebViewState, matrix))
363             needsRedraw = true;
364         else if (!animsRunning)
365             m_glWebViewState->resetLayersDirtyArea();
366
367     } else {
368         TilesManager::instance()->cleanupLayersTextures(0);
369     }
370
371     glBindBuffer(GL_ARRAY_BUFFER, 0);
372     m_previousVisible = visibleRect;
373
374 #endif // USE(ACCELERATED_COMPOSITING)
375 #ifdef DEBUG
376     ClassTracker::instance()->show();
377 #endif
378     return needsRedraw;
379 }
380
381 } // namespace WebCore