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