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

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

Issue 2904263002: [Media Controls] Tests for rotate-to-fullscreen meets orientation lock (Closed)
Patch Set: Fix MSVC warning Created 3 years, 6 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "modules/media_controls/MediaControlsOrientationLockDelegate.h" 5 #include "modules/media_controls/MediaControlsOrientationLockDelegate.h"
6 6
7 #include "core/events/Event.h" 7 #include "core/events/Event.h"
8 #include "core/frame/LocalDOMWindow.h" 8 #include "core/frame/LocalDOMWindow.h"
9 #include "core/frame/Screen.h" 9 #include "core/frame/Screen.h"
10 #include "core/frame/ScreenOrientationController.h" 10 #include "core/frame/ScreenOrientationController.h"
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 // If the rotate-to-fullscreen feature is also enabled, then start listening 177 // If the rotate-to-fullscreen feature is also enabled, then start listening
178 // to deviceorientation events so the orientation can be unlocked once the 178 // to deviceorientation events so the orientation can be unlocked once the
179 // user rotates the device to match the video's orientation (allowing the user 179 // user rotates the device to match the video's orientation (allowing the user
180 // to then exit fullscreen by rotating their device back to the opposite 180 // to then exit fullscreen by rotating their device back to the opposite
181 // orientation). Otherwise, don't listen for deviceorientation events and just 181 // orientation). Otherwise, don't listen for deviceorientation events and just
182 // hold the orientation lock until the user exits fullscreen (which prevents 182 // hold the orientation lock until the user exits fullscreen (which prevents
183 // the user rotating to the wrong fullscreen orientation). 183 // the user rotating to the wrong fullscreen orientation).
184 if (!RuntimeEnabledFeatures::VideoRotateToFullscreenEnabled()) 184 if (!RuntimeEnabledFeatures::VideoRotateToFullscreenEnabled())
185 return; 185 return;
186 186
187 if (is_auto_rotate_enabled_by_user_override_for_testing_ != WTF::nullopt) {
188 GotIsAutoRotateEnabledByUser(
189 is_auto_rotate_enabled_by_user_override_for_testing_.value());
190 return;
191 }
192
187 // Check whether the user locked screen orientation at the OS level. 193 // Check whether the user locked screen orientation at the OS level.
188 #if OS(ANDROID) 194 #if OS(ANDROID)
189 DCHECK(!monitor_.is_bound()); 195 DCHECK(!monitor_.is_bound());
190 Platform::Current()->GetConnector()->BindInterface( 196 Platform::Current()->GetConnector()->BindInterface(
191 device::mojom::blink::kServiceName, mojo::MakeRequest(&monitor_)); 197 device::mojom::blink::kServiceName, mojo::MakeRequest(&monitor_));
192 monitor_->IsAutoRotateEnabledByUser(ConvertToBaseCallback(WTF::Bind( 198 monitor_->IsAutoRotateEnabledByUser(ConvertToBaseCallback(WTF::Bind(
193 &MediaControlsOrientationLockDelegate::GotIsAutoRotateEnabledByUser, 199 &MediaControlsOrientationLockDelegate::GotIsAutoRotateEnabledByUser,
194 WrapPersistent(this)))); 200 WrapPersistent(this))));
195 #else 201 #else
196 GotIsAutoRotateEnabledByUser(true); // Assume always enabled on other OSes. 202 GotIsAutoRotateEnabledByUser(true); // Assume always enabled on other OSes.
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 case kWebScreenOrientationLandscapeSecondary: 296 case kWebScreenOrientationLandscapeSecondary:
291 return kWebScreenOrientationLockLandscape; 297 return kWebScreenOrientationLockLandscape;
292 case kWebScreenOrientationUndefined: 298 case kWebScreenOrientationUndefined:
293 return kWebScreenOrientationLockLandscape; 299 return kWebScreenOrientationLockLandscape;
294 } 300 }
295 301
296 NOTREACHED(); 302 NOTREACHED();
297 return kWebScreenOrientationLockLandscape; 303 return kWebScreenOrientationLockLandscape;
298 } 304 }
299 305
300 void MediaControlsOrientationLockDelegate:: 306 MediaControlsOrientationLockDelegate::DeviceOrientationType
301 MaybeUnlockIfDeviceOrientationMatchesVideo(DeviceOrientationEvent* event) { 307 MediaControlsOrientationLockDelegate::ComputeDeviceOrientation(
302 DCHECK_EQ(state_, State::kMaybeLockedFullscreen); 308 DeviceOrientationData* data) const {
303 DCHECK_NE(locked_orientation_, kWebScreenOrientationLockDefault);
304
305 LocalDOMWindow* dom_window = GetDocument().domWindow(); 309 LocalDOMWindow* dom_window = GetDocument().domWindow();
306 if (!dom_window) 310 if (!dom_window)
307 return; 311 return DeviceOrientationType::kUnknown;
308 312
309 if (!event->Orientation()->CanProvideBeta() || 313 if (!data->CanProvideBeta() || !data->CanProvideGamma())
310 !event->Orientation()->CanProvideGamma()) { 314 return DeviceOrientationType::kUnknown;
311 return; 315 double beta = data->Beta();
312 } 316 double gamma = data->Gamma();
313 double beta = event->Orientation()->Beta();
314 double gamma = event->Orientation()->Gamma();
315 317
316 // Calculate the projection of the up vector (normal to the earth's surface) 318 // Calculate the projection of the up vector (normal to the earth's surface)
317 // onto the device's screen in its natural orientation. (x,y) will lie within 319 // onto the device's screen in its natural orientation. (x,y) will lie within
318 // the unit circle centered on (0,0), e.g. if the top of the device is 320 // the unit circle centered on (0,0), e.g. if the top of the device is
319 // pointing upwards (x,y) will be (0,-1). 321 // pointing upwards (x,y) will be (0,-1).
320 double x = -std::sin(deg2rad(gamma)) * std::cos(deg2rad(beta)); 322 double x = -std::sin(deg2rad(gamma)) * std::cos(deg2rad(beta));
321 double y = -std::sin(deg2rad(beta)); 323 double y = -std::sin(deg2rad(beta));
322 324
323 // Convert (x,y) to polar coordinates: 0 <= device_orientation_angle < 360 and 325 // Convert (x,y) to polar coordinates: 0 <= device_orientation_angle < 360 and
324 // 0 <= r <= 1, such that device_orientation_angle is the clockwise angle in 326 // 0 <= r <= 1, such that device_orientation_angle is the clockwise angle in
325 // degrees between the current physical orientation of the device and the 327 // degrees between the current physical orientation of the device and the
326 // natural physical orientation of the device (ignoring the screen 328 // natural physical orientation of the device (ignoring the screen
327 // orientation). Thus snapping device_orientation_angle to the nearest 329 // orientation). Thus snapping device_orientation_angle to the nearest
328 // multiple of 90 gives the value screen.orientation.angle would have if the 330 // multiple of 90 gives the value screen.orientation.angle would have if the
329 // screen orientation was allowed to rotate freely to match the device 331 // screen orientation was allowed to rotate freely to match the device
330 // orientation. Note that we want device_orientation_angle==0 when the top of 332 // orientation. Note that we want device_orientation_angle==0 when the top of
331 // the device is pointing upwards, but atan2's zero angle points to the right, 333 // the device is pointing upwards, but atan2's zero angle points to the right,
332 // so we pass y=x and x=-y to atan2 to rotate by 90 degrees. 334 // so we pass y=x and x=-y to atan2 to rotate by 90 degrees.
333 double r = std::sqrt(x * x + y * y); 335 double r = std::sqrt(x * x + y * y);
334 double device_orientation_angle = 336 double device_orientation_angle =
335 std::fmod(rad2deg(std::atan2(/* y= */ x, /* x= */ -y)) + 360, 360); 337 std::fmod(rad2deg(std::atan2(/* y= */ x, /* x= */ -y)) + 360, 360);
336 338
339 // If angle between device's screen and the horizontal plane is less than
340 // kMinElevationAngle (chosen to approximately match Android's behavior), then
341 // device is too flat to reliably determine orientation.
337 constexpr double kMinElevationAngle = 24; // degrees from horizontal plane 342 constexpr double kMinElevationAngle = 24; // degrees from horizontal plane
338 if (r < std::sin(deg2rad(kMinElevationAngle))) 343 if (r < std::sin(deg2rad(kMinElevationAngle)))
339 return; // Device is too flat to reliably determine orientation. 344 return DeviceOrientationType::kFlat;
340 345
341 // device_orientation_angle snapped to nearest multiple of 90. 346 // device_orientation_angle snapped to nearest multiple of 90.
342 int device_orientation_angle90 = 347 int device_orientation_angle90 =
343 std::lround(device_orientation_angle / 90) * 90; 348 std::lround(device_orientation_angle / 90) * 90;
344 349
345 if (std::abs(device_orientation_angle - device_orientation_angle90) > 23) { 350 // To be considered portrait or landscape, allow the device to be rotated 23
346 // Device is diagonal (within 44 degree hysteresis zone). 351 // degrees (chosen to approximately match Android's behavior) to either side
347 return; 352 // of those orientations. In the remaining 90 - 2*23 = 44 degree hysteresis
348 } 353 // zones, consider the device to be diagonal. These hysteresis zones prevent
354 // the computed orientation from oscillating rapidly between portrait and
355 // landscape when the device is in between the two orientations.
356 if (std::abs(device_orientation_angle - device_orientation_angle90) > 23)
357 return DeviceOrientationType::kDiagonal;
349 358
350 // screen.orientation.angle is the standardized replacement for 359 // screen.orientation.angle is the standardized replacement for
351 // window.orientation. They are equal, except -90 was replaced by 270. 360 // window.orientation. They are equal, except -90 was replaced by 270.
352 int screen_orientation_angle = 361 int screen_orientation_angle =
353 ScreenScreenOrientation::orientation(nullptr /* ScriptState */, 362 ScreenScreenOrientation::orientation(nullptr /* ScriptState */,
354 *dom_window->screen()) 363 *dom_window->screen())
355 ->angle(); 364 ->angle();
356 365
357 // This is equivalent to screen.orientation.type.startsWith('landscape'). 366 // This is equivalent to screen.orientation.type.startsWith('landscape').
358 bool screen_orientation_is_landscape = 367 bool screen_orientation_is_portrait =
359 dom_window->screen()->width() > dom_window->screen()->height(); 368 dom_window->screen()->width() <= dom_window->screen()->height();
360 369
361 // The natural orientation of the device could either be portrait (almost 370 // The natural orientation of the device could either be portrait (almost
362 // all phones, and some tablets like Nexus 7) or landscape (other tablets 371 // all phones, and some tablets like Nexus 7) or landscape (other tablets
363 // like Pixel C). Detect this by comparing angle to orientation. 372 // like Pixel C). Detect this by comparing angle to orientation.
364 // TODO(johnme): This might get confused on square screens. 373 // TODO(johnme): This might get confused on square screens.
365 bool screen_orientation_is_natural_or_flipped_natural = 374 bool screen_orientation_is_natural_or_flipped_natural =
366 screen_orientation_angle % 180 == 0; 375 screen_orientation_angle % 180 == 0;
367 bool natural_orientation_is_landscape = 376 bool natural_orientation_is_portrait =
368 screen_orientation_is_landscape == 377 screen_orientation_is_portrait ==
369 screen_orientation_is_natural_or_flipped_natural; 378 screen_orientation_is_natural_or_flipped_natural;
370 379
371 bool natural_orientation_matches_video = 380 // If natural_orientation_is_portrait_, then angles 0 and 180 are portrait,
372 natural_orientation_is_landscape == 381 // otherwise angles 90 and 270 are portrait.
373 (locked_orientation_ == kWebScreenOrientationLockLandscape); 382 int portrait_angle_mod_180 = natural_orientation_is_portrait ? 0 : 90;
383 return device_orientation_angle90 % 180 == portrait_angle_mod_180
384 ? DeviceOrientationType::kPortrait
385 : DeviceOrientationType::kLandscape;
386 }
374 387
375 // If natural_orientation_matches_video, then 0 and 180 match video, otherwise 388 void MediaControlsOrientationLockDelegate::
376 // 90 and 270 match video. 389 MaybeUnlockIfDeviceOrientationMatchesVideo(DeviceOrientationEvent* event) {
377 bool device_orientation_matches_video = 390 DCHECK_EQ(state_, State::kMaybeLockedFullscreen);
378 (device_orientation_angle90 % 180) == 391 DCHECK(locked_orientation_ == kWebScreenOrientationLockPortrait ||
379 (natural_orientation_matches_video ? 0 : 90); 392 locked_orientation_ == kWebScreenOrientationLockLandscape);
380 393
381 if (!device_orientation_matches_video) 394 DeviceOrientationType device_orientation =
395 ComputeDeviceOrientation(event->Orientation());
396
397 DeviceOrientationType video_orientation =
398 locked_orientation_ == kWebScreenOrientationLockPortrait
399 ? DeviceOrientationType::kPortrait
400 : DeviceOrientationType::kLandscape;
401
402 if (device_orientation != video_orientation)
382 return; 403 return;
383 404
384 // Job done: the user rotated their device to match the orientation of the 405 // Job done: the user rotated their device to match the orientation of the
385 // video that we locked to, so now we can unlock (and stop listening). 406 // video that we locked to, so now we can unlock (and stop listening).
386 MaybeUnlockOrientation(); 407 MaybeUnlockOrientation();
387 } 408 }
388 409
389 DEFINE_TRACE(MediaControlsOrientationLockDelegate) { 410 DEFINE_TRACE(MediaControlsOrientationLockDelegate) {
390 EventListener::Trace(visitor); 411 EventListener::Trace(visitor);
391 visitor->Trace(video_element_); 412 visitor->Trace(video_element_);
392 } 413 }
393 414
394 } // namespace blink 415 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698