1 /*
2 * Copyright 2011, 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 "ZoomManager.h"
28
29 #include "GLWebViewState.h"
30
31 #if USE(ACCELERATED_COMPOSITING)
32
33 #include <wtf/CurrentTime.h>
34
35 #include <cutils/log.h>
36 #include <wtf/text/CString.h>
37
38 #undef XLOGC
39 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "ZoomManager", __VA_ARGS__)
40
41 #ifdef DEBUG
42
43 #undef XLOG
44 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ZoomManager", __VA_ARGS__)
45
46 #else
47
48 #undef XLOG
49 #define XLOG(...)
50
51 #endif // DEBUG
52
53 namespace WebCore {
54
55 using namespace android;
56
ZoomManager(GLWebViewState * state)57 ZoomManager::ZoomManager(GLWebViewState* state)
58 : m_scaleRequestState(kNoScaleRequest)
59 , m_currentScale(-1)
60 , m_futureScale(-1)
61 , m_layersScale(-1)
62 , m_updateTime(-1)
63 , m_transitionTime(-1)
64 , m_glWebViewState(state)
65 {
66 }
67
scheduleUpdate(const double & currentTime,const SkIRect & viewport,float scale)68 void ZoomManager::scheduleUpdate(const double& currentTime,
69 const SkIRect& viewport, float scale)
70 {
71 // if no update time, set it
72 if (updateTime() == -1) {
73 m_scaleRequestState = kWillScheduleRequest;
74 setUpdateTime(currentTime + s_updateInitialDelay);
75 setFutureScale(scale);
76 m_glWebViewState->setFutureViewport(viewport);
77 return;
78 }
79
80 if (currentTime < updateTime())
81 return;
82
83 // we reached the scheduled update time, check if we can update
84 if (futureScale() == scale) {
85 // we are still with the previous scale, let's go
86 // with the update
87 m_scaleRequestState = kRequestNewScale;
88 setUpdateTime(-1);
89 } else {
90 // we reached the update time, but the planned update was for
91 // a different scale factor -- meaning the user is still probably
92 // in the process of zooming. Let's push the update time a bit.
93 setUpdateTime(currentTime + s_updateDelay);
94 setFutureScale(scale);
95 m_glWebViewState->setFutureViewport(viewport);
96 }
97 }
98
zoomInTransitionTime(double currentTime)99 double ZoomManager::zoomInTransitionTime(double currentTime)
100 {
101 if (m_transitionTime == -1)
102 m_transitionTime = currentTime + s_zoomInTransitionDelay;
103 return m_transitionTime;
104 }
105
zoomOutTransitionTime(double currentTime)106 double ZoomManager::zoomOutTransitionTime(double currentTime)
107 {
108 if (m_transitionTime == -1)
109 m_transitionTime = currentTime + s_zoomOutTransitionDelay;
110 return m_transitionTime;
111 }
112
zoomInTransparency(double currentTime)113 float ZoomManager::zoomInTransparency(double currentTime)
114 {
115 float t = zoomInTransitionTime(currentTime) - currentTime;
116 t *= s_invZoomInTransitionDelay;
117 return fmin(1, fmax(0, t));
118 }
119
zoomOutTransparency(double currentTime)120 float ZoomManager::zoomOutTransparency(double currentTime)
121 {
122 float t = zoomOutTransitionTime(currentTime) - currentTime;
123 t *= s_invZoomOutTransitionDelay;
124 return fmin(1, fmax(0, t));
125 }
126
swapPages()127 bool ZoomManager::swapPages()
128 {
129 bool reset = m_scaleRequestState != kNoScaleRequest;
130 m_scaleRequestState = kNoScaleRequest;
131 return reset;
132 }
133
processNewScale(double currentTime,float scale)134 void ZoomManager::processNewScale(double currentTime, float scale)
135 {
136 m_prepareNextTiledPage = false;
137 m_zooming = false;
138 const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
139
140 if (scale == m_currentScale
141 || m_glWebViewState->preZoomBounds().isEmpty())
142 m_glWebViewState->setPreZoomBounds(viewportTileBounds);
143
144 // If we have a different scale than the current one, we have to
145 // decide what to do. The current behaviour is to delay an update,
146 // so that we do not slow down zooming unnecessarily.
147 if ((m_currentScale != scale
148 && (m_scaleRequestState == ZoomManager::kNoScaleRequest
149 || m_futureScale != scale))
150 || m_scaleRequestState == ZoomManager::kWillScheduleRequest) {
151
152 // schedule the new Zoom request
153 scheduleUpdate(currentTime, viewportTileBounds, scale);
154
155 // If it's a new request, we will have to prepare the page.
156 if (m_scaleRequestState == ZoomManager::kRequestNewScale)
157 m_prepareNextTiledPage = true;
158 }
159
160 // If the viewport has changed since we scheduled the request, we also need
161 // to prepare.
162 if ((m_scaleRequestState == ZoomManager::kRequestNewScale
163 || m_scaleRequestState == ZoomManager::kReceivedNewScale)
164 && m_glWebViewState->futureViewport() != viewportTileBounds)
165 m_prepareNextTiledPage = true;
166
167 // Checking if we are zooming...
168 if (m_scaleRequestState != ZoomManager::kNoScaleRequest) {
169 m_prepareNextTiledPage = true;
170 m_zooming = true;
171 }
172
173 // Get the current scale; if we are zooming, we don't change the scale
174 // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
175 // we change the scaleRequestState. When the state is kReceivedNewScale
176 // (see setReceivedRequest()), we can use the future scale instead of
177 // the current scale to request new textures. After a transition time,
178 // the scaleRequestState will be reset and the current scale will be set
179 // to the future scale.
180 m_layersScale = m_currentScale;
181 }
182
processTransition(double currentTime,float scale,bool * doSwap,float * backPageTransparency,float * frontPageTransparency)183 void ZoomManager::processTransition(double currentTime, float scale,
184 bool* doSwap, float* backPageTransparency,
185 float* frontPageTransparency)
186 {
187 if (scale < m_currentScale)
188 *backPageTransparency = 1 - zoomOutTransparency(currentTime);
189 else
190 *frontPageTransparency = zoomInTransparency(currentTime);
191
192 // The transition between the two page is finished
193 if (currentTime > transitionTime(currentTime, scale)) {
194 resetTransitionTime();
195 *doSwap = true;
196 }
197 }
198
199 } // namespace WebCore
200
201 #endif // USE(ACCELERATED_COMPOSITING)
202