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/tile_priority.h" 6 7 #include "base/values.h" 8 #include "cc/base/math_util.h" 9 10 namespace { 11 12 // TODO(qinmin): modify ui/range/Range.h to support template so that we 13 // don't need to define this. 14 struct Range { 15 Range(float start, float end) : start_(start), end_(end) {} 16 bool IsEmpty(); 17 float start_; 18 float end_; 19 }; 20 21 inline bool Intersects(const Range& a, const Range& b) { 22 return a.start_ < b.end_ && b.start_ < a.end_; 23 } 24 25 inline Range Intersect(const Range& a, const Range& b) { 26 return Range(std::max(a.start_, b.start_), std::min(a.end_, b.end_)); 27 } 28 29 bool Range::IsEmpty() { 30 return start_ >= end_; 31 } 32 33 inline void IntersectNegativeHalfplane(Range* out, 34 float previous, 35 float current, 36 float target, 37 float time_delta) { 38 float time_per_dist = time_delta / (current - previous); 39 float t = (target - current) * time_per_dist; 40 if (time_per_dist > 0.0f) 41 out->start_ = std::max(out->start_, t); 42 else 43 out->end_ = std::min(out->end_, t); 44 } 45 46 inline void IntersectPositiveHalfplane(Range* out, 47 float previous, 48 float current, 49 float target, 50 float time_delta) { 51 float time_per_dist = time_delta / (current - previous); 52 float t = (target - current) * time_per_dist; 53 if (time_per_dist < 0.0f) 54 out->start_ = std::max(out->start_, t); 55 else 56 out->end_ = std::min(out->end_, t); 57 } 58 59 } // namespace 60 61 namespace cc { 62 63 scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree) { 64 switch (tree) { 65 case ACTIVE_TREE: 66 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 67 "ACTIVE_TREE")); 68 case PENDING_TREE: 69 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 70 "PENDING_TREE")); 71 default: 72 DCHECK(false) << "Unrecognized WhichTree value " << tree; 73 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 74 "<unknown WhichTree value>")); 75 } 76 } 77 78 scoped_ptr<base::Value> TileResolutionAsValue( 79 TileResolution resolution) { 80 switch (resolution) { 81 case LOW_RESOLUTION: 82 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 83 "LOW_RESOLUTION")); 84 case HIGH_RESOLUTION: 85 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 86 "HIGH_RESOLUTION")); 87 case NON_IDEAL_RESOLUTION: 88 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 89 "NON_IDEAL_RESOLUTION")); 90 default: 91 DCHECK(false) << "Unrecognized TileResolution value " << resolution; 92 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 93 "<unknown TileResolution value>")); 94 } 95 } 96 97 scoped_ptr<base::Value> TilePriority::AsValue() const { 98 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); 99 state->Set("resolution", TileResolutionAsValue(resolution).release()); 100 state->Set("time_to_visible_in_seconds", 101 MathUtil::AsValueSafely(time_to_visible_in_seconds).release()); 102 state->Set("distance_to_visible_in_pixels", 103 MathUtil::AsValueSafely(distance_to_visible_in_pixels).release()); 104 return state.PassAs<base::Value>(); 105 } 106 107 float TilePriority::TimeForBoundsToIntersect(const gfx::RectF& previous_bounds, 108 const gfx::RectF& current_bounds, 109 float time_delta, 110 const gfx::RectF& target_bounds) { 111 // Perform an intersection test explicitly between current and target. 112 if (current_bounds.x() < target_bounds.right() && 113 current_bounds.y() < target_bounds.bottom() && 114 target_bounds.x() < current_bounds.right() && 115 target_bounds.y() < current_bounds.bottom()) 116 return 0.0f; 117 118 const float kMaxTimeToVisibleInSeconds = 119 std::numeric_limits<float>::infinity(); 120 121 if (time_delta == 0.0f) 122 return kMaxTimeToVisibleInSeconds; 123 124 // As we are trying to solve the case of both scaling and scrolling, using 125 // a single coordinate with velocity is not enough. The logic here is to 126 // calculate the velocity for each edge. Then we calculate the time range that 127 // each edge will stay on the same side of the target bounds. If there is an 128 // overlap between these time ranges, the bounds must have intersect with 129 // each other during that period of time. 130 Range range(0.0f, kMaxTimeToVisibleInSeconds); 131 IntersectPositiveHalfplane( 132 &range, previous_bounds.x(), current_bounds.x(), 133 target_bounds.right(), time_delta); 134 IntersectNegativeHalfplane( 135 &range, previous_bounds.right(), current_bounds.right(), 136 target_bounds.x(), time_delta); 137 IntersectPositiveHalfplane( 138 &range, previous_bounds.y(), current_bounds.y(), 139 target_bounds.bottom(), time_delta); 140 IntersectNegativeHalfplane( 141 &range, previous_bounds.bottom(), current_bounds.bottom(), 142 target_bounds.y(), time_delta); 143 return range.IsEmpty() ? kMaxTimeToVisibleInSeconds : range.start_; 144 } 145 146 scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue( 147 TileMemoryLimitPolicy policy) { 148 switch (policy) { 149 case ALLOW_NOTHING: 150 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 151 "ALLOW_NOTHING")); 152 case ALLOW_ABSOLUTE_MINIMUM: 153 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 154 "ALLOW_ABSOLUTE_MINIMUM")); 155 case ALLOW_PREPAINT_ONLY: 156 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 157 "ALLOW_PREPAINT_ONLY")); 158 case ALLOW_ANYTHING: 159 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 160 "ALLOW_ANYTHING")); 161 default: 162 DCHECK(false) << "Unrecognized policy value"; 163 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 164 "<unknown>")); 165 } 166 } 167 168 scoped_ptr<base::Value> TreePriorityAsValue(TreePriority prio) { 169 switch (prio) { 170 case SAME_PRIORITY_FOR_BOTH_TREES: 171 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 172 "SAME_PRIORITY_FOR_BOTH_TREES")); 173 case SMOOTHNESS_TAKES_PRIORITY: 174 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 175 "SMOOTHNESS_TAKES_PRIORITY")); 176 case NEW_CONTENT_TAKES_PRIORITY: 177 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 178 "NEW_CONTENT_TAKES_PRIORITY")); 179 default: 180 DCHECK(false) << "Unrecognized priority value " << prio; 181 return scoped_ptr<base::Value>(base::Value::CreateStringValue( 182 "<unknown>")); 183 } 184 } 185 186 scoped_ptr<base::Value> GlobalStateThatImpactsTilePriority::AsValue() const { 187 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); 188 state->Set("memory_limit_policy", 189 TileMemoryLimitPolicyAsValue(memory_limit_policy).release()); 190 state->SetInteger("memory_limit_in_bytes", memory_limit_in_bytes); 191 state->SetInteger("unused_memory_limit_in_bytes", 192 unused_memory_limit_in_bytes); 193 state->SetInteger("num_resources_limit", num_resources_limit); 194 state->Set("tree_priority", TreePriorityAsValue(tree_priority).release()); 195 return state.PassAs<base::Value>(); 196 } 197 198 } // namespace cc 199