summaryrefslogtreecommitdiffstats
path: root/cc/picture_pile.cc
blob: 1db3f4bd1cac3e150fbb1197ecbfc5e2d4d0aa3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2012 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 <algorithm>

#include "cc/picture_pile.h"
#include "cc/picture_pile_impl.h"
#include "cc/region.h"

namespace {
// Maximum number of pictures that can overlap before we collapse them into
// a larger one.
const int kMaxOverlapping = 2;
// Maximum percentage area of the base picture another picture in the picture
// list can be.  If higher, we destroy the list and recreate from scratch.
const float kResetThreshold = 0.7f;
// Layout pixel buffer around the visible layer rect to record.  Any base
// picture that intersects the visible layer rect expanded by this distance
// will be recorded.
const int kPixelDistanceToRecord = 8000;
}

namespace cc {

PicturePile::PicturePile() {
}

PicturePile::~PicturePile() {
}

void PicturePile::Update(
    ContentLayerClient* painter,
    const Region& invalidation,
    gfx::Rect visible_layer_rect,
    RenderingStats* stats) {
  gfx::Rect interest_rect = visible_layer_rect;
  interest_rect.Inset(
      -kPixelDistanceToRecord,
      -kPixelDistanceToRecord,
      -kPixelDistanceToRecord,
      -kPixelDistanceToRecord);
  for (Region::Iterator i(invalidation); i.has_rect(); i.next()) {
    // Inflate all recordings from invalidations with a margin so that when
    // scaled down to at least min_contents_scale, any final pixel touched by an
    // invalidation can be fully rasterized by this picture.
    gfx::Rect inflated_invalidation = i.rect();
    inflated_invalidation.Inset(
        -buffer_pixels(),
        -buffer_pixels(),
        -buffer_pixels(),
        -buffer_pixels());
    // Split this inflated invalidation across tile boundaries and apply it
    // to all tiles that it touches.
    for (TilingData::Iterator iter(&tiling_, inflated_invalidation);
         iter; ++iter) {
      gfx::Rect tile =
          tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y());
      if (!tile.Intersects(interest_rect)) {
        // This invalidation touches a tile outside the interest rect, so
        // just remove the entire picture list.
        picture_list_map_.erase(iter.index());
        continue;
      }

      gfx::Rect tile_invalidation =
          gfx::IntersectRects(inflated_invalidation, tile);
      if (tile_invalidation.IsEmpty())
        continue;
      PictureListMap::iterator find = picture_list_map_.find(iter.index());
      if (find == picture_list_map_.end())
        continue;
      PictureList& pic_list = find->second;
      // Leave empty pic_lists empty in case there are multiple invalidations.
      if (!pic_list.empty())
        InvalidateRect(pic_list, tile_invalidation);
    }
  }

  // Walk through all pictures in the rect of interest and record.
  for (TilingData::Iterator iter(&tiling_, interest_rect); iter; ++iter) {
    // Create a picture in this list if it doesn't exist.
    PictureList& pic_list = picture_list_map_[iter.index()];
    if (pic_list.empty()) {
      gfx::Rect tile =
          tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y());
      scoped_refptr<Picture> base_picture = Picture::Create(tile);
      pic_list.push_back(base_picture);
    }

    for (PictureList::iterator pic = pic_list.begin();
         pic != pic_list.end(); ++pic) {
      if (!(*pic)->HasRecording())
        (*pic)->Record(painter, stats);
    }
  }

  UpdateRecordedRegion();
}

class FullyContainedPredicate {
public:
  FullyContainedPredicate(gfx::Rect rect) : layer_rect_(rect) { }
  bool operator()(const scoped_refptr<Picture>& picture) {
    return layer_rect_.Contains(picture->LayerRect());
  }
  gfx::Rect layer_rect_;
};

void PicturePile::InvalidateRect(
    PictureList& picture_list,
    gfx::Rect invalidation) {
  DCHECK(!picture_list.empty());

  std::vector<PictureList::iterator> overlaps;
  for (PictureList::iterator i = picture_list.begin();
       i != picture_list.end(); ++i) {
    if ((*i)->LayerRect().Contains(invalidation) && !(*i)->HasRecording())
      return;
    if ((*i)->LayerRect().Intersects(invalidation) && i != picture_list.begin())
      overlaps.push_back(i);
  }

  gfx::Rect picture_rect = invalidation;
  if (overlaps.size() >= kMaxOverlapping) {
    for (size_t j = 0; j < overlaps.size(); j++)
      picture_rect.Union((*overlaps[j])->LayerRect());
  }

  Picture* base_picture = picture_list.front();
  int max_pixels = kResetThreshold * base_picture->LayerRect().size().GetArea();
  if (picture_rect.size().GetArea() > max_pixels) {
    // This picture list will be entirely recreated, so clear it.
    picture_list.clear();
    return;
  }

  FullyContainedPredicate pred(picture_rect);
  picture_list.erase(std::remove_if(picture_list.begin(),
                                    picture_list.end(),
                                    pred),
                     picture_list.end());
  picture_list.push_back(Picture::Create(picture_rect));
}


void PicturePile::PushPropertiesTo(PicturePileImpl* other) {
  // TODO(enne): Don't clear clones or push anything if nothing has changed
  // on this layer this frame.
  PicturePileBase::PushPropertiesTo(other);
  other->clones_.clear();
}

}  // namespace cc