OLD | NEW |
| (Empty) |
1 // Copyright 2013 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/input/top_controls_manager.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cmath> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/time/time.h" | |
13 #include "cc/input/top_controls_manager_client.h" | |
14 #include "cc/layers/layer_impl.h" | |
15 #include "cc/test/fake_impl_proxy.h" | |
16 #include "cc/test/fake_layer_tree_host_impl.h" | |
17 #include "cc/test/test_shared_bitmap_manager.h" | |
18 #include "cc/test/test_task_graph_runner.h" | |
19 #include "cc/trees/layer_tree_impl.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 #include "ui/gfx/frame_time.h" | |
22 #include "ui/gfx/geometry/vector2d_f.h" | |
23 | |
24 namespace cc { | |
25 namespace { | |
26 | |
27 class MockTopControlsManagerClient : public TopControlsManagerClient { | |
28 public: | |
29 MockTopControlsManagerClient(float top_controls_height, | |
30 float top_controls_show_threshold, | |
31 float top_controls_hide_threshold) | |
32 : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_), | |
33 redraw_needed_(false), | |
34 update_draw_properties_needed_(false), | |
35 top_controls_shown_ratio_(1.f), | |
36 top_controls_height_(top_controls_height), | |
37 top_controls_show_threshold_(top_controls_show_threshold), | |
38 top_controls_hide_threshold_(top_controls_hide_threshold) { | |
39 active_tree_ = LayerTreeImpl::create( | |
40 &host_impl_, new SyncedProperty<ScaleGroup>, new SyncedTopControls, | |
41 new SyncedElasticOverscroll); | |
42 root_scroll_layer_ = LayerImpl::Create(active_tree_.get(), 1); | |
43 } | |
44 | |
45 ~MockTopControlsManagerClient() override {} | |
46 | |
47 void DidChangeTopControlsPosition() override { | |
48 redraw_needed_ = true; | |
49 update_draw_properties_needed_ = true; | |
50 } | |
51 | |
52 bool HaveRootScrollLayer() const override { return true; } | |
53 | |
54 float TopControlsHeight() const override { return top_controls_height_; } | |
55 | |
56 void SetCurrentTopControlsShownRatio(float ratio) override { | |
57 ASSERT_FALSE(std::isnan(ratio)); | |
58 ASSERT_FALSE(ratio == std::numeric_limits<float>::infinity()); | |
59 ASSERT_FALSE(ratio == -std::numeric_limits<float>::infinity()); | |
60 ratio = std::max(ratio, 0.f); | |
61 ratio = std::min(ratio, 1.f); | |
62 top_controls_shown_ratio_ = ratio; | |
63 } | |
64 | |
65 float CurrentTopControlsShownRatio() const override { | |
66 return top_controls_shown_ratio_; | |
67 } | |
68 | |
69 LayerImpl* rootScrollLayer() { | |
70 return root_scroll_layer_.get(); | |
71 } | |
72 | |
73 TopControlsManager* manager() { | |
74 if (!manager_) { | |
75 manager_ = TopControlsManager::Create(this, | |
76 top_controls_show_threshold_, | |
77 top_controls_hide_threshold_); | |
78 } | |
79 return manager_.get(); | |
80 } | |
81 | |
82 void SetTopControlsHeight(float height) { top_controls_height_ = height; } | |
83 | |
84 private: | |
85 FakeImplProxy proxy_; | |
86 TestSharedBitmapManager shared_bitmap_manager_; | |
87 TestTaskGraphRunner task_graph_runner_; | |
88 FakeLayerTreeHostImpl host_impl_; | |
89 scoped_ptr<LayerTreeImpl> active_tree_; | |
90 scoped_ptr<LayerImpl> root_scroll_layer_; | |
91 scoped_ptr<TopControlsManager> manager_; | |
92 bool redraw_needed_; | |
93 bool update_draw_properties_needed_; | |
94 | |
95 float top_controls_shown_ratio_; | |
96 float top_controls_height_; | |
97 float top_controls_show_threshold_; | |
98 float top_controls_hide_threshold_; | |
99 }; | |
100 | |
101 TEST(TopControlsManagerTest, EnsureScrollThresholdApplied) { | |
102 MockTopControlsManagerClient client(100.f, 0.5f, 0.5f); | |
103 TopControlsManager* manager = client.manager(); | |
104 | |
105 manager->ScrollBegin(); | |
106 | |
107 // Scroll down to hide the controls entirely. | |
108 manager->ScrollBy(gfx::Vector2dF(0.f, 30.f)); | |
109 EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset()); | |
110 | |
111 manager->ScrollBy(gfx::Vector2dF(0.f, 30.f)); | |
112 EXPECT_FLOAT_EQ(-60.f, manager->ControlsTopOffset()); | |
113 | |
114 manager->ScrollBy(gfx::Vector2dF(0.f, 100.f)); | |
115 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
116 | |
117 // Scroll back up a bit and ensure the controls don't move until we cross | |
118 // the threshold. | |
119 manager->ScrollBy(gfx::Vector2dF(0.f, -10.f)); | |
120 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
121 | |
122 manager->ScrollBy(gfx::Vector2dF(0.f, -50.f)); | |
123 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
124 | |
125 // After hitting the threshold, further scrolling up should result in the top | |
126 // controls showing. | |
127 manager->ScrollBy(gfx::Vector2dF(0.f, -10.f)); | |
128 EXPECT_FLOAT_EQ(-90.f, manager->ControlsTopOffset()); | |
129 | |
130 manager->ScrollBy(gfx::Vector2dF(0.f, -50.f)); | |
131 EXPECT_FLOAT_EQ(-40.f, manager->ControlsTopOffset()); | |
132 | |
133 // Reset the scroll threshold by going further up the page than the initial | |
134 // threshold. | |
135 manager->ScrollBy(gfx::Vector2dF(0.f, -100.f)); | |
136 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
137 | |
138 // See that scrolling down the page now will result in the controls hiding. | |
139 manager->ScrollBy(gfx::Vector2dF(0.f, 20.f)); | |
140 EXPECT_FLOAT_EQ(-20.f, manager->ControlsTopOffset()); | |
141 | |
142 manager->ScrollEnd(); | |
143 } | |
144 | |
145 TEST(TopControlsManagerTest, PartialShownHideAnimation) { | |
146 MockTopControlsManagerClient client(100.f, 0.5f, 0.5f); | |
147 TopControlsManager* manager = client.manager(); | |
148 manager->ScrollBegin(); | |
149 manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); | |
150 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
151 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
152 manager->ScrollEnd(); | |
153 | |
154 manager->ScrollBegin(); | |
155 manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); | |
156 EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset()); | |
157 EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset()); | |
158 manager->ScrollEnd(); | |
159 | |
160 EXPECT_TRUE(manager->animation()); | |
161 | |
162 base::TimeTicks time = gfx::FrameTime::Now(); | |
163 float previous; | |
164 while (manager->animation()) { | |
165 previous = manager->TopControlsShownRatio(); | |
166 time = base::TimeDelta::FromMicroseconds(100) + time; | |
167 manager->Animate(time); | |
168 EXPECT_LT(manager->TopControlsShownRatio(), previous); | |
169 } | |
170 EXPECT_FALSE(manager->animation()); | |
171 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
172 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
173 } | |
174 | |
175 TEST(TopControlsManagerTest, PartialShownShowAnimation) { | |
176 MockTopControlsManagerClient client(100.f, 0.5f, 0.5f); | |
177 TopControlsManager* manager = client.manager(); | |
178 manager->ScrollBegin(); | |
179 manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); | |
180 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
181 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
182 manager->ScrollEnd(); | |
183 | |
184 manager->ScrollBegin(); | |
185 manager->ScrollBy(gfx::Vector2dF(0.f, -70.f)); | |
186 EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset()); | |
187 EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset()); | |
188 manager->ScrollEnd(); | |
189 | |
190 EXPECT_TRUE(manager->animation()); | |
191 | |
192 base::TimeTicks time = gfx::FrameTime::Now(); | |
193 float previous; | |
194 while (manager->animation()) { | |
195 previous = manager->TopControlsShownRatio(); | |
196 time = base::TimeDelta::FromMicroseconds(100) + time; | |
197 manager->Animate(time); | |
198 EXPECT_GT(manager->TopControlsShownRatio(), previous); | |
199 } | |
200 EXPECT_FALSE(manager->animation()); | |
201 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
202 EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset()); | |
203 } | |
204 | |
205 TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdShows) { | |
206 MockTopControlsManagerClient client(100.f, 0.25f, 0.25f); | |
207 TopControlsManager* manager = client.manager(); | |
208 | |
209 manager->ScrollBegin(); | |
210 | |
211 manager->ScrollBy(gfx::Vector2dF(0.f, 20.f)); | |
212 EXPECT_FLOAT_EQ(-20.f, manager->ControlsTopOffset()); | |
213 EXPECT_FLOAT_EQ(80.f, manager->ContentTopOffset()); | |
214 | |
215 manager->ScrollEnd(); | |
216 EXPECT_TRUE(manager->animation()); | |
217 | |
218 base::TimeTicks time = gfx::FrameTime::Now(); | |
219 float previous; | |
220 while (manager->animation()) { | |
221 previous = manager->TopControlsShownRatio(); | |
222 time = base::TimeDelta::FromMicroseconds(100) + time; | |
223 manager->Animate(time); | |
224 EXPECT_GT(manager->TopControlsShownRatio(), previous); | |
225 } | |
226 EXPECT_FALSE(manager->animation()); | |
227 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
228 EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset()); | |
229 } | |
230 | |
231 TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdHides) { | |
232 MockTopControlsManagerClient client(100.f, 0.25f, 0.25f); | |
233 TopControlsManager* manager = client.manager(); | |
234 | |
235 manager->ScrollBegin(); | |
236 | |
237 manager->ScrollBy(gfx::Vector2dF(0.f, 30.f)); | |
238 EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset()); | |
239 EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset()); | |
240 | |
241 manager->ScrollEnd(); | |
242 EXPECT_TRUE(manager->animation()); | |
243 | |
244 base::TimeTicks time = gfx::FrameTime::Now(); | |
245 float previous; | |
246 while (manager->animation()) { | |
247 previous = manager->TopControlsShownRatio(); | |
248 time = base::TimeDelta::FromMicroseconds(100) + time; | |
249 manager->Animate(time); | |
250 EXPECT_LT(manager->TopControlsShownRatio(), previous); | |
251 } | |
252 EXPECT_FALSE(manager->animation()); | |
253 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
254 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
255 } | |
256 | |
257 TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdHides) { | |
258 MockTopControlsManagerClient client(100.f, 0.25f, 0.25f); | |
259 TopControlsManager* manager = client.manager(); | |
260 | |
261 manager->ScrollBy(gfx::Vector2dF(0.f, 200.f)); | |
262 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
263 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
264 | |
265 manager->ScrollBegin(); | |
266 | |
267 manager->ScrollBy(gfx::Vector2dF(0.f, -20.f)); | |
268 EXPECT_FLOAT_EQ(-80.f, manager->ControlsTopOffset()); | |
269 EXPECT_FLOAT_EQ(20.f, manager->ContentTopOffset()); | |
270 | |
271 manager->ScrollEnd(); | |
272 EXPECT_TRUE(manager->animation()); | |
273 | |
274 base::TimeTicks time = gfx::FrameTime::Now(); | |
275 float previous; | |
276 while (manager->animation()) { | |
277 previous = manager->TopControlsShownRatio(); | |
278 time = base::TimeDelta::FromMicroseconds(100) + time; | |
279 manager->Animate(time); | |
280 EXPECT_LT(manager->TopControlsShownRatio(), previous); | |
281 } | |
282 EXPECT_FALSE(manager->animation()); | |
283 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
284 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
285 } | |
286 | |
287 TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdShows) { | |
288 MockTopControlsManagerClient client(100.f, 0.25f, 0.25f); | |
289 TopControlsManager* manager = client.manager(); | |
290 | |
291 manager->ScrollBy(gfx::Vector2dF(0.f, 200.f)); | |
292 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
293 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
294 | |
295 manager->ScrollBegin(); | |
296 | |
297 manager->ScrollBy(gfx::Vector2dF(0.f, -30.f)); | |
298 EXPECT_FLOAT_EQ(-70.f, manager->ControlsTopOffset()); | |
299 EXPECT_FLOAT_EQ(30.f, manager->ContentTopOffset()); | |
300 | |
301 manager->ScrollEnd(); | |
302 EXPECT_TRUE(manager->animation()); | |
303 | |
304 base::TimeTicks time = gfx::FrameTime::Now(); | |
305 float previous; | |
306 while (manager->animation()) { | |
307 previous = manager->TopControlsShownRatio(); | |
308 time = base::TimeDelta::FromMicroseconds(100) + time; | |
309 manager->Animate(time); | |
310 EXPECT_GT(manager->TopControlsShownRatio(), previous); | |
311 } | |
312 EXPECT_FALSE(manager->animation()); | |
313 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
314 EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset()); | |
315 } | |
316 | |
317 TEST(TopControlsManagerTest, PinchIgnoresScroll) { | |
318 MockTopControlsManagerClient client(100.f, 0.5f, 0.5f); | |
319 TopControlsManager* manager = client.manager(); | |
320 | |
321 // Hide the controls. | |
322 manager->ScrollBegin(); | |
323 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
324 | |
325 manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); | |
326 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
327 | |
328 manager->PinchBegin(); | |
329 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
330 | |
331 // Scrolls are ignored during pinch. | |
332 manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); | |
333 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
334 manager->PinchEnd(); | |
335 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
336 | |
337 // Scrolls should no long be ignored. | |
338 manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); | |
339 EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset()); | |
340 EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset()); | |
341 manager->ScrollEnd(); | |
342 | |
343 EXPECT_TRUE(manager->animation()); | |
344 } | |
345 | |
346 TEST(TopControlsManagerTest, PinchBeginStartsAnimationIfNecessary) { | |
347 MockTopControlsManagerClient client(100.f, 0.5f, 0.5f); | |
348 TopControlsManager* manager = client.manager(); | |
349 | |
350 manager->ScrollBegin(); | |
351 manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); | |
352 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
353 | |
354 manager->PinchBegin(); | |
355 EXPECT_FALSE(manager->animation()); | |
356 | |
357 manager->PinchEnd(); | |
358 EXPECT_FALSE(manager->animation()); | |
359 | |
360 manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); | |
361 EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset()); | |
362 EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset()); | |
363 | |
364 manager->PinchBegin(); | |
365 EXPECT_TRUE(manager->animation()); | |
366 | |
367 base::TimeTicks time = base::TimeTicks::Now(); | |
368 float previous; | |
369 while (manager->animation()) { | |
370 previous = manager->TopControlsShownRatio(); | |
371 time = base::TimeDelta::FromMicroseconds(100) + time; | |
372 manager->Animate(time); | |
373 EXPECT_LT(manager->TopControlsShownRatio(), previous); | |
374 } | |
375 EXPECT_FALSE(manager->animation()); | |
376 | |
377 manager->PinchEnd(); | |
378 EXPECT_FALSE(manager->animation()); | |
379 | |
380 manager->ScrollBy(gfx::Vector2dF(0.f, -55.f)); | |
381 EXPECT_FLOAT_EQ(-45.f, manager->ControlsTopOffset()); | |
382 EXPECT_FLOAT_EQ(55.f, manager->ContentTopOffset()); | |
383 EXPECT_FALSE(manager->animation()); | |
384 | |
385 manager->ScrollEnd(); | |
386 EXPECT_TRUE(manager->animation()); | |
387 | |
388 time = base::TimeTicks::Now(); | |
389 while (manager->animation()) { | |
390 previous = manager->TopControlsShownRatio(); | |
391 time = base::TimeDelta::FromMicroseconds(100) + time; | |
392 manager->Animate(time); | |
393 EXPECT_GT(manager->TopControlsShownRatio(), previous); | |
394 } | |
395 EXPECT_FALSE(manager->animation()); | |
396 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
397 } | |
398 | |
399 TEST(TopControlsManagerTest, HeightChangeMaintainsFullyVisibleControls) { | |
400 MockTopControlsManagerClient client(0.f, 0.5f, 0.5f); | |
401 TopControlsManager* manager = client.manager(); | |
402 | |
403 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
404 | |
405 client.SetTopControlsHeight(100.f); | |
406 EXPECT_FALSE(manager->animation()); | |
407 EXPECT_FLOAT_EQ(100.f, manager->TopControlsHeight()); | |
408 EXPECT_FLOAT_EQ(0, manager->ControlsTopOffset()); | |
409 | |
410 client.SetTopControlsHeight(50.f); | |
411 EXPECT_FALSE(manager->animation()); | |
412 EXPECT_FLOAT_EQ(50.f, manager->TopControlsHeight()); | |
413 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
414 } | |
415 | |
416 TEST(TopControlsManagerTest, GrowingHeightKeepsTopControlsHidden) { | |
417 MockTopControlsManagerClient client(0.f, 0.5f, 0.5f); | |
418 TopControlsManager* manager = client.manager(); | |
419 client.SetTopControlsHeight(1.f); | |
420 manager->UpdateTopControlsState(HIDDEN, HIDDEN, false); | |
421 EXPECT_EQ(-1.f, manager->ControlsTopOffset()); | |
422 EXPECT_EQ(0.f, manager->ContentTopOffset()); | |
423 | |
424 client.SetTopControlsHeight(50.f); | |
425 EXPECT_FALSE(manager->animation()); | |
426 EXPECT_EQ(-50.f, manager->ControlsTopOffset()); | |
427 EXPECT_EQ(0.f, manager->ContentTopOffset()); | |
428 | |
429 client.SetTopControlsHeight(100.f); | |
430 EXPECT_FALSE(manager->animation()); | |
431 EXPECT_EQ(-100.f, manager->ControlsTopOffset()); | |
432 EXPECT_EQ(0.f, manager->ContentTopOffset()); | |
433 } | |
434 | |
435 TEST(TopControlsManagerTest, ShrinkingHeightKeepsTopControlsHidden) { | |
436 MockTopControlsManagerClient client(100.f, 0.5f, 0.5f); | |
437 TopControlsManager* manager = client.manager(); | |
438 | |
439 manager->ScrollBegin(); | |
440 manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); | |
441 EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); | |
442 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
443 manager->ScrollEnd(); | |
444 | |
445 client.SetTopControlsHeight(50.f); | |
446 EXPECT_FALSE(manager->animation()); | |
447 EXPECT_FLOAT_EQ(-50.f, manager->ControlsTopOffset()); | |
448 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
449 | |
450 client.SetTopControlsHeight(0.f); | |
451 EXPECT_FALSE(manager->animation()); | |
452 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
453 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
454 } | |
455 | |
456 TEST(TopControlsManagerTest, ScrollByWithZeroHeightControlsIsNoop) { | |
457 MockTopControlsManagerClient client(0.f, 0.5f, 0.5f); | |
458 TopControlsManager* manager = client.manager(); | |
459 manager->UpdateTopControlsState(BOTH, BOTH, false); | |
460 | |
461 manager->ScrollBegin(); | |
462 gfx::Vector2dF pending = manager->ScrollBy(gfx::Vector2dF(0.f, 20.f)); | |
463 EXPECT_FLOAT_EQ(20.f, pending.y()); | |
464 EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); | |
465 EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); | |
466 EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio()); | |
467 manager->ScrollEnd(); | |
468 } | |
469 | |
470 | |
471 } // namespace | |
472 } // namespace cc | |
OLD | NEW |