// Copyright 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/tiled_layer_impl.h" #include "base/basictypes.h" #include "base/stringprintf.h" #include "cc/append_quads_data.h" #include "cc/checkerboard_draw_quad.h" #include "cc/debug_border_draw_quad.h" #include "cc/debug_colors.h" #include "cc/layer_tiling_data.h" #include "cc/math_util.h" #include "cc/quad_sink.h" #include "cc/solid_color_draw_quad.h" #include "cc/tile_draw_quad.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/quad_f.h" using namespace std; using WebKit::WebTransformationMatrix; namespace cc { // Non-debug checkerboards are grey. const SkColor kTileCheckerboardColor = SkColorSetRGB(241, 241, 241); class DrawableTile : public LayerTilingData::Tile { public: static scoped_ptr create() { return make_scoped_ptr(new DrawableTile()); } ResourceProvider::ResourceId resourceId() const { return m_resourceId; } void setResourceId(ResourceProvider::ResourceId resourceId) { m_resourceId = resourceId; } bool contentsSwizzled() { return m_contentsSwizzled; } void setContentsSwizzled(bool contentsSwizzled) { m_contentsSwizzled = contentsSwizzled; } private: DrawableTile() : m_resourceId(0) , m_contentsSwizzled(false) { } ResourceProvider::ResourceId m_resourceId; bool m_contentsSwizzled; DISALLOW_COPY_AND_ASSIGN(DrawableTile); }; TiledLayerImpl::TiledLayerImpl(int id) : LayerImpl(id) , m_skipsDraw(true) { } TiledLayerImpl::~TiledLayerImpl() { } ResourceProvider::ResourceId TiledLayerImpl::contentsResourceId() const { // This function is only valid for single texture layers, e.g. masks. DCHECK(m_tiler); DCHECK(m_tiler->numTilesX() == 1); DCHECK(m_tiler->numTilesY() == 1); DrawableTile* tile = tileAt(0, 0); ResourceProvider::ResourceId resourceId = tile ? tile->resourceId() : 0; return resourceId; } void TiledLayerImpl::dumpLayerProperties(std::string* str, int indent) const { str->append(indentString(indent)); base::StringAppendF(str, "skipsDraw: %d\n", (!m_tiler || m_skipsDraw)); LayerImpl::dumpLayerProperties(str, indent); } bool TiledLayerImpl::hasTileAt(int i, int j) const { return m_tiler->tileAt(i, j); } bool TiledLayerImpl::hasResourceIdForTileAt(int i, int j) const { return hasTileAt(i, j) && tileAt(i, j)->resourceId(); } DrawableTile* TiledLayerImpl::tileAt(int i, int j) const { return static_cast(m_tiler->tileAt(i, j)); } DrawableTile* TiledLayerImpl::createTile(int i, int j) { scoped_ptr tile(DrawableTile::create()); DrawableTile* addedTile = tile.get(); m_tiler->addTile(tile.PassAs(), i, j); return addedTile; } void TiledLayerImpl::getDebugBorderProperties(SkColor* color, float* width) const { *color = DebugColors::TiledContentLayerBorderColor(); *width = DebugColors::TiledContentLayerBorderWidth(layerTreeHostImpl()); } void TiledLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData) { const gfx::Rect& contentRect = visibleContentRect(); if (!m_tiler || m_tiler->hasEmptyBounds() || contentRect.IsEmpty()) return; SharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState()); appendDebugBorderQuad(quadSink, sharedQuadState, appendQuadsData); int left, top, right, bottom; m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom); if (showDebugBorders()) { for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { DrawableTile* tile = tileAt(i, j); gfx::Rect tileRect = m_tiler->tileBounds(i, j); SkColor borderColor; float borderWidth; if (m_skipsDraw || !tile || !tile->resourceId()) { borderColor = DebugColors::MissingTileBorderColor(); borderWidth = DebugColors::MissingTileBorderWidth(layerTreeHostImpl()); } else { borderColor = DebugColors::TileBorderColor(); borderWidth = DebugColors::TileBorderWidth(layerTreeHostImpl()); } scoped_ptr debugBorderQuad = DebugBorderDrawQuad::Create(); debugBorderQuad->SetNew(sharedQuadState, tileRect, borderColor, borderWidth); quadSink.append(debugBorderQuad.PassAs(), appendQuadsData); } } } if (m_skipsDraw) return; for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { DrawableTile* tile = tileAt(i, j); gfx::Rect tileRect = m_tiler->tileBounds(i, j); gfx::Rect displayRect = tileRect; tileRect.Intersect(contentRect); // Skip empty tiles. if (tileRect.IsEmpty()) continue; if (!tile || !tile->resourceId()) { if (drawCheckerboardForMissingTiles()) { SkColor checkerColor; if (showDebugBorders()) checkerColor = tile ? DebugColors::InvalidatedTileCheckerboardColor() : DebugColors::EvictedTileCheckerboardColor(); else checkerColor = kTileCheckerboardColor; scoped_ptr checkerboardQuad = CheckerboardDrawQuad::Create(); checkerboardQuad->SetNew(sharedQuadState, tileRect, checkerColor); appendQuadsData.hadMissingTiles |= quadSink.append(checkerboardQuad.PassAs(), appendQuadsData); } else { scoped_ptr solidColorQuad = SolidColorDrawQuad::Create(); solidColorQuad->SetNew(sharedQuadState, tileRect, backgroundColor()); appendQuadsData.hadMissingTiles |= quadSink.append(solidColorQuad.PassAs(), appendQuadsData); } continue; } gfx::Rect tileOpaqueRect = contentsOpaque() ? tileRect : gfx::IntersectRects(tile->opaqueRect(), contentRect); // Keep track of how the top left has moved, so the texture can be // offset the same amount. gfx::Vector2d displayOffset = tileRect.origin() - displayRect.origin(); gfx::Vector2d textureOffset = m_tiler->textureOffset(i, j) + displayOffset; gfx::RectF texCoordRect = gfx::RectF(tileRect.size()) + textureOffset; float tileWidth = static_cast(m_tiler->tileSize().width()); float tileHeight = static_cast(m_tiler->tileSize().height()); gfx::Size textureSize(tileWidth, tileHeight); bool clipped = false; gfx::QuadF visibleContentInTargetQuad = MathUtil::mapQuad(drawTransform(), gfx::QuadF(visibleContentRect()), clipped); bool isAxisAlignedInTarget = !clipped && visibleContentInTargetQuad.IsRectilinear(); bool useAA = m_tiler->hasBorderTexels() && !isAxisAlignedInTarget; bool leftEdgeAA = !i && useAA; bool topEdgeAA = !j && useAA; bool rightEdgeAA = i == m_tiler->numTilesX() - 1 && useAA; bool bottomEdgeAA = j == m_tiler->numTilesY() - 1 && useAA; scoped_ptr quad = TileDrawQuad::Create(); quad->SetNew(sharedQuadState, tileRect, tileOpaqueRect, tile->resourceId(), texCoordRect, textureSize, tile->contentsSwizzled(), leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA); quadSink.append(quad.PassAs(), appendQuadsData); } } } void TiledLayerImpl::setTilingData(const LayerTilingData& tiler) { if (m_tiler) m_tiler->reset(); else m_tiler = LayerTilingData::create(tiler.tileSize(), tiler.hasBorderTexels() ? LayerTilingData::HasBorderTexels : LayerTilingData::NoBorderTexels); *m_tiler = tiler; } void TiledLayerImpl::pushTileProperties(int i, int j, ResourceProvider::ResourceId resourceId, const gfx::Rect& opaqueRect, bool contentsSwizzled) { DrawableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); tile->setResourceId(resourceId); tile->setOpaqueRect(opaqueRect); tile->setContentsSwizzled(contentsSwizzled); } void TiledLayerImpl::pushInvalidTile(int i, int j) { DrawableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); tile->setResourceId(0); tile->setOpaqueRect(gfx::Rect()); tile->setContentsSwizzled(false); } Region TiledLayerImpl::visibleContentOpaqueRegion() const { if (m_skipsDraw) return Region(); if (contentsOpaque()) return visibleContentRect(); return m_tiler->opaqueRegionInContentRect(visibleContentRect()); } void TiledLayerImpl::didLoseContext() { m_tiler->reset(); } const char* TiledLayerImpl::layerTypeAsString() const { return "ContentLayer"; } } // namespace cc