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    const 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::RemoveTilesInRegion(const Region& region) {
40  for (size_t i = 0; i < tilings_.size(); ++i)
41    tilings_[i]->RemoveTilesInRegion(region);
42}
43
44bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
45                                        const gfx::Size& new_layer_bounds,
46                                        const Region& layer_invalidation,
47                                        float minimum_contents_scale) {
48  if (new_layer_bounds.IsEmpty()) {
49    RemoveAllTilings();
50    layer_bounds_ = new_layer_bounds;
51    return false;
52  }
53
54  tilings_.reserve(other.tilings_.size());
55
56  // Remove any tilings that aren't in |other| or don't meet the minimum.
57  for (size_t i = 0; i < tilings_.size(); ++i) {
58    float scale = tilings_[i]->contents_scale();
59    if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale))
60      continue;
61    // Swap with the last element and remove it.
62    tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
63    tilings_.pop_back();
64    --i;
65  }
66
67  bool have_high_res_tiling = false;
68
69  // Add any missing tilings from |other| that meet the minimum.
70  for (size_t i = 0; i < other.tilings_.size(); ++i) {
71    float contents_scale = other.tilings_[i]->contents_scale();
72    if (contents_scale < minimum_contents_scale)
73      continue;
74    if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
75      this_tiling->set_resolution(other.tilings_[i]->resolution());
76
77      this_tiling->UpdateTilesToCurrentPile(layer_invalidation,
78                                            new_layer_bounds);
79      this_tiling->CreateMissingTilesInLiveTilesRect();
80      if (this_tiling->resolution() == HIGH_RESOLUTION)
81        have_high_res_tiling = true;
82
83      DCHECK(this_tiling->tile_size() ==
84             client_->CalculateTileSize(this_tiling->tiling_size()))
85          << "tile_size: " << this_tiling->tile_size().ToString()
86          << " tiling_size: " << this_tiling->tiling_size().ToString()
87          << " CalculateTileSize: "
88          << client_->CalculateTileSize(this_tiling->tiling_size()).ToString();
89      continue;
90    }
91    scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
92        contents_scale,
93        new_layer_bounds,
94        client_);
95    new_tiling->set_resolution(other.tilings_[i]->resolution());
96    if (new_tiling->resolution() == HIGH_RESOLUTION)
97      have_high_res_tiling = true;
98    tilings_.push_back(new_tiling.Pass());
99  }
100  tilings_.sort(LargestToSmallestScaleFunctor());
101
102  layer_bounds_ = new_layer_bounds;
103  return have_high_res_tiling;
104}
105
106PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) {
107  for (size_t i = 0; i < tilings_.size(); ++i)
108    DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
109
110  tilings_.push_back(PictureLayerTiling::Create(contents_scale,
111                                                layer_bounds_,
112                                                client_));
113  PictureLayerTiling* appended = tilings_.back();
114
115  tilings_.sort(LargestToSmallestScaleFunctor());
116  return appended;
117}
118
119int PictureLayerTilingSet::NumHighResTilings() const {
120  int num_high_res = 0;
121  for (size_t i = 0; i < tilings_.size(); ++i) {
122    if (tilings_[i]->resolution() == HIGH_RESOLUTION)
123      num_high_res++;
124  }
125  return num_high_res;
126}
127
128PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const {
129  for (size_t i = 0; i < tilings_.size(); ++i) {
130    if (tilings_[i]->contents_scale() == scale)
131      return tilings_[i];
132  }
133  return NULL;
134}
135
136void PictureLayerTilingSet::RemoveAllTilings() {
137  tilings_.clear();
138}
139
140void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
141  ScopedPtrVector<PictureLayerTiling>::iterator iter =
142    std::find(tilings_.begin(), tilings_.end(), tiling);
143  if (iter == tilings_.end())
144    return;
145  tilings_.erase(iter);
146}
147
148void PictureLayerTilingSet::RemoveAllTiles() {
149  for (size_t i = 0; i < tilings_.size(); ++i)
150    tilings_[i]->Reset();
151}
152
153PictureLayerTilingSet::CoverageIterator::CoverageIterator(
154    const PictureLayerTilingSet* set,
155    float contents_scale,
156    const gfx::Rect& content_rect,
157    float ideal_contents_scale)
158    : set_(set),
159      contents_scale_(contents_scale),
160      ideal_contents_scale_(ideal_contents_scale),
161      current_tiling_(-1) {
162  missing_region_.Union(content_rect);
163
164  for (ideal_tiling_ = 0;
165       static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
166       ++ideal_tiling_) {
167    PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
168    if (tiling->contents_scale() < ideal_contents_scale_) {
169      if (ideal_tiling_ > 0)
170        ideal_tiling_--;
171      break;
172    }
173  }
174
175  DCHECK_LE(set_->tilings_.size(),
176            static_cast<size_t>(std::numeric_limits<int>::max()));
177
178  int num_tilings = set_->tilings_.size();
179  if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
180    ideal_tiling_--;
181
182  ++(*this);
183}
184
185PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
186}
187
188gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
189  if (!tiling_iter_) {
190    if (!region_iter_.has_rect())
191      return gfx::Rect();
192    return region_iter_.rect();
193  }
194  return tiling_iter_.geometry_rect();
195}
196
197gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
198  if (!tiling_iter_)
199    return gfx::RectF();
200  return tiling_iter_.texture_rect();
201}
202
203gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const {
204  if (!tiling_iter_)
205    return gfx::Size();
206  return tiling_iter_.texture_size();
207}
208
209Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
210  if (!tiling_iter_)
211    return NULL;
212  return *tiling_iter_;
213}
214
215Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
216  if (!tiling_iter_)
217    return NULL;
218  return *tiling_iter_;
219}
220
221PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() {
222  if (current_tiling_ < 0)
223    return NULL;
224  if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
225    return NULL;
226  return set_->tilings_[current_tiling_];
227}
228
229int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
230  // Order returned by this method is:
231  // 1. Ideal tiling index
232  // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
233  // 3. Tiling index > Ideal in increasing order (lower res than ideal)
234  // 4. Tiling index > tilings.size() (invalid index)
235  if (current_tiling_ < 0)
236    return ideal_tiling_;
237  else if (current_tiling_ > ideal_tiling_)
238    return current_tiling_ + 1;
239  else if (current_tiling_)
240    return current_tiling_ - 1;
241  else
242    return ideal_tiling_ + 1;
243}
244
245PictureLayerTilingSet::CoverageIterator&
246PictureLayerTilingSet::CoverageIterator::operator++() {
247  bool first_time = current_tiling_ < 0;
248
249  if (!*this && !first_time)
250    return *this;
251
252  if (tiling_iter_)
253    ++tiling_iter_;
254
255  // Loop until we find a valid place to stop.
256  while (true) {
257    while (tiling_iter_ &&
258           (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) {
259      missing_region_.Union(tiling_iter_.geometry_rect());
260      ++tiling_iter_;
261    }
262    if (tiling_iter_)
263      return *this;
264
265    // If the set of current rects for this tiling is done, go to the next
266    // tiling and set up to iterate through all of the remaining holes.
267    // This will also happen the first time through the loop.
268    if (!region_iter_.has_rect()) {
269      current_tiling_ = NextTiling();
270      current_region_.Swap(&missing_region_);
271      missing_region_.Clear();
272      region_iter_ = Region::Iterator(current_region_);
273
274      // All done and all filled.
275      if (!region_iter_.has_rect()) {
276        current_tiling_ = set_->tilings_.size();
277        return *this;
278      }
279
280      // No more valid tiles, return this checkerboard rect.
281      if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
282        return *this;
283    }
284
285    // Pop a rect off.  If there are no more tilings, then these will be
286    // treated as geometry with null tiles that the caller can checkerboard.
287    gfx::Rect last_rect = region_iter_.rect();
288    region_iter_.next();
289
290    // Done, found next checkerboard rect to return.
291    if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
292      return *this;
293
294    // Construct a new iterator for the next tiling, but we need to loop
295    // again until we get to a valid one.
296    tiling_iter_ = PictureLayerTiling::CoverageIterator(
297        set_->tilings_[current_tiling_],
298        contents_scale_,
299        last_rect);
300  }
301
302  return *this;
303}
304
305PictureLayerTilingSet::CoverageIterator::operator bool() const {
306  return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
307      region_iter_.has_rect();
308}
309
310void PictureLayerTilingSet::DidBecomeActive() {
311  for (size_t i = 0; i < tilings_.size(); ++i)
312    tilings_[i]->DidBecomeActive();
313}
314
315void PictureLayerTilingSet::DidBecomeRecycled() {
316  for (size_t i = 0; i < tilings_.size(); ++i)
317    tilings_[i]->DidBecomeRecycled();
318}
319
320void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue* state) const {
321  for (size_t i = 0; i < tilings_.size(); ++i) {
322    state->BeginDictionary();
323    tilings_[i]->AsValueInto(state);
324    state->EndDictionary();
325  }
326}
327
328size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
329  size_t amount = 0;
330  for (size_t i = 0; i < tilings_.size(); ++i)
331    amount += tilings_[i]->GPUMemoryUsageInBytes();
332  return amount;
333}
334
335PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange(
336    TilingRangeType type) const {
337  // Doesn't seem to be the case right now but if it ever becomes a performance
338  // problem to compute these ranges each time this function is called, we can
339  // compute them only when the tiling set has changed instead.
340  TilingRange high_res_range(0, 0);
341  TilingRange low_res_range(tilings_.size(), tilings_.size());
342  for (size_t i = 0; i < tilings_.size(); ++i) {
343    const PictureLayerTiling* tiling = tilings_[i];
344    if (tiling->resolution() == HIGH_RESOLUTION)
345      high_res_range = TilingRange(i, i + 1);
346    if (tiling->resolution() == LOW_RESOLUTION)
347      low_res_range = TilingRange(i, i + 1);
348  }
349
350  switch (type) {
351    case HIGHER_THAN_HIGH_RES:
352      return TilingRange(0, high_res_range.start);
353    case HIGH_RES:
354      return high_res_range;
355    case BETWEEN_HIGH_AND_LOW_RES:
356      return TilingRange(high_res_range.end, low_res_range.start);
357    case LOW_RES:
358      return low_res_range;
359    case LOWER_THAN_LOW_RES:
360      return TilingRange(low_res_range.end, tilings_.size());
361  }
362
363  NOTREACHED();
364  return TilingRange(0, 0);
365}
366
367}  // namespace cc
368