Home | History | Annotate | Download | only in resources
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/resources/picture_pile_base.h"
      6 
      7 #include <algorithm>
      8 #include <set>
      9 #include <vector>
     10 
     11 #include "base/debug/trace_event_argument.h"
     12 #include "base/logging.h"
     13 #include "base/values.h"
     14 #include "cc/base/math_util.h"
     15 #include "cc/debug/traced_value.h"
     16 #include "third_party/skia/include/core/SkColor.h"
     17 #include "ui/gfx/rect_conversions.h"
     18 
     19 namespace {
     20 // Dimensions of the tiles in this picture pile as well as the dimensions of
     21 // the base picture in each tile.
     22 const int kBasePictureSize = 512;
     23 const int kTileGridBorderPixels = 1;
     24 #ifdef NDEBUG
     25 const bool kDefaultClearCanvasSetting = false;
     26 #else
     27 const bool kDefaultClearCanvasSetting = true;
     28 #endif
     29 
     30 // Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
     31 // between 0 and 1 meaning invalidation frequency between 0% and 100% that
     32 // indicates when to stop invalidating offscreen regions.
     33 // kFrequentInvalidationDistanceThreshold defines what it means to be
     34 // "offscreen" in terms of distance to visible in css pixels.
     35 const float kInvalidationFrequencyThreshold = 0.75f;
     36 const int kFrequentInvalidationDistanceThreshold = 512;
     37 
     38 }  // namespace
     39 
     40 namespace cc {
     41 
     42 PicturePileBase::PicturePileBase()
     43     : min_contents_scale_(0),
     44       background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
     45       slow_down_raster_scale_factor_for_debug_(0),
     46       contents_opaque_(false),
     47       contents_fill_bounds_completely_(false),
     48       show_debug_picture_borders_(false),
     49       clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
     50       has_any_recordings_(false),
     51       has_text_(false),
     52       is_mask_(false),
     53       is_solid_color_(false),
     54       solid_color_(SK_ColorTRANSPARENT) {
     55   tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
     56   tile_grid_info_.fTileInterval.setEmpty();
     57   tile_grid_info_.fMargin.setEmpty();
     58   tile_grid_info_.fOffset.setZero();
     59 }
     60 
     61 PicturePileBase::PicturePileBase(const PicturePileBase* other)
     62     : picture_map_(other->picture_map_),
     63       tiling_(other->tiling_),
     64       recorded_viewport_(other->recorded_viewport_),
     65       min_contents_scale_(other->min_contents_scale_),
     66       tile_grid_info_(other->tile_grid_info_),
     67       background_color_(other->background_color_),
     68       slow_down_raster_scale_factor_for_debug_(
     69           other->slow_down_raster_scale_factor_for_debug_),
     70       contents_opaque_(other->contents_opaque_),
     71       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
     72       show_debug_picture_borders_(other->show_debug_picture_borders_),
     73       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
     74       has_any_recordings_(other->has_any_recordings_),
     75       has_text_(other->has_text_),
     76       is_mask_(other->is_mask_),
     77       is_solid_color_(other->is_solid_color_),
     78       solid_color_(other->solid_color_) {
     79 }
     80 
     81 PicturePileBase::~PicturePileBase() {
     82 }
     83 
     84 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
     85   DCHECK(min_contents_scale);
     86   if (min_contents_scale_ == min_contents_scale)
     87     return;
     88 
     89   // Picture contents are played back scaled. When the final contents scale is
     90   // less than 1 (i.e. low res), then multiple recorded pixels will be used
     91   // to raster one final pixel.  To avoid splitting a final pixel across
     92   // pictures (which would result in incorrect rasterization due to blending), a
     93   // buffer margin is added so that any picture can be snapped to integral
     94   // final pixels.
     95   //
     96   // For example, if a 1/4 contents scale is used, then that would be 3 buffer
     97   // pixels, since that's the minimum number of pixels to add so that resulting
     98   // content can be snapped to a four pixel aligned grid.
     99   int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
    100   buffer_pixels = std::max(0, buffer_pixels);
    101   SetBufferPixels(buffer_pixels);
    102   min_contents_scale_ = min_contents_scale;
    103 }
    104 
    105 // static
    106 void PicturePileBase::ComputeTileGridInfo(
    107     const gfx::Size& tile_grid_size,
    108     SkTileGridFactory::TileGridInfo* info) {
    109   DCHECK(info);
    110   info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
    111                           tile_grid_size.height() - 2 * kTileGridBorderPixels);
    112   DCHECK_GT(info->fTileInterval.width(), 0);
    113   DCHECK_GT(info->fTileInterval.height(), 0);
    114   info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
    115   // Offset the tile grid coordinate space to take into account the fact
    116   // that the top-most and left-most tiles do not have top and left borders
    117   // respectively.
    118   info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
    119 }
    120 
    121 void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
    122   ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
    123 }
    124 
    125 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
    126   if (new_buffer_pixels == buffer_pixels())
    127     return;
    128 
    129   Clear();
    130   tiling_.SetBorderTexels(new_buffer_pixels);
    131 }
    132 
    133 void PicturePileBase::Clear() {
    134   picture_map_.clear();
    135   recorded_viewport_ = gfx::Rect();
    136 }
    137 
    138 bool PicturePileBase::HasRecordingAt(int x, int y) {
    139   PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
    140   if (found == picture_map_.end())
    141     return false;
    142   return !!found->second.GetPicture();
    143 }
    144 
    145 bool PicturePileBase::CanRaster(float contents_scale,
    146                                 const gfx::Rect& content_rect) {
    147   if (tiling_.tiling_size().IsEmpty())
    148     return false;
    149   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
    150       content_rect, 1.f / contents_scale);
    151   layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
    152 
    153   // Common case inside of viewport to avoid the slower map lookups.
    154   if (recorded_viewport_.Contains(layer_rect)) {
    155     // Sanity check that there are no false positives in recorded_viewport_.
    156     DCHECK(CanRasterSlowTileCheck(layer_rect));
    157     return true;
    158   }
    159 
    160   return CanRasterSlowTileCheck(layer_rect);
    161 }
    162 
    163 bool PicturePileBase::CanRasterSlowTileCheck(
    164     const gfx::Rect& layer_rect) const {
    165   bool include_borders = false;
    166   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
    167        tile_iter;
    168        ++tile_iter) {
    169     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
    170     if (map_iter == picture_map_.end())
    171       return false;
    172     if (!map_iter->second.GetPicture())
    173       return false;
    174   }
    175   return true;
    176 }
    177 
    178 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const {
    179   gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
    180   return PadRect(tile);
    181 }
    182 
    183 gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const {
    184   gfx::Rect padded_rect = rect;
    185   padded_rect.Inset(
    186       -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
    187   return padded_rect;
    188 }
    189 
    190 void PicturePileBase::AsValueInto(base::debug::TracedValue* pictures) const {
    191   gfx::Rect tiling_rect(tiling_.tiling_size());
    192   std::set<const void*> appended_pictures;
    193   bool include_borders = true;
    194   for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
    195        tile_iter;
    196        ++tile_iter) {
    197     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
    198     if (map_iter == picture_map_.end())
    199       continue;
    200 
    201     const Picture* picture = map_iter->second.GetPicture();
    202     if (picture && (appended_pictures.count(picture) == 0)) {
    203       appended_pictures.insert(picture);
    204       TracedValue::AppendIDRef(picture, pictures);
    205     }
    206   }
    207 }
    208 
    209 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
    210 
    211 PicturePileBase::PictureInfo::~PictureInfo() {}
    212 
    213 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
    214     int frame_number) {
    215   DCHECK_GE(frame_number, last_frame_number_);
    216   if (frame_number == last_frame_number_)
    217     return;
    218 
    219   invalidation_history_ <<= (frame_number - last_frame_number_);
    220   last_frame_number_ = frame_number;
    221 }
    222 
    223 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
    224   AdvanceInvalidationHistory(frame_number);
    225   invalidation_history_.set(0);
    226 
    227   bool did_invalidate = !!picture_.get();
    228   picture_ = NULL;
    229   return did_invalidate;
    230 }
    231 
    232 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
    233                                                   int distance_to_visible) {
    234   AdvanceInvalidationHistory(frame_number);
    235 
    236   // We only need recording if we don't have a picture. Furthermore, we only
    237   // need a recording if we're within frequent invalidation distance threshold
    238   // or the invalidation is not frequent enough (below invalidation frequency
    239   // threshold).
    240   return !picture_.get() &&
    241          ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
    242           (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
    243 }
    244 
    245 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
    246   picture_ = picture;
    247 }
    248 
    249 const Picture* PicturePileBase::PictureInfo::GetPicture() const {
    250   return picture_.get();
    251 }
    252 
    253 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
    254   return invalidation_history_.count() /
    255          static_cast<float>(INVALIDATION_FRAMES_TRACKED);
    256 }
    257 
    258 }  // namespace cc
    259