blob: f4636f26f4ee08a0fa3fb7d8ffad3ee0b27f8c1f [file] [log] [blame]
// 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;
namespace cc {
// Non-debug checkerboards are grey.
const SkColor kTileCheckerboardColor = SkColorSetRGB(241, 241, 241);
class DrawableTile : public LayerTilingData::Tile {
public:
static scoped_ptr<DrawableTile> 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<DrawableTile*>(m_tiler->tileAt(i, j));
}
DrawableTile* TiledLayerImpl::createTile(int i, int j)
{
scoped_ptr<DrawableTile> tile(DrawableTile::create());
DrawableTile* addedTile = tile.get();
m_tiler->addTile(tile.PassAs<LayerTilingData::Tile>(), 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<DebugBorderDrawQuad> debugBorderQuad = DebugBorderDrawQuad::Create();
debugBorderQuad->SetNew(sharedQuadState, tileRect, borderColor, borderWidth);
quadSink.append(debugBorderQuad.PassAs<DrawQuad>(), 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<CheckerboardDrawQuad> checkerboardQuad = CheckerboardDrawQuad::Create();
checkerboardQuad->SetNew(sharedQuadState, tileRect, checkerColor);
appendQuadsData.hadMissingTiles |= quadSink.append(checkerboardQuad.PassAs<DrawQuad>(), appendQuadsData);
} else {
scoped_ptr<SolidColorDrawQuad> solidColorQuad = SolidColorDrawQuad::Create();
solidColorQuad->SetNew(sharedQuadState, tileRect, backgroundColor());
appendQuadsData.hadMissingTiles |= quadSink.append(solidColorQuad.PassAs<DrawQuad>(), 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<float>(m_tiler->tileSize().width());
float tileHeight = static_cast<float>(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<TileDrawQuad> quad = TileDrawQuad::Create();
quad->SetNew(sharedQuadState, tileRect, tileOpaqueRect, tile->resourceId(), texCoordRect, textureSize, tile->contentsSwizzled(), leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA);
quadSink.append(quad.PassAs<DrawQuad>(), 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