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#define LOG_TAG "SurfaceBacking"
27#define LOG_NDEBUG 1
28
29#include "config.h"
30#include "SurfaceBacking.h"
31
32#include "AndroidLog.h"
33#include "Color.h"
34#include "ClassTracker.h"
35#include "GLWebViewState.h"
36#include "LayerAndroid.h"
37
38#define LOW_RES_PREFETCH_SCALE_MODIFIER 0.3f
39
40namespace WebCore {
41
42SurfaceBacking::SurfaceBacking(bool isBaseSurface)
43    : m_frontTileGrid(new TileGrid(isBaseSurface))
44    , m_backTileGrid(new TileGrid(isBaseSurface))
45    , m_lowResTileGrid(new TileGrid(isBaseSurface))
46    , m_scale(-1)
47    , m_futureScale(-1)
48    , m_zooming(false)
49    , m_maxZoomScale(1)
50
51{
52#ifdef DEBUG_COUNT
53    ClassTracker::instance()->increment("SurfaceBacking");
54#endif
55}
56
57SurfaceBacking::~SurfaceBacking()
58{
59    delete m_frontTileGrid;
60    delete m_backTileGrid;
61    delete m_lowResTileGrid;
62#ifdef DEBUG_COUNT
63    ClassTracker::instance()->decrement("SurfaceBacking");
64#endif
65}
66
67void SurfaceBacking::prepareGL(GLWebViewState* state, float maxZoomScale,
68                               const IntRect& prepareArea, const IntRect& fullContentArea,
69                               TilePainter* painter, bool aggressiveRendering,
70                               bool updateWithBlit)
71{
72    // If the surface backing has ever zoomed beyond 1.0 scale, it's always
73    // allowed to (so repaints aren't necessary when allowZoom toggles). If not,
74    // and allowZoom is false, don't allow scale greater than 1.0
75    m_maxZoomScale = std::max(m_maxZoomScale, maxZoomScale);
76    float scale = state->scale();
77    bool scaleOverridden = false;
78    if (scale > m_maxZoomScale) {
79        scale = m_maxZoomScale;
80        scaleOverridden = true;
81    }
82
83    if (m_scale == -1) {
84        m_scale = scale;
85        m_futureScale = scale;
86    }
87
88    if (m_futureScale != scale) {
89        m_futureScale = scale;
90        if (scaleOverridden)
91            m_zoomUpdateTime = 0; // start rendering immediately
92        else
93            m_zoomUpdateTime = WTF::currentTime() + SurfaceBacking::s_zoomUpdateDelay;
94        m_zooming = true;
95
96        // release back TileGrid's TileTextures, so they can be reused immediately
97        m_backTileGrid->discardTextures();
98    }
99
100    int prepareRegionFlags = TileGrid::StandardRegion;
101    if (aggressiveRendering)
102        prepareRegionFlags |= TileGrid::ExpandedRegion;
103
104    ALOGV("Prepare SurfBack %p, scale %.2f, m_scale %.2f, futScale: %.2f, zooming: %d, f %p, b %p",
105          this, scale, m_scale, m_futureScale, m_zooming,
106          m_frontTileGrid, m_backTileGrid);
107
108    if (m_zooming && (m_zoomUpdateTime < WTF::currentTime())) {
109        // prepare the visible portions of the back tile grid at the futureScale
110        m_backTileGrid->prepareGL(state, m_futureScale,
111                                  prepareArea, fullContentArea, painter,
112                                  TileGrid::StandardRegion, false);
113
114        if (m_backTileGrid->isReady()) {
115            // zooming completed, swap the TileGrids and new front tiles
116            swapTileGrids();
117
118            m_frontTileGrid->swapTiles();
119            m_backTileGrid->discardTextures();
120            m_lowResTileGrid->discardTextures();
121
122            m_scale = m_futureScale;
123            m_zooming = false;
124
125            // clear the StandardRegion flag, to prevent preparing it twice -
126            // the new frontTileGrid has already had its StandardRegion prepared
127            prepareRegionFlags &= ~TileGrid::StandardRegion;
128        }
129    }
130
131    if (!m_zooming) {
132        if (prepareRegionFlags) {
133            // if the front grid hasn't already prepared, or needs to prepare
134            // expanded bounds do so now
135            m_frontTileGrid->prepareGL(state, m_scale,
136                                       prepareArea, fullContentArea, painter,
137                                       prepareRegionFlags, false, updateWithBlit);
138        }
139        if (aggressiveRendering) {
140            // prepare low res content
141            float lowResPrefetchScale = m_scale * LOW_RES_PREFETCH_SCALE_MODIFIER;
142            m_lowResTileGrid->prepareGL(state, lowResPrefetchScale,
143                                       prepareArea, fullContentArea, painter,
144                                       TileGrid::StandardRegion | TileGrid::ExpandedRegion, true);
145            m_lowResTileGrid->swapTiles();
146        }
147    }
148}
149
150void SurfaceBacking::drawGL(const IntRect& visibleContentArea, float opacity,
151                            const TransformationMatrix* transform,
152                            bool aggressiveRendering, const Color* background)
153{
154    // draw low res prefetch page if zooming or front texture missing content
155    if (aggressiveRendering && isMissingContent())
156        m_lowResTileGrid->drawGL(visibleContentArea, opacity, transform);
157
158    m_frontTileGrid->drawGL(visibleContentArea, opacity, transform, background);
159}
160
161void SurfaceBacking::markAsDirty(const SkRegion& dirtyArea)
162{
163    m_backTileGrid->markAsDirty(dirtyArea);
164    m_frontTileGrid->markAsDirty(dirtyArea);
165    m_lowResTileGrid->markAsDirty(dirtyArea);
166}
167
168bool SurfaceBacking::swapTiles()
169{
170    bool swap = m_backTileGrid->swapTiles();
171    swap |= m_frontTileGrid->swapTiles();
172    swap |= m_lowResTileGrid->swapTiles();
173    return swap;
174}
175
176void SurfaceBacking::computeTexturesAmount(TexturesResult* result,
177                                           const IntRect& visibleContentArea,
178                                           const IntRect& fullContentArea,
179                                           LayerAndroid* layer)
180{
181
182    // get two numbers here:
183    // - textures needed for a clipped area
184    // - textures needed for an un-clipped area
185    TileGrid* tileGrid = m_zooming ? m_backTileGrid : m_frontTileGrid;
186    int nbTexturesUnclipped = tileGrid->nbTextures(fullContentArea, m_futureScale);
187    int nbTexturesClipped = tileGrid->nbTextures(visibleContentArea, m_futureScale);
188
189    if (layer) {
190        // TODO: should handle multi-layer case better
191
192        // Set kFixedLayers level
193        if (layer->isPositionFixed())
194            result->fixed += nbTexturesClipped;
195
196        // Set kScrollableAndFixedLayers level
197        if (layer->contentIsScrollable()
198            || layer->isPositionFixed())
199            result->scrollable += nbTexturesClipped;
200    }
201
202    // Set kClippedTextures level
203    result->clipped += nbTexturesClipped;
204
205    // Set kAllTextures level
206    if (layer && layer->contentIsScrollable())
207        result->full += nbTexturesClipped;
208    else
209        result->full += nbTexturesUnclipped;
210}
211
212void SurfaceBacking::swapTileGrids()
213{
214    TileGrid* temp = m_frontTileGrid;
215    m_frontTileGrid = m_backTileGrid;
216    m_backTileGrid = temp;
217}
218
219} // namespace WebCore
220