Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(614)

Side by Side Diff: third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegateTest.cpp

Issue 2830713003: [Media controls] Add rotate-to-fullscreen gesture behind flag (Closed)
Patch Set: Address review comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "modules/media_controls/MediaControlsRotateToFullscreenDelegate.h"
6
7 #include "core/HTMLNames.h"
8 #include "core/css/CSSStyleDeclaration.h"
9 #include "core/dom/Document.h"
10 #include "core/dom/DocumentUserGestureToken.h"
11 #include "core/dom/Fullscreen.h"
12 #include "core/frame/FrameView.h"
13 #include "core/frame/LocalDOMWindow.h"
14 #include "core/frame/Settings.h"
15 #include "core/html/HTMLAudioElement.h"
16 #include "core/html/HTMLVideoElement.h"
17 #include "core/loader/EmptyClients.h"
18 #include "core/testing/DummyPageHolder.h"
19 #include "modules/media_controls/MediaControlsImpl.h"
20 #include "platform/UserGestureIndicator.h"
21 #include "platform/testing/EmptyWebMediaPlayer.h"
22 #include "platform/testing/UnitTestHelpers.h"
23 #include "platform/wtf/text/AtomicString.h"
24 #include "public/platform/WebSize.h"
25 #include "public/platform/modules/screen_orientation/WebScreenOrientationType.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using ::testing::Return;
30
31 namespace blink {
32
33 using namespace HTMLNames;
34
35 namespace {
36
37 class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer {
38 public:
39 // ChromeClient overrides:
40 bool HasVideo() const override { return true; }
41
42 MOCK_CONST_METHOD0(NaturalSize, WebSize());
43 };
44
45 class MockChromeClient : public EmptyChromeClient {
46 public:
47 // ChromeClient overrides:
48 void EnterFullscreen(LocalFrame& frame) override {
49 Fullscreen::From(*frame.GetDocument()).DidEnterFullscreen();
50 }
51 void ExitFullscreen(LocalFrame& frame) override {
52 Fullscreen::From(*frame.GetDocument()).DidExitFullscreen();
53 }
54
55 MOCK_CONST_METHOD0(GetScreenInfo, WebScreenInfo());
56 };
57
58 class StubLocalFrameClient : public EmptyLocalFrameClient {
59 public:
60 static StubLocalFrameClient* Create() { return new StubLocalFrameClient; }
61
62 std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
63 HTMLMediaElement&,
64 const WebMediaPlayerSource&,
65 WebMediaPlayerClient*) override {
66 return WTF::WrapUnique(new MockVideoWebMediaPlayer());
kinuko 2017/04/25 06:30:58 nit: please use MakeUnique instead
johnme 2017/04/27 15:57:48 Done (and also in MediaControlsOrientationLockDele
67 }
68 };
69
70 } // anonymous namespace
71
72 class MediaControlsRotateToFullscreenDelegateTest : public ::testing::Test {
73 protected:
74 using SimpleOrientation =
75 MediaControlsRotateToFullscreenDelegate::SimpleOrientation;
76
77 void SetUp() override {
78 previous_video_rotate_to_fullscreen_value_ =
79 RuntimeEnabledFeatures::videoRotateToFullscreenEnabled();
80 RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(true);
81
82 chrome_client_ = new MockChromeClient();
83
84 Page::PageClients clients;
85 FillWithEmptyClients(clients);
86 clients.chrome_client = chrome_client_.Get();
87
88 page_holder_ = DummyPageHolder::Create(IntSize(800, 600), &clients,
89 StubLocalFrameClient::Create());
90
91 video_ = HTMLVideoElement::Create(GetDocument());
92 GetVideo().setAttribute(controlsAttr, g_empty_atom);
93 // Most tests should call GetDocument().body()->AppendChild(&GetVideo());
94 // This is not done automatically, so that tests control timing of `Attach`.
95 }
96
97 void TearDown() override {
98 RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(
99 previous_video_rotate_to_fullscreen_value_);
100 }
101
102 static bool HasDelegate(const MediaControls& media_controls) {
103 return !!static_cast<const MediaControlsImpl*>(&media_controls)
104 ->rotate_to_fullscreen_delegate_;
105 }
106
107 static bool HasOrientationLockDelegate(const MediaControls& media_controls) {
108 return !!static_cast<const MediaControlsImpl*>(&media_controls)
109 ->orientation_lock_delegate_;
110 }
111
112 void SimulateVideoReadyState(HTMLMediaElement::ReadyState state) {
113 GetVideo().SetReadyState(state);
114 }
115
116 SimpleOrientation ObservedScreenOrientation() const {
117 return GetMediaControls()
118 .rotate_to_fullscreen_delegate_->current_screen_orientation_;
119 }
120
121 SimpleOrientation ComputeVideoOrientation() const {
122 return GetMediaControls()
123 .rotate_to_fullscreen_delegate_->ComputeVideoOrientation();
124 }
125
126 bool IsObservingVisibility() const {
127 return GetMediaControls()
128 .rotate_to_fullscreen_delegate_->visibility_observer_;
129 }
130
131 bool ObservedVisibility() const {
132 return GetMediaControls().rotate_to_fullscreen_delegate_->is_visible_;
133 }
134
135 void DisableControls() {
136 // If scripts are not enabled, controls will always be shown.
137 page_holder_->GetFrame().GetSettings()->SetScriptEnabled(true);
138
139 GetVideo().removeAttribute(controlsAttr);
140 }
141
142 void DispatchEvent(EventTarget& target, const AtomicString& type) {
143 target.DispatchEvent(Event::Create(type));
144 }
145
146 void InitScreenAndVideo(WebScreenOrientationType initial_screen_orientation,
147 WebSize video_size);
148
149 void PlayVideo();
150
151 void UpdateVisibilityObserver() {
152 // Let IntersectionObserver update.
153 GetDocument().View()->UpdateAllLifecyclePhases();
154 testing::RunPendingTasks();
155 }
156
157 void RotateTo(WebScreenOrientationType new_screen_orientation);
158
159 MockChromeClient& GetChromeClient() const { return *chrome_client_; }
160 LocalDOMWindow& GetWindow() const { return *GetDocument().domWindow(); }
161 Document& GetDocument() const { return page_holder_->GetDocument(); }
162 HTMLVideoElement& GetVideo() const { return *video_; }
163 MediaControlsImpl& GetMediaControls() const {
164 return *static_cast<MediaControlsImpl*>(GetVideo().GetMediaControls());
165 }
166 MockVideoWebMediaPlayer& GetWebMediaPlayer() const {
167 return *static_cast<MockVideoWebMediaPlayer*>(
168 GetVideo().GetWebMediaPlayer());
169 }
170
171 private:
172 bool previous_video_rotate_to_fullscreen_value_;
173 Persistent<MockChromeClient> chrome_client_;
174 std::unique_ptr<DummyPageHolder> page_holder_;
175 Persistent<HTMLVideoElement> video_;
176 };
177
178 void MediaControlsRotateToFullscreenDelegateTest::InitScreenAndVideo(
179 WebScreenOrientationType initial_screen_orientation,
180 WebSize video_size) {
181 // Set initial screen orientation (called by `Attach` during `AppendChild`).
182 WebScreenInfo screen_info;
183 screen_info.orientation_type = initial_screen_orientation;
184 EXPECT_CALL(GetChromeClient(), GetScreenInfo())
185 .Times(1)
186 .WillOnce(Return(screen_info));
187
188 // Set up the WebMediaPlayer instance.
189 GetDocument().body()->AppendChild(&GetVideo());
190 GetVideo().SetSrc("https://example.com");
191 testing::RunPendingTasks();
192 SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
193
194 // Set video size.
195 EXPECT_CALL(GetWebMediaPlayer(), NaturalSize())
196 .WillRepeatedly(Return(video_size));
197 }
198
199 void MediaControlsRotateToFullscreenDelegateTest::PlayVideo() {
200 {
201 UserGestureIndicator gesture(
202 DocumentUserGestureToken::Create(&GetDocument()));
203 GetVideo().Play();
204 }
205 testing::RunPendingTasks();
206 }
207
208 void MediaControlsRotateToFullscreenDelegateTest::RotateTo(
209 WebScreenOrientationType new_screen_orientation) {
210 WebScreenInfo screen_info;
211 screen_info.orientation_type = new_screen_orientation;
212 EXPECT_CALL(GetChromeClient(), GetScreenInfo())
213 .Times(1)
214 .WillOnce(Return(screen_info));
215 DispatchEvent(GetWindow(), EventTypeNames::orientationchange);
216 testing::RunPendingTasks();
217 }
218
219 TEST_F(MediaControlsRotateToFullscreenDelegateTest, DelegateRequiresFlag) {
220 // SetUp turns the flag on by default.
221 GetDocument().body()->AppendChild(&GetVideo());
222 EXPECT_TRUE(HasDelegate(GetMediaControls()));
223
224 // No delegate when flag is off.
225 RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(false);
226 HTMLVideoElement* video = HTMLVideoElement::Create(GetDocument());
227 GetDocument().body()->AppendChild(video);
228 EXPECT_FALSE(HasDelegate(*video->GetMediaControls()));
229 }
230
231 TEST_F(MediaControlsRotateToFullscreenDelegateTest, DelegateRequiresVideo) {
232 HTMLAudioElement* audio = HTMLAudioElement::Create(GetDocument());
233 GetDocument().body()->AppendChild(audio);
234 EXPECT_FALSE(HasDelegate(*audio->GetMediaControls()));
235 }
236
237 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
238 OrientationLockIsMutuallyExclusive) {
239 // Rotate to fullscreen and fullscreen orientation lock are currently
240 // incompatible, so if both are enabled only one should be active.
241 RuntimeEnabledFeatures::setVideoRotateToFullscreenEnabled(true);
242 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(true);
243 HTMLVideoElement* video = HTMLVideoElement::Create(GetDocument());
244 GetDocument().body()->AppendChild(video);
245 EXPECT_TRUE(HasDelegate(*video->GetMediaControls()));
246 EXPECT_FALSE(HasOrientationLockDelegate(*video->GetMediaControls()));
247 }
248
249 TEST_F(MediaControlsRotateToFullscreenDelegateTest, ComputeVideoOrientation) {
250 // Set up the WebMediaPlayer instance.
251 GetDocument().body()->AppendChild(&GetVideo());
252 GetVideo().SetSrc("https://example.com");
253 testing::RunPendingTasks();
254
255 // Each `ComputeVideoOrientation` calls `NaturalSize` twice, except the first
256 // one where the video is not yet ready.
257 EXPECT_CALL(GetWebMediaPlayer(), NaturalSize())
258 .Times(12)
259 .WillOnce(Return(WebSize(400, 400)))
260 .WillOnce(Return(WebSize(400, 400)))
261 .WillOnce(Return(WebSize(300, 200)))
262 .WillOnce(Return(WebSize(300, 200)))
263 .WillOnce(Return(WebSize(200, 300)))
264 .WillOnce(Return(WebSize(200, 300)))
265 .WillOnce(Return(WebSize(300, 199)))
266 .WillOnce(Return(WebSize(300, 199)))
267 .WillOnce(Return(WebSize(199, 300)))
268 .WillOnce(Return(WebSize(199, 300)))
269 .WillOnce(Return(WebSize(0, 0)))
270 .WillOnce(Return(WebSize(0, 0)));
271
272 // Video is not yet ready.
273 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
274
275 SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
276
277 // 400x400 is square.
278 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
279 // 300x200 is landscape.
280 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
281 // 200x300 is portrait.
282 EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation());
283 // 300x199 is too small.
284 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
285 // 199x300 is too small.
286 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
287 // 0x0 is empty.
288 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
289 }
290
291 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
292 OnlyObserveVisibilityWhenPlaying) {
293 // Should not initially be observing visibility.
294 GetDocument().body()->AppendChild(&GetVideo());
295 EXPECT_FALSE(IsObservingVisibility());
296
297 // Should start observing visibility when played.
298 {
299 UserGestureIndicator gesture(
300 DocumentUserGestureToken::Create(&GetDocument()));
301 GetVideo().Play();
302 }
303 testing::RunPendingTasks();
304 EXPECT_TRUE(IsObservingVisibility());
305 EXPECT_FALSE(ObservedVisibility());
306
307 // Should have observed visibility once compositor updates.
308 GetDocument().View()->UpdateAllLifecyclePhases();
309 testing::RunPendingTasks();
310 EXPECT_TRUE(ObservedVisibility());
311
312 // Should stop observing visibility when paused.
313 GetVideo().pause();
314 testing::RunPendingTasks();
315 EXPECT_FALSE(IsObservingVisibility());
316 EXPECT_FALSE(ObservedVisibility());
317
318 // Should resume observing visibility when playback resumes.
319 {
320 UserGestureIndicator gesture(
321 DocumentUserGestureToken::Create(&GetDocument()));
322 GetVideo().Play();
323 }
324 testing::RunPendingTasks();
325 EXPECT_TRUE(IsObservingVisibility());
326 EXPECT_FALSE(ObservedVisibility());
327
328 // Should have observed visibility once compositor updates.
329 GetDocument().View()->UpdateAllLifecyclePhases();
330 testing::RunPendingTasks();
331 EXPECT_TRUE(ObservedVisibility());
332 }
333
334 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
335 EnterSuccessPortraitInlineToLandscapeFullscreen) {
336 // Portrait screen, landscape video.
337 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480));
338 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
339 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
340
341 // Play video.
342 PlayVideo();
343 UpdateVisibilityObserver();
344
345 EXPECT_TRUE(ObservedVisibility());
346 EXPECT_FALSE(GetVideo().IsFullscreen());
347
348 // Rotate screen to landscape.
349 RotateTo(kWebScreenOrientationLandscapePrimary);
350
351 // Should enter fullscreen.
352 EXPECT_TRUE(GetVideo().IsFullscreen());
353 }
354
355 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
356 EnterSuccessLandscapeInlineToPortraitFullscreen) {
357 // Landscape screen, portrait video.
358 InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(480, 640));
359 EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation());
360 EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation());
361
362 // Play video.
363 PlayVideo();
364 UpdateVisibilityObserver();
365
366 EXPECT_TRUE(ObservedVisibility());
367 EXPECT_FALSE(GetVideo().IsFullscreen());
368
369 // Rotate screen to portrait.
370 RotateTo(kWebScreenOrientationPortraitPrimary);
371
372 // Should enter fullscreen.
373 EXPECT_TRUE(GetVideo().IsFullscreen());
374 }
375
376 TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailNoControls) {
377 DisableControls();
378
379 // Portrait screen, landscape video.
380 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480));
381 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
382 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
383
384 // Play video.
385 PlayVideo();
386 UpdateVisibilityObserver();
387
388 EXPECT_TRUE(ObservedVisibility());
389
390 // Rotate screen to landscape.
391 RotateTo(kWebScreenOrientationLandscapePrimary);
392
393 // Should not enter fullscreen since video has no controls.
394 EXPECT_FALSE(GetVideo().IsFullscreen());
395 }
396
397 TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailPaused) {
398 // Portrait screen, landscape video.
399 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480));
400 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
401 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
402
403 EXPECT_FALSE(ObservedVisibility());
404
405 UpdateVisibilityObserver();
406
407 EXPECT_FALSE(ObservedVisibility());
408
409 // Rotate screen to landscape.
410 RotateTo(kWebScreenOrientationLandscapePrimary);
411
412 // Should not enter fullscreen since video is paused.
413 EXPECT_FALSE(GetVideo().IsFullscreen());
414 }
415
416 TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailHidden) {
417 // Portrait screen, landscape video.
418 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480));
419 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
420 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
421
422 // Play video.
423 PlayVideo();
424 UpdateVisibilityObserver();
425
426 EXPECT_TRUE(ObservedVisibility());
427
428 // Move video offscreen.
429 GetDocument().body()->style()->setProperty("margin-top", "-999px", "",
430 ASSERT_NO_EXCEPTION);
431
432 UpdateVisibilityObserver();
433
434 EXPECT_FALSE(ObservedVisibility());
435
436 // Rotate screen to landscape.
437 RotateTo(kWebScreenOrientationLandscapePrimary);
438
439 // Should not enter fullscreen since video is not visible.
440 EXPECT_FALSE(GetVideo().IsFullscreen());
441 }
442
443 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
444 EnterFail180DegreeRotation) {
445 // Landscape screen, landscape video.
446 InitScreenAndVideo(kWebScreenOrientationLandscapeSecondary,
447 WebSize(640, 480));
448 EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation());
449 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
450
451 // Play video.
452 PlayVideo();
453 UpdateVisibilityObserver();
454
455 EXPECT_TRUE(ObservedVisibility());
456
457 // Rotate screen 180 degrees to the opposite landscape (without passing via a
458 // portrait orientation).
459 RotateTo(kWebScreenOrientationLandscapePrimary);
460
461 // Should not enter fullscreen since this is a 180 degree orientation.
462 EXPECT_FALSE(GetVideo().IsFullscreen());
463 }
464
465 TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailSquare) {
466 // Portrait screen, square video.
467 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(400, 400));
468 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
469 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
470
471 // Play video.
472 PlayVideo();
473 UpdateVisibilityObserver();
474
475 EXPECT_TRUE(ObservedVisibility());
476
477 // Rotate screen to landscape.
478 RotateTo(kWebScreenOrientationLandscapePrimary);
479
480 // Should not enter fullscreen since video is square.
481 EXPECT_FALSE(GetVideo().IsFullscreen());
482 }
483
484 TEST_F(MediaControlsRotateToFullscreenDelegateTest, EnterFailSmall) {
485 // Portrait screen, small landscape video.
486 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(300, 199));
487 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
488 EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
489
490 // Play video.
491 PlayVideo();
492 UpdateVisibilityObserver();
493
494 EXPECT_TRUE(ObservedVisibility());
495
496 // Rotate screen to landscape.
497 RotateTo(kWebScreenOrientationLandscapePrimary);
498
499 // Should not enter fullscreen since video is too small.
500 EXPECT_FALSE(GetVideo().IsFullscreen());
501 }
502
503 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
504 ExitSuccessLandscapeFullscreenToPortraitInline) {
505 // Landscape screen, landscape video.
506 InitScreenAndVideo(kWebScreenOrientationLandscapePrimary, WebSize(640, 480));
507 EXPECT_EQ(SimpleOrientation::kLandscape, ObservedScreenOrientation());
508 EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
509
510 // Start in fullscreen.
511 {
512 UserGestureIndicator gesture(
513 DocumentUserGestureToken::Create(&GetDocument()));
514 GetMediaControls().EnterFullscreen();
515 }
516 testing::RunPendingTasks();
517 EXPECT_TRUE(GetVideo().IsFullscreen());
518
519 // Leave video paused (playing is not a requirement to exit fullscreen).
520 EXPECT_TRUE(GetVideo().paused());
521 EXPECT_FALSE(ObservedVisibility());
522
523 // Rotate screen to portrait.
524 RotateTo(kWebScreenOrientationPortraitPrimary);
525
526 // Should exit fullscreen.
527 EXPECT_FALSE(GetVideo().IsFullscreen());
528 }
529
530 TEST_F(MediaControlsRotateToFullscreenDelegateTest,
531 ExitSuccessPortraitFullscreenToLandscapeInline) {
532 // Portrait screen, portrait video.
533 InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(480, 640));
534 EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
535 EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation());
536
537 // Start in fullscreen.
538 {
539 UserGestureIndicator gesture(
540 DocumentUserGestureToken::Create(&GetDocument()));
541 GetMediaControls().EnterFullscreen();
542 }
543 testing::RunPendingTasks();
544 EXPECT_TRUE(GetVideo().IsFullscreen());
545
546 // Leave video paused (playing is not a requirement to exit fullscreen).
547 EXPECT_TRUE(GetVideo().paused());
548 EXPECT_FALSE(ObservedVisibility());
549
550 // Rotate screen to landscape.
551 RotateTo(kWebScreenOrientationLandscapePrimary);
552
553 // Should exit fullscreen.
554 EXPECT_FALSE(GetVideo().IsFullscreen());
555 }
556
557 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698