picture_layer_tiling_set.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright 2012 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_layer_tiling_set.h"
6
7#include <limits>
8
9namespace cc {
10
11namespace {
12
13class LargestToSmallestScaleFunctor {
14 public:
15  bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) {
16    return left->contents_scale() > right->contents_scale();
17  }
18};
19
20}  // namespace
21
22
23PictureLayerTilingSet::PictureLayerTilingSet(
24    PictureLayerTilingClient* client,
25    gfx::Size layer_bounds)
26    : client_(client),
27      layer_bounds_(layer_bounds) {
28}
29
30PictureLayerTilingSet::~PictureLayerTilingSet() {
31}
32
33void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) {
34  client_ = client;
35  for (size_t i = 0; i < tilings_.size(); ++i)
36    tilings_[i]->SetClient(client_);
37}
38
39void PictureLayerTilingSet::SyncTilings(
40    const PictureLayerTilingSet& other,
41    gfx::Size new_layer_bounds,
42    const Region& layer_invalidation,
43    float minimum_contents_scale) {
44  if (new_layer_bounds.IsEmpty()) {
45    RemoveAllTilings();
46    layer_bounds_ = new_layer_bounds;
47    return;
48  }
49
50  tilings_.reserve(other.tilings_.size());
51
52  // Remove any tilings that aren't in |other| or don't meet the minimum.
53  for (size_t i = 0; i < tilings_.size(); ++i) {
54    float scale = tilings_[i]->contents_scale();
55    if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale))
56      continue;
57    // Swap with the last element and remove it.
58    tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
59    tilings_.pop_back();
60    --i;
61  }
62
63  // Add any missing tilings from |other| that meet the minimum.
64  for (size_t i = 0; i < other.tilings_.size(); ++i) {
65    float contents_scale = other.tilings_[i]->contents_scale();
66    if (contents_scale < minimum_contents_scale)
67      continue;
68    if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
69      this_tiling->set_resolution(other.tilings_[i]->resolution());
70      this_tiling->UpdateTilesToCurrentPile();
71      this_tiling->SetLayerBounds(new_layer_bounds);
72      this_tiling->Invalidate(layer_invalidation);
73      this_tiling->CreateMissingTilesInLiveTilesRect();
74      DCHECK(this_tiling->tile_size() ==
75             client_->CalculateTileSize(this_tiling->ContentRect().size()));
76      continue;
77    }
78    scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
79        contents_scale,
80        new_layer_bounds,
81        client_);
82    new_tiling->set_resolution(other.tilings_[i]->resolution());
83    tilings_.push_back(new_tiling.Pass());
84  }
85  tilings_.sort(LargestToSmallestScaleFunctor());
86
87  layer_bounds_ = new_layer_bounds;
88}
89
90void PictureLayerTilingSet::SetCanUseLCDText(bool can_use_lcd_text) {
91  for (size_t i = 0; i < tilings_.size(); ++i)
92    tilings_[i]->SetCanUseLCDText(can_use_lcd_text);
93}
94
95PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) {
96  for (size_t i = 0; i < tilings_.size(); ++i)
97    DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
98
99  tilings_.push_back(PictureLayerTiling::Create(contents_scale,
100                                                layer_bounds_,
101                                                client_));
102  PictureLayerTiling* appended = tilings_.back();
103
104  tilings_.sort(LargestToSmallestScaleFunctor());
105  return appended;
106}
107
108PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const {
109  for (size_t i = 0; i < tilings_.size(); ++i) {
110    if (tilings_[i]->contents_scale() == scale)
111      return tilings_[i];
112  }
113  return NULL;
114}
115
116void PictureLayerTilingSet::RemoveAllTilings() {
117  tilings_.clear();
118}
119
120void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
121  ScopedPtrVector<PictureLayerTiling>::iterator iter =
122    std::find(tilings_.begin(), tilings_.end(), tiling);
123  if (iter == tilings_.end())
124    return;
125  tilings_.erase(iter);
126}
127
128void PictureLayerTilingSet::RemoveAllTiles() {
129  for (size_t i = 0; i < tilings_.size(); ++i)
130    tilings_[i]->Reset();
131}
132
133PictureLayerTilingSet::CoverageIterator::CoverageIterator(
134    const PictureLayerTilingSet* set,
135    float contents_scale,
136    gfx::Rect content_rect,
137    float ideal_contents_scale)
138    : set_(set),
139      contents_scale_(contents_scale),
140      ideal_contents_scale_(ideal_contents_scale),
141      current_tiling_(-1) {
142  missing_region_.Union(content_rect);
143
144  for (ideal_tiling_ = 0;
145       static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
146       ++ideal_tiling_) {
147    PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
148    if (tiling->contents_scale() < ideal_contents_scale_) {
149      if (ideal_tiling_ > 0)
150        ideal_tiling_--;
151      break;
152    }
153  }
154
155  DCHECK_LE(set_->tilings_.size(),
156            static_cast<size_t>(std::numeric_limits<int>::max()));
157
158  int num_tilings = set_->tilings_.size();
159  if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
160    ideal_tiling_--;
161
162  ++(*this);
163}
164
165PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
166}
167
168gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
169  if (!tiling_iter_) {
170    if (!region_iter_.has_rect())
171      return gfx::Rect();
172    return region_iter_.rect();
173  }
174  return tiling_iter_.geometry_rect();
175}
176
177gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
178  if (!tiling_iter_)
179    return gfx::RectF();
180  return tiling_iter_.texture_rect();
181}
182
183gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const {
184  if (!tiling_iter_)
185    return gfx::Size();
186  return tiling_iter_.texture_size();
187}
188
189Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
190  if (!tiling_iter_)
191    return NULL;
192  return *tiling_iter_;
193}
194
195Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
196  if (!tiling_iter_)
197    return NULL;
198  return *tiling_iter_;
199}
200
201PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() {
202  if (current_tiling_ < 0)
203    return NULL;
204  if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
205    return NULL;
206  return set_->tilings_[current_tiling_];
207}
208
209int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
210  // Order returned by this method is:
211  // 1. Ideal tiling index
212  // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
213  // 3. Tiling index > Ideal in increasing order (lower res than ideal)
214  // 4. Tiling index > tilings.size() (invalid index)
215  if (current_tiling_ < 0)
216    return ideal_tiling_;
217  else if (current_tiling_ > ideal_tiling_)
218    return current_tiling_ + 1;
219  else if (current_tiling_)
220    return current_tiling_ - 1;
221  else
222    return ideal_tiling_ + 1;
223}
224
225PictureLayerTilingSet::CoverageIterator&
226PictureLayerTilingSet::CoverageIterator::operator++() {
227  bool first_time = current_tiling_ < 0;
228
229  if (!*this && !first_time)
230    return *this;
231
232  if (tiling_iter_)
233    ++tiling_iter_;
234
235  // Loop until we find a valid place to stop.
236  while (true) {
237    while (tiling_iter_ &&
238           (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw(NULL))) {
239      missing_region_.Union(tiling_iter_.geometry_rect());
240      ++tiling_iter_;
241    }
242    if (tiling_iter_)
243      return *this;
244
245    // If the set of current rects for this tiling is done, go to the next
246    // tiling and set up to iterate through all of the remaining holes.
247    // This will also happen the first time through the loop.
248    if (!region_iter_.has_rect()) {
249      current_tiling_ = NextTiling();
250      current_region_.Swap(&missing_region_);
251      missing_region_.Clear();
252      region_iter_ = Region::Iterator(current_region_);
253
254      // All done and all filled.
255      if (!region_iter_.has_rect()) {
256        current_tiling_ = set_->tilings_.size();
257        return *this;
258      }
259
260      // No more valid tiles, return this checkerboard rect.
261      if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
262        return *this;
263    }
264
265    // Pop a rect off.  If there are no more tilings, then these will be
266    // treated as geometry with null tiles that the caller can checkerboard.
267    gfx::Rect last_rect = region_iter_.rect();
268    region_iter_.next();
269
270    // Done, found next checkerboard rect to return.
271    if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
272      return *this;
273
274    // Construct a new iterator for the next tiling, but we need to loop
275    // again until we get to a valid one.
276    tiling_iter_ = PictureLayerTiling::CoverageIterator(
277        set_->tilings_[current_tiling_],
278        contents_scale_,
279        last_rect);
280  }
281
282  return *this;
283}
284
285PictureLayerTilingSet::CoverageIterator::operator bool() const {
286  return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
287      region_iter_.has_rect();
288}
289
290void PictureLayerTilingSet::UpdateTilePriorities(
291    WhichTree tree,
292    gfx::Size device_viewport,
293    gfx::Rect viewport_in_content_space,
294    gfx::Rect visible_content_rect,
295    gfx::Size last_layer_bounds,
296    gfx::Size current_layer_bounds,
297    float last_layer_contents_scale,
298    float current_layer_contents_scale,
299    const gfx::Transform& last_screen_transform,
300    const gfx::Transform& current_screen_transform,
301    double current_frame_time_in_seconds,
302    size_t max_tiles_for_interest_area) {
303  gfx::Rect viewport_in_layer_space = gfx::ScaleToEnclosingRect(
304      viewport_in_content_space,
305      1.f / current_layer_contents_scale);
306  gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
307      visible_content_rect,
308      1.f / current_layer_contents_scale);
309
310  for (size_t i = 0; i < tilings_.size(); ++i) {
311    tilings_[i]->UpdateTilePriorities(
312        tree,
313        device_viewport,
314        viewport_in_layer_space,
315        visible_layer_rect,
316        last_layer_bounds,
317        current_layer_bounds,
318        last_layer_contents_scale,
319        current_layer_contents_scale,
320        last_screen_transform,
321        current_screen_transform,
322        current_frame_time_in_seconds,
323        max_tiles_for_interest_area);
324  }
325}
326
327void PictureLayerTilingSet::DidBecomeActive() {
328  for (size_t i = 0; i < tilings_.size(); ++i)
329    tilings_[i]->DidBecomeActive();
330}
331
332scoped_ptr<base::Value> PictureLayerTilingSet::AsValue() const {
333  scoped_ptr<base::ListValue> state(new base::ListValue());
334  for (size_t i = 0; i < tilings_.size(); ++i)
335    state->Append(tilings_[i]->AsValue().release());
336  return state.PassAs<base::Value>();
337}
338
339size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
340  size_t amount = 0;
341  for (size_t i = 0; i < tilings_.size(); ++i)
342    amount += tilings_[i]->GPUMemoryUsageInBytes();
343  return amount;
344}
345
346}  // namespace cc
347