OSDN Git Service

Implement an invert screen mode
[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     m_content.clear();
72 #ifdef DEBUG_COUNT
73     ClassTracker::instance()->decrement("BaseLayerAndroid");
74 #endif
75 }
76
77 void BaseLayerAndroid::setContent(const PictureSet& src)
78 {
79 #if USE(ACCELERATED_COMPOSITING)
80     // FIXME: We lock here because we do not want
81     // to paint and change the m_content concurrently.
82     // We should instead refactor PictureSet to use
83     // an atomic refcounting scheme and use atomic operations
84     // to swap PictureSets.
85     android::Mutex::Autolock lock(m_drawLock);
86 #endif
87     m_content.set(src);
88     // FIXME: We cannot set the size of the base layer because it will screw up
89     // the matrix used.  We need to fix matrix computation for the base layer
90     // and then we can set the size.
91     // setSize(src.width(), src.height());
92 }
93
94 void BaseLayerAndroid::setExtra(SkPicture& src)
95 {
96 #if USE(ACCELERATED_COMPOSITING)
97     android::Mutex::Autolock lock(m_drawLock);
98 #endif
99     m_extra.swap(src);
100 }
101
102 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
103 {
104 #if USE(ACCELERATED_COMPOSITING)
105     android::Mutex::Autolock lock(m_drawLock);
106 #endif
107     if (!m_content.isEmpty())
108         m_content.draw(canvas);
109     // TODO : replace with !m_extra.isEmpty() once such a call exists
110     if (m_extra.width() > 0)
111         m_extra.draw(canvas);
112 }
113
114 #if USE(ACCELERATED_COMPOSITING)
115 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double currentTime)
116 {
117     if (!m_glWebViewState)
118         return false;
119
120     bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0;
121     bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0;
122
123     m_glWebViewState->setViewport(viewport, scale);
124
125     const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
126     XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
127             viewportTileBounds.fTop, scale);
128
129     if (scale == m_glWebViewState->currentScale()
130         || m_glWebViewState->preZoomBounds().isEmpty())
131         m_glWebViewState->setPreZoomBounds(viewportTileBounds);
132
133     bool prepareNextTiledPage = false;
134     // If we have a different scale than the current one, we have to
135     // decide what to do. The current behaviour is to delay an update,
136     // so that we do not slow down zooming unnecessarily.
137     if ((m_glWebViewState->currentScale() != scale && (m_glWebViewState->scaleRequestState() == GLWebViewState::kNoScaleRequest || m_glWebViewState->futureScale() != scale))
138         || m_glWebViewState->scaleRequestState() == GLWebViewState::kWillScheduleRequest) {
139
140         // schedule the new request
141         m_glWebViewState->scheduleUpdate(currentTime, viewportTileBounds, scale);
142
143         // If it's a new request, we will have to prepare the page.
144         if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale)
145             prepareNextTiledPage = true;
146     }
147
148     // If the viewport has changed since we scheduled the request, we also need to prepare.
149     if ((m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale || m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale)
150         && m_glWebViewState->futureViewport() != viewportTileBounds)
151         prepareNextTiledPage = true;
152
153     bool zooming = false;
154     if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
155         prepareNextTiledPage = true;
156         zooming = true;
157     }
158
159     // Display the current page
160     TiledPage* tiledPage = m_glWebViewState->frontPage();
161     tiledPage->setScale(m_glWebViewState->currentScale());
162
163     // Let's prepare the page if needed
164     if (prepareNextTiledPage) {
165         TiledPage* nextTiledPage = m_glWebViewState->backPage();
166         nextTiledPage->setScale(scale);
167         m_glWebViewState->setFutureViewport(viewportTileBounds);
168         m_glWebViewState->lockBaseLayerUpdate();
169         nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
170         // Cancel pending paints for the foreground page
171         TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
172     }
173
174     float transparency = 1;
175     bool doSwap = false;
176
177     // If we fired a request, let's check if it's ready to use
178     if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale) {
179         TiledPage* nextTiledPage = m_glWebViewState->backPage();
180         if (nextTiledPage->ready(viewportTileBounds, m_glWebViewState->futureScale()))
181             m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
182     }
183
184     // If the page is ready, display it. We do a short transition between
185     // the two pages (current one and future one with the new scale factor)
186     if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
187         TiledPage* nextTiledPage = m_glWebViewState->backPage();
188         double transitionTime = (scale < m_glWebViewState->currentScale()) ?
189             m_glWebViewState->zoomOutTransitionTime(currentTime) :
190             m_glWebViewState->zoomInTransitionTime(currentTime);
191
192         float newTilesTransparency = 1;
193         if (scale < m_glWebViewState->currentScale())
194             newTilesTransparency = 1 - m_glWebViewState->zoomOutTransparency(currentTime);
195         else
196             transparency = m_glWebViewState->zoomInTransparency(currentTime);
197
198         nextTiledPage->draw(newTilesTransparency, viewportTileBounds);
199
200         // The transition between the two pages is finished, swap them
201         if (currentTime > transitionTime) {
202             m_glWebViewState->resetTransitionTime();
203             doSwap = true;
204         }
205     }
206
207     const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
208
209     TiledPage* nextTiledPage = m_glWebViewState->backPage();
210     bool needsRedraw = false;
211
212     // We are now using an hybrid model -- during scrolling,
213     // we will display the current tiledPage even if some tiles are
214     // out of date. When standing still on the other hand, we wait until
215     // the back page is ready before swapping the pages, ensuring that the
216     // displayed content is in sync.
217     if (!doSwap && !zooming && !m_glWebViewState->moving()) {
218         if (!tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
219             m_glWebViewState->lockBaseLayerUpdate();
220             nextTiledPage->setScale(m_glWebViewState->currentScale());
221             nextTiledPage->prepare(goingDown, goingLeft, preZoomBounds);
222         }
223         if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
224             nextTiledPage->draw(transparency, preZoomBounds);
225             m_glWebViewState->resetFrameworkInval();
226             m_glWebViewState->unlockBaseLayerUpdate();
227             doSwap = true;
228         } else {
229             tiledPage->draw(transparency, preZoomBounds);
230         }
231     } else {
232         if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
233            m_glWebViewState->resetFrameworkInval();
234
235         // Ask for the tiles and draw -- tiles may be out of date.
236         if (!zooming)
237            m_glWebViewState->unlockBaseLayerUpdate();
238
239         if (!prepareNextTiledPage)
240             tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
241         tiledPage->draw(transparency, preZoomBounds);
242     }
243
244     if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
245         || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
246         needsRedraw = true;
247
248     if (doSwap) {
249         m_glWebViewState->setCurrentScale(scale);
250         m_glWebViewState->swapPages();
251         m_glWebViewState->unlockBaseLayerUpdate();
252     }
253
254     m_glWebViewState->paintExtras();
255     return needsRedraw;
256 }
257 #endif // USE(ACCELERATED_COMPOSITING)
258
259 bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
260                               IntRect& viewRect, SkRect& visibleRect,
261                               IntRect& webViewRect, int titleBarHeight,
262                               IntRect& screenClip, float scale, SkColor color)
263 {
264     bool needsRedraw = false;
265 #if USE(ACCELERATED_COMPOSITING)
266     int left = viewRect.x();
267     int top = viewRect.y();
268     int width = viewRect.width();
269     int height = viewRect.height();
270     XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d - %.2f",
271          left, top, width, height, scale);
272
273     m_glWebViewState->setBackgroundColor(color);
274     if (TilesManager::instance()->invertedScreen()) {
275         float color = 1.0 - ((((float) m_color.red() / 255.0) +
276                       ((float) m_color.green() / 255.0) +
277                       ((float) m_color.blue() / 255.0)) / 3.0);
278         glClearColor(color, color, color, 1);
279     } else {
280         glClearColor((float)m_color.red() / 255.0,
281                      (float)m_color.green() / 255.0,
282                      (float)m_color.blue() / 255.0, 1);
283     }
284     glClear(GL_COLOR_BUFFER_BIT);
285
286     glViewport(left, top, width, height);
287     ShaderProgram* shader = TilesManager::instance()->shader();
288     if (shader->program() == -1) {
289         XLOG("Reinit shader");
290         shader->init();
291     }
292     glUseProgram(shader->program());
293     glUniform1i(shader->textureSampler(), 0);
294     shader->setViewRect(viewRect);
295     shader->setViewport(visibleRect);
296     shader->setWebViewRect(webViewRect);
297     shader->setTitleBarHeight(titleBarHeight);
298     shader->setScreenClip(screenClip);
299     shader->resetBlending();
300
301     double currentTime = WTF::currentTime();
302     needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime);
303     bool goingDown = m_previousVisible.fTop - visibleRect.fTop <= 0;
304     bool goingLeft = m_previousVisible.fLeft - visibleRect.fLeft >= 0;
305     m_glWebViewState->setDirection(goingDown, goingLeft);
306     if (!needsRedraw)
307         m_glWebViewState->resetFrameworkInval();
308
309     if (compositedRoot) {
310         TransformationMatrix ident;
311
312         bool animsRunning = compositedRoot->evaluateAnimations();
313         if (animsRunning)
314             needsRedraw = true;
315
316         compositedRoot->updateFixedLayersPositions(visibleRect);
317         FloatRect clip(0, 0, viewRect.width(), viewRect.height());
318         compositedRoot->updateGLPositions(ident, clip, 1);
319         SkMatrix matrix;
320         matrix.setTranslate(left, top);
321
322         // Get the current scale; if we are zooming, we don't change the scale
323         // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
324         // we change the scaleRequestState. When the state is kReceivedNewScale
325         // we can use the future scale instead of the current scale to request
326         // new textures. After a transition time, the scaleRequestState will be
327         // reset and the current scale will be set to the future scale.
328         float scale = m_glWebViewState->currentScale();
329         if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
330             scale = m_glWebViewState->futureScale();
331         }
332         compositedRoot->setScale(scale);
333
334 #ifdef DEBUG
335         int size = compositedRoot->countTextureSize();
336         int nbLayers = compositedRoot->nbLayers();
337         XLOG("We are using %d Mb for %d layers", size / 1024 / 1024, nbLayers);
338         compositedRoot->showLayers();
339 #endif
340         // Clean up GL textures for video layer.
341         TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
342
343         if (compositedRoot->drawGL(m_glWebViewState, matrix))
344             needsRedraw = true;
345         else if (!animsRunning)
346             m_glWebViewState->resetLayersDirtyArea();
347
348     }
349
350     glBindBuffer(GL_ARRAY_BUFFER, 0);
351     m_previousVisible = visibleRect;
352
353 #endif // USE(ACCELERATED_COMPOSITING)
354 #ifdef DEBUG
355     ClassTracker::instance()->show();
356 #endif
357     return needsRedraw;
358 }
359
360 } // namespace WebCore