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 "CanvasLayer" 27#define LOG_NDEBUG 1 28 29#include "config.h" 30#include "CanvasLayer.h" 31 32#if USE(ACCELERATED_COMPOSITING) 33 34#include "AndroidLog.h" 35#include "CanvasTexture.h" 36#include "DrawQuadData.h" 37#include "Image.h" 38#include "ImageBuffer.h" 39#include "RenderLayerCompositor.h" 40#include "SkBitmap.h" 41#include "SkBitmapRef.h" 42#include "SkCanvas.h" 43#include "TilesManager.h" 44 45namespace WebCore { 46 47CanvasLayer::CanvasLayer(RenderLayer* owner, HTMLCanvasElement* canvas) 48 : LayerAndroid(owner) 49 , m_canvas(canvas) 50 , m_dirtyCanvas() 51 , m_bitmap(0) 52{ 53 init(); 54 m_canvas->addObserver(this); 55 // Make sure we initialize in case the canvas has already been laid out 56 canvasResized(m_canvas); 57} 58 59CanvasLayer::CanvasLayer(const CanvasLayer& layer) 60 : LayerAndroid(layer) 61 , m_canvas(0) 62 , m_bitmap(0) 63{ 64 init(); 65 if (!layer.m_canvas) { 66 // The canvas has already been destroyed - this shouldn't happen 67 ALOGW("Creating a CanvasLayer for a destroyed canvas!"); 68 m_visibleContentRect = IntRect(); 69 m_offsetFromRenderer = IntSize(); 70 m_texture->setHwAccelerated(false); 71 return; 72 } 73 // We are making a copy for the UI, sync the interesting bits 74 m_visibleContentRect = layer.visibleContentRect(); 75 m_offsetFromRenderer = layer.offsetFromRenderer(); 76 bool previousState = m_texture->hasValidTexture(); 77 if (!previousState && layer.m_dirtyCanvas.isEmpty()) { 78 // We were previously in software and don't have anything new to draw, 79 // so stay in software 80 m_bitmap = layer.bitmap(); 81 SkSafeRef(m_bitmap); 82 } else { 83 // Attempt to upload to a surface texture 84 if (!m_texture->uploadImageBuffer(layer.m_canvas->buffer())) { 85 // Blargh, no surface texture or ImageBuffer - fall back to software 86 m_bitmap = layer.bitmap(); 87 SkSafeRef(m_bitmap); 88 // Merge the canvas invals with the layer's invals to repaint the needed 89 // tiles. 90 SkRegion::Iterator iter(layer.m_dirtyCanvas); 91 const IntPoint& offset = m_visibleContentRect.location(); 92 for (; !iter.done(); iter.next()) { 93 SkIRect diff = iter.rect(); 94 diff.fLeft += offset.x(); 95 diff.fRight += offset.x(); 96 diff.fTop += offset.y(); 97 diff.fBottom += offset.y(); 98 m_dirtyRegion.op(diff, SkRegion::kUnion_Op); 99 } 100 } 101 if (previousState != m_texture->hasValidTexture()) { 102 // Need to do a full inval of the canvas content as we are mode switching 103 m_dirtyRegion.op(m_visibleContentRect.x(), m_visibleContentRect.y(), 104 m_visibleContentRect.maxX(), m_visibleContentRect.maxY(), SkRegion::kUnion_Op); 105 } 106 } 107} 108 109CanvasLayer::~CanvasLayer() 110{ 111 if (m_canvas) 112 m_canvas->removeObserver(this); 113 SkSafeUnref(m_bitmap); 114} 115 116void CanvasLayer::init() 117{ 118 m_texture = CanvasTexture::getCanvasTexture(this); 119} 120 121void CanvasLayer::canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect) 122{ 123 if (!m_texture->hasValidTexture()) { 124 // We only need to track invals if we aren't using a SurfaceTexture. 125 // If we drop out of hwa, we will do a full inval anyway 126 SkIRect irect = SkIRect::MakeXYWH(changedRect.x(), changedRect.y(), 127 changedRect.width(), changedRect.height()); 128 m_dirtyCanvas.op(irect, SkRegion::kUnion_Op); 129 } 130 owningLayer()->compositor()->scheduleLayerFlush(); 131} 132 133void CanvasLayer::canvasResized(HTMLCanvasElement*) 134{ 135 const IntSize& size = m_canvas->size(); 136 m_dirtyCanvas.setRect(0, 0, size.width(), size.height()); 137 // If we are smaller than one tile, don't bother using a surface texture 138 if (size.width() <= TilesManager::tileWidth() 139 && size.height() <= TilesManager::tileHeight()) 140 m_texture->setSize(IntSize()); 141 else 142 m_texture->setSize(size); 143} 144 145void CanvasLayer::canvasDestroyed(HTMLCanvasElement*) 146{ 147 m_canvas = 0; 148} 149 150void CanvasLayer::clearDirtyRegion() 151{ 152 LayerAndroid::clearDirtyRegion(); 153 m_dirtyCanvas.setEmpty(); 154 if (m_canvas) 155 m_canvas->clearDirtyRect(); 156} 157 158SkBitmapRef* CanvasLayer::bitmap() const 159{ 160 if (!m_canvas || !m_canvas->buffer()) 161 return 0; 162 return m_canvas->copiedImage()->nativeImageForCurrentFrame(); 163} 164 165IntRect CanvasLayer::visibleContentRect() const 166{ 167 if (!m_canvas 168 || !m_canvas->renderer() 169 || !m_canvas->renderer()->style() 170 || !m_canvas->inDocument() 171 || m_canvas->renderer()->style()->visibility() != VISIBLE) 172 return IntRect(); 173 return m_canvas->renderBox()->contentBoxRect(); 174} 175 176IntSize CanvasLayer::offsetFromRenderer() const 177{ 178 return m_canvas->renderBox()->layer()->backing()->graphicsLayer()->offsetFromRenderer(); 179} 180 181bool CanvasLayer::needsTexture() 182{ 183 return (m_bitmap && !masksToBounds()) || LayerAndroid::needsTexture(); 184} 185 186void CanvasLayer::contentDraw(SkCanvas* canvas, PaintStyle style) 187{ 188 LayerAndroid::contentDraw(canvas, style); 189 if (!m_bitmap || masksToBounds()) 190 return; 191 SkBitmap& bitmap = m_bitmap->bitmap(); 192 SkRect dst = SkRect::MakeXYWH(m_visibleContentRect.x() - m_offsetFromRenderer.width(), 193 m_visibleContentRect.y() - m_offsetFromRenderer.height(), 194 m_visibleContentRect.width(), m_visibleContentRect.height()); 195 canvas->drawBitmapRect(bitmap, 0, dst, 0); 196} 197 198bool CanvasLayer::drawGL(bool layerTilesDisabled) 199{ 200 bool ret = LayerAndroid::drawGL(layerTilesDisabled); 201 m_texture->requireTexture(); 202 if (!m_bitmap && m_texture->updateTexImage()) { 203 SkRect rect = SkRect::MakeXYWH(m_visibleContentRect.x() - m_offsetFromRenderer.width(), 204 m_visibleContentRect.y() - m_offsetFromRenderer.height(), 205 m_visibleContentRect.width(), m_visibleContentRect.height()); 206 TextureQuadData data(m_texture->texture(), GL_TEXTURE_EXTERNAL_OES, 207 GL_LINEAR, LayerQuad, &m_drawTransform, &rect); 208 TilesManager::instance()->shader()->drawQuad(&data); 209 } 210 return ret; 211} 212 213LayerAndroid::InvalidateFlags CanvasLayer::onSetHwAccelerated(bool hwAccelerated) 214{ 215 if (m_texture->setHwAccelerated(hwAccelerated)) 216 return LayerAndroid::InvalidateLayers; 217 return LayerAndroid::InvalidateNone; 218} 219 220} // namespace WebCore 221 222#endif // USE(ACCELERATED_COMPOSITING) 223