| 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 |