root/cc/layers/tiled_layer_impl.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Create
  2. resource_id
  3. set_resource_id
  4. contents_swizzled
  5. set_contents_swizzled
  6. contents_swizzled_
  7. skips_draw_
  8. ContentsResourceId
  9. HasTileAt
  10. HasResourceIdForTileAt
  11. TileAt
  12. CreateTile
  13. GetDebugBorderProperties
  14. CreateLayerImpl
  15. AsValueInto
  16. GPUMemoryUsageInBytes
  17. PushPropertiesTo
  18. WillDraw
  19. AppendQuads
  20. SetTilingData
  21. PushTileProperties
  22. PushInvalidTile
  23. VisibleContentOpaqueRegion
  24. ReleaseResources
  25. LayerTypeAsString

// 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/layers/tiled_layer_impl.h"

#include "base/basictypes.h"
#include "base/strings/stringprintf.h"
#include "cc/base/math_util.h"
#include "cc/debug/debug_colors.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/quad_sink.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/layer_tiling_data.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/quad_f.h"

namespace cc {

class DrawableTile : public LayerTilingData::Tile {
 public:
  static scoped_ptr<DrawableTile> Create() {
    return make_scoped_ptr(new DrawableTile());
  }

  ResourceProvider::ResourceId resource_id() const { return resource_id_; }
  void set_resource_id(ResourceProvider::ResourceId resource_id) {
    resource_id_ = resource_id;
  }
  bool contents_swizzled() { return contents_swizzled_; }
  void set_contents_swizzled(bool contents_swizzled) {
    contents_swizzled_ = contents_swizzled;
  }

 private:
  DrawableTile() : resource_id_(0), contents_swizzled_(false) {}

  ResourceProvider::ResourceId resource_id_;
  bool contents_swizzled_;

  DISALLOW_COPY_AND_ASSIGN(DrawableTile);
};

TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
    : LayerImpl(tree_impl, id), skips_draw_(true) {}

TiledLayerImpl::~TiledLayerImpl() {
}

ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
  // This function is only valid for single texture layers, e.g. masks.
  DCHECK(tiler_);
  // It's possible the mask layer is created but has no size or otherwise
  // can't draw.
  if (tiler_->num_tiles_x() == 0 || tiler_->num_tiles_y() == 0)
    return 0;

  // Any other number of tiles other than 0 or 1 is incorrect for masks.
  DCHECK_EQ(tiler_->num_tiles_x(), 1);
  DCHECK_EQ(tiler_->num_tiles_y(), 1);

  DrawableTile* tile = TileAt(0, 0);
  ResourceProvider::ResourceId resource_id = tile ? tile->resource_id() : 0;
  return resource_id;
}

bool TiledLayerImpl::HasTileAt(int i, int j) const {
  return !!tiler_->TileAt(i, j);
}

bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
}

DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
}

DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
  scoped_ptr<DrawableTile> tile(DrawableTile::Create());
  DrawableTile* added_tile = tile.get();
  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);

  return added_tile;
}

void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
                                              float* width) const {
  *color = DebugColors::TiledContentLayerBorderColor();
  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}

scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
    LayerTreeImpl* tree_impl) {
  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}

void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
  LayerImpl::AsValueInto(state);
  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
}

size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
  size_t amount = 0;
  const size_t kMemoryUsagePerTileInBytes =
      4 * tiler_->tile_size().width() * tiler_->tile_size().height();
  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    if (!tile || !tile->resource_id())
      continue;
    amount += kMemoryUsagePerTileInBytes;
  }
  return amount;
}

void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
  LayerImpl::PushPropertiesTo(layer);

  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);

  tiled_layer->set_skips_draw(skips_draw_);
  tiled_layer->SetTilingData(*tiler_);

  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    int i = iter->first.first;
    int j = iter->first.second;
    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);

    tiled_layer->PushTileProperties(i,
                                    j,
                                    tile->resource_id(),
                                    tile->opaque_rect(),
                                    tile->contents_swizzled());
  }
}

bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
                              ResourceProvider* resource_provider) {
  if (!tiler_ || tiler_->has_empty_bounds() ||
      visible_content_rect().IsEmpty() ||
      draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
    return false;
  return LayerImpl::WillDraw(draw_mode, resource_provider);
}

void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
                                 AppendQuadsData* append_quads_data) {
  DCHECK(tiler_);
  DCHECK(!tiler_->has_empty_bounds());
  DCHECK(!visible_content_rect().IsEmpty());

  gfx::Rect content_rect = visible_content_rect();
  SharedQuadState* shared_quad_state =
      quad_sink->UseSharedQuadState(CreateSharedQuadState());
  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);

  int left, top, right, bottom;
  tiler_->ContentRectToTileIndices(content_rect, &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 tile_rect = tiler_->tile_bounds(i, j);
        gfx::Rect visible_tile_rect = tile_rect;
        SkColor border_color;
        float border_width;

        if (skips_draw_ || !tile || !tile->resource_id()) {
          border_color = DebugColors::MissingTileBorderColor();
          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
        } else {
          border_color = DebugColors::HighResTileBorderColor();
          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
        }
        scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
            DebugBorderDrawQuad::Create();
        debug_border_quad->SetNew(shared_quad_state,
                                  tile_rect,
                                  visible_tile_rect,
                                  border_color,
                                  border_width);
        quad_sink->MaybeAppend(debug_border_quad.PassAs<DrawQuad>());
      }
    }
  }

  if (skips_draw_)
    return;

  for (int j = top; j <= bottom; ++j) {
    for (int i = left; i <= right; ++i) {
      DrawableTile* tile = TileAt(i, j);
      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
      gfx::Rect display_rect = tile_rect;
      tile_rect.Intersect(content_rect);
      gfx::Rect visible_tile_rect = tile_rect;

      // Skip empty tiles.
      if (tile_rect.IsEmpty())
        continue;

      if (!tile || !tile->resource_id()) {
        SkColor checker_color;
        if (ShowDebugBorders()) {
          checker_color =
              tile ? DebugColors::InvalidatedTileCheckerboardColor()
                   : DebugColors::EvictedTileCheckerboardColor();
        } else {
          checker_color = DebugColors::DefaultCheckerboardColor();
        }

        scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
            CheckerboardDrawQuad::Create();
        checkerboard_quad->SetNew(
            shared_quad_state, tile_rect, visible_tile_rect, checker_color);
        if (quad_sink->MaybeAppend(checkerboard_quad.PassAs<DrawQuad>()))
          append_quads_data->num_missing_tiles++;

        continue;
      }

      gfx::Rect tile_opaque_rect =
          contents_opaque() ? tile_rect : gfx::IntersectRects(
                                              tile->opaque_rect(), tile_rect);

      // Keep track of how the top left has moved, so the texture can be
      // offset the same amount.
      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
      gfx::Vector2d texture_offset =
          tiler_->texture_offset(i, j) + display_offset;
      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;

      float tile_width = static_cast<float>(tiler_->tile_size().width());
      float tile_height = static_cast<float>(tiler_->tile_size().height());
      gfx::Size texture_size(tile_width, tile_height);

      scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
      quad->SetNew(shared_quad_state,
                   tile_rect,
                   tile_opaque_rect,
                   visible_tile_rect,
                   tile->resource_id(),
                   tex_coord_rect,
                   texture_size,
                   tile->contents_swizzled());
      quad_sink->MaybeAppend(quad.PassAs<DrawQuad>());
    }
  }
}

void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
  if (tiler_) {
    tiler_->reset();
  } else {
    tiler_ = LayerTilingData::Create(tiler.tile_size(),
                                     tiler.has_border_texels()
                                         ? LayerTilingData::HAS_BORDER_TEXELS
                                         : LayerTilingData::NO_BORDER_TEXELS);
  }
  *tiler_ = tiler;
}

void TiledLayerImpl::PushTileProperties(
    int i,
    int j,
    ResourceProvider::ResourceId resource_id,
    const gfx::Rect& opaque_rect,
    bool contents_swizzled) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(resource_id);
  tile->set_opaque_rect(opaque_rect);
  tile->set_contents_swizzled(contents_swizzled);
}

void TiledLayerImpl::PushInvalidTile(int i, int j) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(0);
  tile->set_opaque_rect(gfx::Rect());
  tile->set_contents_swizzled(false);
}

Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
  if (skips_draw_)
    return Region();
  if (contents_opaque())
    return visible_content_rect();
  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
}

void TiledLayerImpl::ReleaseResources() {
  tiler_->reset();
}

const char* TiledLayerImpl::LayerTypeAsString() const {
  return "cc::TiledLayerImpl";
}

}  // namespace cc

/* [<][>][^][v][top][bottom][index][help] */