OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/tile_priority.h" | 5 #include "cc/tile_priority.h" |
6 | 6 |
7 #include "base/values.h" | 7 #include "base/values.h" |
8 | 8 |
9 namespace { | 9 namespace { |
10 | 10 |
11 // TODO(qinmin): modify ui/range/Range.h to support template so that we | 11 // TODO(qinmin): modify ui/range/Range.h to support template so that we |
12 // don't need to define this. | 12 // don't need to define this. |
13 struct Range { | 13 struct Range { |
14 Range(double start, double end) : start_(start), end_(end) {} | 14 Range(float start, float end) : start_(start), end_(end) {} |
15 Range Intersects(const Range& other); | |
16 bool IsEmpty(); | 15 bool IsEmpty(); |
17 double start_; | 16 float start_; |
18 double end_; | 17 float end_; |
19 }; | 18 }; |
20 | 19 |
21 Range Range::Intersects(const Range& other) { | 20 inline bool Intersects(const Range& a, const Range& b) { |
22 start_ = std::max(start_, other.start_); | 21 return a.start_ < b.end_ && b.start_ < a.end_; |
23 end_ = std::min(end_, other.end_); | 22 } |
24 return Range(start_, end_); | 23 |
| 24 inline Range Intersect(const Range& a, const Range& b) { |
| 25 return Range(std::max(a.start_, b.start_), std::min(a.end_, b.end_)); |
25 } | 26 } |
26 | 27 |
27 bool Range::IsEmpty() { | 28 bool Range::IsEmpty() { |
28 return start_ >= end_; | 29 return start_ >= end_; |
29 } | 30 } |
30 | 31 |
31 // Calculate a time range that |value| will be larger than |threshold| | 32 inline void IntersectNegativeHalfplane(Range& out, float previous, |
32 // given the velocity of its change. | 33 float current, float target, float time_delta) { |
33 Range TimeRangeValueLargerThanThreshold( | 34 float time_per_dist = time_delta / (current - previous); |
34 int value, int threshold, double velocity) { | 35 float t = (target - current) * time_per_dist; |
35 double minimum_time = 0; | 36 if (time_per_dist > 0.0f) |
36 double maximum_time = cc::TilePriority::kMaxTimeToVisibleInSeconds; | 37 out.start_ = std::max(out.start_, t); |
| 38 else |
| 39 out.end_ = std::min(out.end_, t); |
| 40 } |
37 | 41 |
38 if (velocity > 0) { | 42 inline void IntersectPositiveHalfplane(Range& out, float previous, |
39 if (value < threshold) | 43 float current, float target, float time_delta) { |
40 minimum_time = std::min(cc::TilePriority::kMaxTimeToVisibleInSeconds, | 44 float time_per_dist = time_delta / (current - previous); |
41 (threshold - value) / velocity); | 45 float t = (target - current) * time_per_dist; |
42 } else if (velocity <= 0) { | 46 if (time_per_dist < 0.0f) |
43 if (value < threshold) | 47 out.start_ = std::max(out.start_, t); |
44 minimum_time = cc::TilePriority::kMaxTimeToVisibleInSeconds; | 48 else |
45 else if (velocity != 0) | 49 out.end_ = std::min(out.end_, t); |
46 maximum_time = std::min(maximum_time, (threshold - value) / velocity); | |
47 } | |
48 | |
49 return Range(minimum_time, maximum_time); | |
50 } | 50 } |
51 | 51 |
52 } // namespace | 52 } // namespace |
53 | 53 |
54 namespace cc { | 54 namespace cc { |
55 | 55 |
56 const double TilePriority::kMaxTimeToVisibleInSeconds = 1000; | 56 const float TilePriority::kMaxTimeToVisibleInSeconds = |
| 57 std::numeric_limits<float>::infinity(); |
57 | 58 |
58 scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree) { | 59 float TilePriority::TimeForBoundsToIntersect(const gfx::RectF& previous_bounds, |
59 switch (tree) { | 60 const gfx::RectF& current_bounds, |
60 case ACTIVE_TREE: | 61 float time_delta, |
61 return scoped_ptr<base::Value>(base::Value::CreateStringValue( | 62 const gfx::RectF& target_bounds) { |
62 "ACTIVE_TREE")); | 63 // Perform an intersection test explicitly between current and target. |
63 case PENDING_TREE: | 64 if (current_bounds.x() < target_bounds.right() && |
64 return scoped_ptr<base::Value>(base::Value::CreateStringValue( | 65 current_bounds.y() < target_bounds.bottom() && |
65 "PENDING_TREE")); | 66 target_bounds.x() < current_bounds.right() && |
66 default: | 67 target_bounds.y() < current_bounds.bottom()) |
67 DCHECK(false) << "Unrecognized WhichTree value"; | 68 return 0.0f; |
68 return scoped_ptr<base::Value>(base::Value::CreateStringValue( | |
69 "<unknown WhichTree value>")); | |
70 } | |
71 } | |
72 | 69 |
73 int TilePriority::manhattanDistance(const gfx::RectF& a, const gfx::RectF& b) { | 70 if (time_delta == 0.0f) |
74 gfx::RectF c = gfx::UnionRects(a, b); | |
75 // Rects touching the edge of the screen should not be considered visible. | |
76 // So we add 1 pixel here to avoid that situation. | |
77 int x = static_cast<int>( | |
78 std::max(0.0f, c.width() - a.width() - b.width() + 1)); | |
79 int y = static_cast<int>( | |
80 std::max(0.0f, c.height() - a.height() - b.height() + 1)); | |
81 return (x + y); | |
82 } | |
83 | |
84 double TilePriority::TimeForBoundsToIntersect(gfx::RectF previous_bounds, | |
85 gfx::RectF current_bounds, | |
86 double time_delta, | |
87 gfx::RectF target_bounds) { | |
88 if (current_bounds.Intersects(target_bounds)) | |
89 return 0; | |
90 | |
91 if (previous_bounds.Intersects(target_bounds) || time_delta == 0) | |
92 return kMaxTimeToVisibleInSeconds; | 71 return kMaxTimeToVisibleInSeconds; |
93 | 72 |
94 // As we are trying to solve the case of both scaling and scrolling, using | 73 // As we are trying to solve the case of both scaling and scrolling, using |
95 // a single coordinate with velocity is not enough. The logic here is to | 74 // a single coordinate with velocity is not enough. The logic here is to |
96 // calculate the velocity for each edge. Then we calculate the time range that | 75 // calculate the velocity for each edge. Then we calculate the time range that |
97 // each edge will stay on the same side of the target bounds. If there is an | 76 // each edge will stay on the same side of the target bounds. If there is an |
98 // overlap between these time ranges, the bounds must have intersect with | 77 // overlap between these time ranges, the bounds must have intersect with |
99 // each other during that period of time. | 78 // each other during that period of time. |
100 double velocity = | 79 Range range(0.0f, kMaxTimeToVisibleInSeconds); |
101 (current_bounds.right() - previous_bounds.right()) / time_delta; | 80 IntersectPositiveHalfplane( |
102 Range range = TimeRangeValueLargerThanThreshold( | 81 range, previous_bounds.x(), current_bounds.x(), |
103 current_bounds.right(), target_bounds.x(), velocity); | 82 target_bounds.right(), time_delta); |
104 | 83 IntersectNegativeHalfplane( |
105 velocity = (current_bounds.x() - previous_bounds.x()) / time_delta; | 84 range, previous_bounds.right(), current_bounds.right(), |
106 range = range.Intersects(TimeRangeValueLargerThanThreshold( | 85 target_bounds.x(), time_delta); |
107 -current_bounds.x(), -target_bounds.right(), -velocity)); | 86 IntersectPositiveHalfplane( |
108 | 87 range, previous_bounds.y(), current_bounds.y(), |
109 | 88 target_bounds.bottom(), time_delta); |
110 velocity = (current_bounds.y() - previous_bounds.y()) / time_delta; | 89 IntersectNegativeHalfplane( |
111 range = range.Intersects(TimeRangeValueLargerThanThreshold( | 90 range, previous_bounds.bottom(), current_bounds.bottom(), |
112 -current_bounds.y(), -target_bounds.bottom(), -velocity)); | 91 target_bounds.y(), time_delta); |
113 | |
114 velocity = (current_bounds.bottom() - previous_bounds.bottom()) / time_delta; | |
115 range = range.Intersects(TimeRangeValueLargerThanThreshold( | |
116 current_bounds.bottom(), target_bounds.y(), velocity)); | |
117 | |
118 return range.IsEmpty() ? kMaxTimeToVisibleInSeconds : range.start_; | 92 return range.IsEmpty() ? kMaxTimeToVisibleInSeconds : range.start_; |
119 } | 93 } |
120 | 94 |
121 scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue( | 95 scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue( |
122 TileMemoryLimitPolicy policy) { | 96 TileMemoryLimitPolicy policy) { |
123 switch (policy) { | 97 switch (policy) { |
124 case ALLOW_NOTHING: | 98 case ALLOW_NOTHING: |
125 return scoped_ptr<base::Value>(base::Value::CreateStringValue( | 99 return scoped_ptr<base::Value>(base::Value::CreateStringValue( |
126 "ALLOW_NOTHING")); | 100 "ALLOW_NOTHING")); |
127 case ALLOW_ABSOLUTE_MINIMUM: | 101 case ALLOW_ABSOLUTE_MINIMUM: |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 scoped_ptr<base::Value> GlobalStateThatImpactsTilePriority::AsValue() const { | 135 scoped_ptr<base::Value> GlobalStateThatImpactsTilePriority::AsValue() const { |
162 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); | 136 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); |
163 state->Set("memory_limit_policy", TileMemoryLimitPolicyAsValue(memory_limit_po
licy).release()); | 137 state->Set("memory_limit_policy", TileMemoryLimitPolicyAsValue(memory_limit_po
licy).release()); |
164 state->SetInteger("memory_limit_in_bytes", memory_limit_in_bytes); | 138 state->SetInteger("memory_limit_in_bytes", memory_limit_in_bytes); |
165 state->Set("tree_priority", TreePriorityAsValue(tree_priority).release()); | 139 state->Set("tree_priority", TreePriorityAsValue(tree_priority).release()); |
166 return state.PassAs<base::Value>(); | 140 return state.PassAs<base::Value>(); |
167 } | 141 } |
168 | 142 |
169 | 143 |
170 } // namespace cc | 144 } // namespace cc |
OLD | NEW |