Surface.cpp revision 893264ea664be9af3ac64e24116045b51df6f031
1/* 2 * Copyright 2012, 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 "Surface" 27#define LOG_NDEBUG 1 28 29#include "config.h" 30#include "Surface.h" 31 32#include "AndroidLog.h" 33#include "BaseLayerAndroid.h" 34#include "ClassTracker.h" 35#include "LayerAndroid.h" 36#include "GLWebViewState.h" 37#include "SkCanvas.h" 38#include "SurfaceBacking.h" 39#include "TilesManager.h" 40 41// Surfaces with an area larger than 2048*2048 should never be unclipped 42#define MAX_UNCLIPPED_AREA 4194304 43 44namespace WebCore { 45 46Surface::Surface() 47 : m_surfaceBacking(0) 48 , m_needsTexture(false) 49 , m_hasText(false) 50{ 51#ifdef DEBUG_COUNT 52 ClassTracker::instance()->increment("Surface"); 53#endif 54} 55 56Surface::~Surface() 57{ 58 for (unsigned int i = 0; i < m_layers.size(); i++) 59 SkSafeUnref(m_layers[i]); 60 if (m_surfaceBacking) 61 SkSafeUnref(m_surfaceBacking); 62#ifdef DEBUG_COUNT 63 ClassTracker::instance()->decrement("Surface"); 64#endif 65} 66 67bool Surface::tryUpdateSurface(Surface* oldSurface) 68{ 69 if (!needsTexture() || !oldSurface->needsTexture()) 70 return false; 71 72 // merge surfaces based on first layer ID 73 if (getFirstLayer()->uniqueId() != oldSurface->getFirstLayer()->uniqueId()) 74 return false; 75 76 m_surfaceBacking = oldSurface->m_surfaceBacking; 77 SkSafeRef(m_surfaceBacking); 78 79 ALOGV("%p taking old SurfBack %p from surface %p, nt %d", 80 this, m_surfaceBacking, oldSurface, oldSurface->needsTexture()); 81 82 if (!m_surfaceBacking) { 83 // no SurfBack to inval, so don't worry about it. 84 return true; 85 } 86 87 if (singleLayer() && oldSurface->singleLayer()) { 88 // both are single matching layers, simply apply inval 89 SkRegion* layerInval = getFirstLayer()->getInvalRegion(); 90 m_surfaceBacking->markAsDirty(*layerInval); 91 } else { 92 SkRegion invalRegion; 93 bool fullInval = m_layers.size() != oldSurface->m_layers.size(); 94 if (!fullInval) { 95 for (unsigned int i = 0; i < m_layers.size(); i++) { 96 if (m_layers[i]->uniqueId() != oldSurface->m_layers[i]->uniqueId()) { 97 // layer list has changed, fully invalidate 98 // TODO: partially invalidate based on layer size/position 99 fullInval = true; 100 break; 101 } else if (!m_layers[i]->getInvalRegion()->isEmpty()) { 102 // merge layer inval - translate the layer's inval region into surface coordinates 103 SkPoint pos = m_layers[i]->getPosition(); 104 m_layers[i]->getInvalRegion()->translate(pos.fX, pos.fY); 105 invalRegion.op(*(m_layers[i]->getInvalRegion()), SkRegion::kUnion_Op); 106 break; 107 } 108 } 109 } 110 111 if (fullInval) 112 invalRegion.setRect(-1e8, -1e8, 2e8, 2e8); 113 114 m_surfaceBacking->markAsDirty(invalRegion); 115 } 116 return true; 117} 118 119void Surface::addLayer(LayerAndroid* layer, const TransformationMatrix& transform) 120{ 121 m_layers.append(layer); 122 SkSafeRef(layer); 123 124 m_needsTexture |= layer->needsTexture(); 125 m_hasText |= layer->hasText(); 126 127 // calculate area size for comparison later 128 IntRect rect = layer->unclippedArea(); 129 SkPoint pos = layer->getPosition(); 130 rect.setLocation(IntPoint(pos.fX, pos.fY)); 131 132 if (layer->needsTexture()) { 133 if (m_unclippedArea.isEmpty()) { 134 m_drawTransform = transform; 135 m_drawTransform.translate3d(-pos.fX, -pos.fY, 0); 136 m_unclippedArea = rect; 137 } else 138 m_unclippedArea.unite(rect); 139 ALOGV("Surf %p adding LA %p, size %d, %d %dx%d, now Surf size %d,%d %dx%d", 140 this, layer, rect.x(), rect.y(), rect.width(), rect.height(), 141 m_unclippedArea.x(), m_unclippedArea.y(), 142 m_unclippedArea.width(), m_unclippedArea.height()); 143 } 144 145 if (isBase()) 146 m_background = static_cast<BaseLayerAndroid*>(layer)->getBackgroundColor(); 147} 148 149IntRect Surface::visibleArea() 150{ 151 if (singleLayer()) 152 return getFirstLayer()->visibleArea(); 153 154 IntRect rect = m_unclippedArea; 155 156 // clip with the viewport in documents coordinate 157 IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); 158 rect.intersect(documentViewport); 159 160 // TODO: handle recursive layer clip 161 162 return rect; 163} 164 165IntRect Surface::unclippedArea() 166{ 167 if (singleLayer()) 168 return getFirstLayer()->unclippedArea(); 169 return m_unclippedArea; 170} 171 172bool Surface::useAggressiveRendering() 173{ 174 // When the background is semi-opaque, 0 < alpha < 255, we had to turn off 175 // low res to avoid artifacts from double drawing. 176 // TODO: avoid double drawing for low res tiles. 177 return isBase() 178 && (!m_background.alpha() 179 || !m_background.hasAlpha()); 180} 181 182void Surface::prepareGL(bool layerTilesDisabled) 183{ 184 bool tilesDisabled = layerTilesDisabled && !isBase(); 185 if (!m_surfaceBacking) { 186 ALOGV("prepareGL on Surf %p, no SurfBack, needsTexture? %d", 187 this, m_surfaceBacking, needsTexture()); 188 189 if (!needsTexture()) 190 return; 191 192 m_surfaceBacking = new SurfaceBacking(isBase()); 193 } 194 195 if (tilesDisabled) { 196 m_surfaceBacking->discardTextures(); 197 } else { 198 bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors 199 IntRect prepareArea = computePrepareArea(); 200 IntRect fullArea = unclippedArea(); 201 202 ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers", 203 this, m_surfaceBacking, m_layers.size()); 204 205 m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, 206 prepareArea, fullArea, 207 this, useAggressiveRendering()); 208 } 209} 210 211bool Surface::drawGL(bool layerTilesDisabled) 212{ 213 bool tilesDisabled = layerTilesDisabled && !isBase(); 214 if (!getFirstLayer()->visible()) 215 return false; 216 217 if (!isBase()) { 218 // TODO: why are clipping regions wrong for base layer? 219 FloatRect drawClip = getFirstLayer()->drawClip(); 220 FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip); 221 TilesManager::instance()->shader()->clip(clippingRect); 222 } 223 224 bool askRedraw = false; 225 if (m_surfaceBacking && !tilesDisabled) { 226 ALOGV("drawGL on Surf %p with SurfBack %p", this, m_surfaceBacking); 227 228 // TODO: why this visibleArea is different from visibleRect at zooming for base? 229 IntRect drawArea = visibleArea(); 230 m_surfaceBacking->drawGL(drawArea, opacity(), drawTransform(), 231 useAggressiveRendering(), background()); 232 } 233 234 // draw member layers (draws image textures, glextras) 235 for (unsigned int i = 0; i < m_layers.size(); i++) 236 askRedraw |= m_layers[i]->drawGL(tilesDisabled); 237 238 return askRedraw; 239} 240 241void Surface::swapTiles() 242{ 243 if (!m_surfaceBacking) 244 return; 245 246 m_surfaceBacking->swapTiles(); 247} 248 249bool Surface::isReady() 250{ 251 if (!m_surfaceBacking) 252 return true; 253 254 return m_surfaceBacking->isReady(); 255} 256 257bool Surface::isMissingContent() 258{ 259 if (!m_surfaceBacking) 260 return true; 261 262 return m_surfaceBacking->isMissingContent(); 263} 264 265IntRect Surface::computePrepareArea() { 266 IntRect area; 267 268 if (!getFirstLayer()->contentIsScrollable() 269 && !isBase() 270 && getFirstLayer()->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { 271 272 area = unclippedArea(); 273 274 double total = ((double) area.width()) * ((double) area.height()); 275 if (total > MAX_UNCLIPPED_AREA) 276 area = visibleArea(); 277 } else { 278 area = visibleArea(); 279 } 280 281 return area; 282} 283 284void Surface::computeTexturesAmount(TexturesResult* result) 285{ 286 if (!m_surfaceBacking || isBase()) 287 return; 288 289 m_surfaceBacking->computeTexturesAmount(result, getFirstLayer()); 290} 291 292bool Surface::isBase() 293{ 294 // base layer surface 295 // - doesn't use layer tiles (disables blending, doesn't compute textures amount) 296 // - ignores clip rects 297 // - only prepares clippedArea 298 return getFirstLayer()->subclassType() == LayerAndroid::BaseLayer; 299} 300 301bool Surface::paint(SkCanvas* canvas) 302{ 303 if (singleLayer()) { 304 getFirstLayer()->contentDraw(canvas, Layer::UnmergedLayers); 305 306 // TODO: double buffer by disabling SurfaceCollection swaps and position 307 // updates until painting complete 308 309 // In single surface mode, draw layer content onto the base layer 310 if (isBase() 311 && getFirstLayer()->countChildren() 312 && getFirstLayer()->state()->layersRenderingMode() > GLWebViewState::kClippedTextures) 313 getFirstLayer()->getChild(0)->drawCanvas(canvas, true, Layer::FlattenedLayers); 314 } else { 315 SkAutoCanvasRestore acr(canvas, true); 316 SkMatrix matrix; 317 GLUtils::toSkMatrix(matrix, m_drawTransform); 318 319 SkMatrix inverse; 320 inverse.reset(); 321 matrix.invert(&inverse); 322 323 SkMatrix canvasMatrix = canvas->getTotalMatrix(); 324 inverse.postConcat(canvasMatrix); 325 canvas->setMatrix(inverse); 326 327 for (unsigned int i=0; i<m_layers.size(); i++) 328 m_layers[i]->drawCanvas(canvas, false, Layer::MergedLayers); 329 } 330 return true; 331} 332 333float Surface::opacity() 334{ 335 if (singleLayer()) 336 return getFirstLayer()->drawOpacity(); 337 return 1.0; 338} 339 340Color* Surface::background() 341{ 342 if (!isBase() || !m_background.isValid()) 343 return 0; 344 return &m_background; 345} 346 347const TransformationMatrix* Surface::drawTransform() 348{ 349 // single layer surfaces query the layer's draw transform, while multi-layer 350 // surfaces copy the draw transform once, during initialization 351 // TODO: support fixed multi-layer surfaces by querying the changing drawTransform 352 if (singleLayer()) 353 return getFirstLayer()->drawTransform(); 354 355 return &m_drawTransform; 356} 357 358} // namespace WebCore 359