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 "PaintedSurface.h"
28
29
30#include "LayerAndroid.h"
31#include "TiledTexture.h"
32#include "TilesManager.h"
33#include "SkCanvas.h"
34#include "SkPicture.h"
35
36#include <cutils/log.h>
37#include <wtf/CurrentTime.h>
38#include <wtf/text/CString.h>
39
40#undef XLOGC
41#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "PaintedSurface", __VA_ARGS__)
42
43#ifdef DEBUG
44
45#undef XLOG
46#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "PaintedSurface", __VA_ARGS__)
47
48#else
49
50#undef XLOG
51#define XLOG(...)
52
53#endif // DEBUG
54
55// Layers with an area larger than 2048*2048 should never be unclipped
56#define MAX_UNCLIPPED_AREA 4194304
57
58namespace WebCore {
59
60PaintedSurface::PaintedSurface()
61    : m_drawingLayer(0)
62    , m_paintingLayer(0)
63    , m_tiledTexture(0)
64    , m_scale(0)
65    , m_pictureUsed(0)
66{
67    TilesManager::instance()->addPaintedSurface(this);
68#ifdef DEBUG_COUNT
69    ClassTracker::instance()->increment("PaintedSurface");
70#endif
71    m_tiledTexture = new DualTiledTexture(this);
72}
73
74PaintedSurface::~PaintedSurface()
75{
76#ifdef DEBUG_COUNT
77    ClassTracker::instance()->decrement("PaintedSurface");
78#endif
79    delete m_tiledTexture;
80}
81
82void PaintedSurface::prepare(GLWebViewState* state)
83{
84    XLOG("PS %p has PL %p, DL %p", this, m_paintingLayer, m_drawingLayer);
85    LayerAndroid* paintingLayer = m_paintingLayer;
86    if (!paintingLayer)
87        paintingLayer = m_drawingLayer;
88
89    if (!paintingLayer)
90        return;
91
92    bool startFastSwap = false;
93    if (state->isScrolling()) {
94        // when scrolling, block updates and swap tiles as soon as they're ready
95        startFastSwap = true;
96    }
97
98    XLOG("prepare layer %d %x at scale %.2f",
99         paintingLayer->uniqueId(), paintingLayer,
100         paintingLayer->getScale());
101
102    IntRect visibleArea = computeVisibleArea(paintingLayer);
103
104    m_scale = state->scale();
105
106    // If we do not have text, we may as well limit ourselves to
107    // a scale factor of one... this saves up textures.
108    if (m_scale > 1 && !paintingLayer->hasText())
109        m_scale = 1;
110
111    m_tiledTexture->prepare(state, m_scale, m_pictureUsed != paintingLayer->pictureUsed(),
112                            startFastSwap, visibleArea);
113}
114
115bool PaintedSurface::draw()
116{
117    if (!m_drawingLayer || !m_drawingLayer->needsTexture())
118        return false;
119
120    bool askRedraw = false;
121    if (m_tiledTexture)
122        askRedraw = m_tiledTexture->draw();
123
124    return askRedraw;
125}
126
127void PaintedSurface::setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea)
128{
129    m_paintingLayer = layer;
130    if (m_tiledTexture)
131        m_tiledTexture->update(dirtyArea, layer->picture());
132}
133
134bool PaintedSurface::isReady()
135{
136    if (m_tiledTexture)
137        return m_tiledTexture->isReady();
138    return false;
139}
140
141void PaintedSurface::swapTiles()
142{
143    if (m_tiledTexture)
144        m_tiledTexture->swapTiles();
145}
146
147float PaintedSurface::opacity() {
148    if (m_drawingLayer)
149        return m_drawingLayer->drawOpacity();
150    return 1.0;
151}
152
153const TransformationMatrix* PaintedSurface::transform() {
154    // used exclusively for drawing, so only use m_drawingLayer
155    if (!m_drawingLayer)
156        return 0;
157
158    return m_drawingLayer->drawTransform();
159}
160
161void PaintedSurface::computeTexturesAmount(TexturesResult* result)
162{
163    if (!m_tiledTexture)
164        return;
165
166    // for now, always done on drawinglayer
167    LayerAndroid* layer = m_drawingLayer;
168
169    if (!layer)
170        return;
171
172    IntRect unclippedArea = layer->unclippedArea();
173    IntRect clippedVisibleArea = layer->visibleArea();
174    // get two numbers here:
175    // - textures needed for a clipped area
176    // - textures needed for an un-clipped area
177    int nbTexturesUnclipped = m_tiledTexture->nbTextures(unclippedArea, m_scale);
178    int nbTexturesClipped = m_tiledTexture->nbTextures(clippedVisibleArea, m_scale);
179
180    // Set kFixedLayers level
181    if (layer->isFixed())
182        result->fixed += nbTexturesClipped;
183
184    // Set kScrollableAndFixedLayers level
185    if (layer->contentIsScrollable()
186        || layer->isFixed())
187        result->scrollable += nbTexturesClipped;
188
189    // Set kClippedTextures level
190    result->clipped += nbTexturesClipped;
191
192    // Set kAllTextures level
193    if (layer->contentIsScrollable())
194        result->full += nbTexturesClipped;
195    else
196        result->full += nbTexturesUnclipped;
197}
198
199IntRect PaintedSurface::computeVisibleArea(LayerAndroid* layer) {
200    IntRect area;
201    if (!layer)
202        return area;
203
204    if (!layer->contentIsScrollable()
205        && layer->state()->layersRenderingMode() == GLWebViewState::kAllTextures) {
206        area = layer->unclippedArea();
207        double total = ((double) area.width()) * ((double) area.height());
208        if (total > MAX_UNCLIPPED_AREA)
209            area = layer->visibleArea();
210    } else {
211        area = layer->visibleArea();
212    }
213
214    return area;
215}
216
217bool PaintedSurface::owns(BaseTileTexture* texture)
218{
219    if (m_tiledTexture)
220        return m_tiledTexture->owns(texture);
221    return false;
222}
223
224} // namespace WebCore
225