summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h
blob: 37e14f2ee31b9d444414f8429aae8dcaabb04ed1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_ORIENTATION_LOCK_DELEGATE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_ORIENTATION_LOCK_DELEGATE_H_

#include "base/optional.h"
#include "services/device/public/mojom/screen_orientation.mojom-blink.h"
#include "third_party/blink/public/common/screen_orientation/web_screen_orientation_lock_type.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/wtf/time.h"

namespace blink {

class DeviceOrientationData;
class DeviceOrientationEvent;
class Document;
class HTMLVideoElement;

// MediaControlsOrientationLockDelegate is implementing the orientation lock
// feature when a <video> is fullscreen. It is meant to be created by
// `MediaControlsImpl` when the feature applies. Once created, it will use
// events to change state.
//
// The behavior depends on whether MediaControlsRotateToFullscreenDelegate is
// enabled. If it is enabled and the user has not locked the screen orientation
// at the OS level, then the orientation lock is only held until the user
// rotates their device to match the orientation of the video; otherwise it is
// held until fullscreen is exited.
//
// The different states of the class are:
// - PendingFullscreen: the object is created and it is either waiting for the
//   associated <video> to go fullscreen in order to apply an orientation lock,
//   or it already went fullscreen then the lock was unlocked since the user
//   rotated their device, and now it is waiting until fullscreen is re-entered;
// - PendingMetadata: the <video> is fullscreen but the metadata have not been
//   downloaded yet. It can happen because of network latency or because the
//   <video> went fullscreen before playback and download started;
// - MaybeLockedFullscreen: the <video> is fullscreen and a screen orientation
//   lock is applied.
//
// The possible state transitions are:
// - PendingFullscreen => PendingMetadata: on fullscreenchange event (entering
//   fullscreen) when metadata are not available;
// - PendingFullscreen => MaybeLockedFullscreen: on fullscreenchange event
//   (entering fullscreen) when metadata are available;
// - PendingMetadata => MaybeLockedFullscreen: on loadedmetadata;
// - PendingMetadata => PendingFullscreen: on fullscreenchange event (exiting
//   fullscreen);
// - MaybeLockedFullscreen => PendingFullscreen: on fullscreenchange event
//   (exiting fullscreen) or on deviceorientation event (rotated to match the
//   orientation of the video).
class MediaControlsOrientationLockDelegate final : public EventListener {
 public:
  explicit MediaControlsOrientationLockDelegate(HTMLVideoElement&);

  // Called by MediaControlsImpl when the HTMLMediaElement is added to a
  // document. All event listeners should be added.
  void Attach();

  // Called by MediaControlsImpl when the HTMLMediaElement is no longer in the
  // document. All event listeners should be removed in order to prepare the
  // object to be garbage collected.
  void Detach();

  // EventListener implementation.
  bool operator==(const EventListener&) const override;

  void Trace(blink::Visitor*) override;

 private:
  friend class MediaControlsOrientationLockDelegateTest;
  friend class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest;

  enum class State {
    kPendingFullscreen,
    kPendingMetadata,
    kMaybeLockedFullscreen,
  };

  enum class DeviceOrientationType {
    kUnknown,
    kFlat,
    kDiagonal,
    kPortrait,
    kLandscape
  };

  // EventListener implementation.
  void Invoke(ExecutionContext*, Event*) override;

  HTMLVideoElement& VideoElement() const;
  Document& GetDocument() const;

  // Returns the orientation in which the video should be locked based on its
  // size.
  MODULES_EXPORT WebScreenOrientationLockType ComputeOrientationLock() const;

  // Locks the screen orientation if the video has metadata information
  // available. Delays locking orientation until metadata are available
  // otherwise.
  void MaybeLockOrientation();

  // Changes a previously locked screen orientation to instead be locked to
  // the "any" orientation that allows accelerometer-based rotation. This is
  // not the same as unlocking (which returns to the "default" orientation,
  // which may in fact be more restrictive).
  void ChangeLockToAnyOrientation();

  // Unlocks the screen orientation if the screen orientation was previously
  // locked.
  void MaybeUnlockOrientation();

  void MaybeListenToDeviceOrientation();
  void GotIsAutoRotateEnabledByUser(bool enabled);

  MODULES_EXPORT DeviceOrientationType
  ComputeDeviceOrientation(DeviceOrientationData*) const;

  void MaybeLockToAnyIfDeviceOrientationMatchesVideo(DeviceOrientationEvent*);

  // Delay before `MaybeLockToAnyIfDeviceOrientationMatchesVideo` changes lock.
  // Emprically, 200ms is too short, but 250ms avoids glitches. 500ms gives us
  // a 2x margin in case the device is running slow, without being noticeable.
  MODULES_EXPORT static constexpr TimeDelta kLockToAnyDelay =
      TimeDelta::FromMilliseconds(500);

  // Current state of the object. See comment at the top of the file for a
  // detailed description.
  State state_ = State::kPendingFullscreen;

  // Which lock is currently applied by this delegate.
  WebScreenOrientationLockType locked_orientation_ =
      kWebScreenOrientationLockDefault /* unlocked */;

  TaskHandle lock_to_any_task_;

  device::mojom::blink::ScreenOrientationListenerPtr monitor_;

  base::Optional<bool> is_auto_rotate_enabled_by_user_override_for_testing_;

  // `video_element_` owns MediaControlsImpl that owns |this|.
  Member<HTMLVideoElement> video_element_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_ORIENTATION_LOCK_DELEGATE_H_