OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "MediaControlsOrientationLockDelegate.h" | |
6 | |
7 #include "core/events/Event.h" | |
8 #include "core/frame/ScreenOrientationController.h" | |
9 #include "core/html/HTMLVideoElement.h" | |
10 #include "core/page/ChromeClient.h" | |
11 #include "platform/Histogram.h" | |
12 #include "public/platform/WebScreenInfo.h" | |
13 #include "public/platform/modules/screen_orientation/WebLockOrientationCallback.
h" | |
14 | |
15 namespace blink { | |
16 | |
17 namespace { | |
18 | |
19 // These values are used for histograms. Do not reorder. | |
20 enum class MetadataAvailabilityMetrics { | |
21 Available = 0, // Available when lock was attempted. | |
22 Missing = 1, // Missing when lock was attempted. | |
23 Received = 2, // Received after being missing in order to lock. | |
24 | |
25 // Keep at the end. | |
26 Max = 3 | |
27 }; | |
28 | |
29 // These values are used for histograms. Do not reorder. | |
30 enum class LockResultMetrics { | |
31 AlreadyLocked = 0, // Frame already has a lock. | |
32 Portrait = 1, // Locked to portrait. | |
33 Landscape = 2, // Locked to landscape. | |
34 | |
35 // Keep at the end. | |
36 Max = 3 | |
37 }; | |
38 | |
39 void recordMetadataAvailability(MetadataAvailabilityMetrics metrics) { | |
40 DEFINE_STATIC_LOCAL( | |
41 EnumerationHistogram, metadataHistogram, | |
42 ("Media.Video.FullscreenOrientationLock.MetadataAvailability", | |
43 static_cast<int>(MetadataAvailabilityMetrics::Max))); | |
44 metadataHistogram.count(static_cast<int>(metrics)); | |
45 } | |
46 | |
47 void recordLockResult(LockResultMetrics metrics) { | |
48 DEFINE_STATIC_LOCAL(EnumerationHistogram, lockResultHistogram, | |
49 ("Media.Video.FullscreenOrientationLock.LockResult", | |
50 static_cast<int>(LockResultMetrics::Max))); | |
51 lockResultHistogram.count(static_cast<int>(metrics)); | |
52 } | |
53 | |
54 // WebLockOrientationCallback implementation that will not react to a success | |
55 // nor a failure. | |
56 class DummyScreenOrientationCallback : public WebLockOrientationCallback { | |
57 public: | |
58 void onSuccess() override {} | |
59 void onError(WebLockOrientationError) override {} | |
60 }; | |
61 | |
62 } // anonymous namespace | |
63 | |
64 MediaControlsOrientationLockDelegate::MediaControlsOrientationLockDelegate( | |
65 HTMLVideoElement& video) | |
66 : EventListener(CPPEventListenerType), m_videoElement(video) { | |
67 if (videoElement().isConnected()) | |
68 attach(); | |
69 } | |
70 | |
71 void MediaControlsOrientationLockDelegate::attach() { | |
72 DCHECK(videoElement().isConnected()); | |
73 | |
74 document().addEventListener(EventTypeNames::fullscreenchange, this, true); | |
75 videoElement().addEventListener(EventTypeNames::webkitfullscreenchange, this, | |
76 true); | |
77 videoElement().addEventListener(EventTypeNames::loadedmetadata, this, true); | |
78 } | |
79 | |
80 void MediaControlsOrientationLockDelegate::detach() { | |
81 DCHECK(!videoElement().isConnected()); | |
82 | |
83 document().removeEventListener(EventTypeNames::fullscreenchange, this, true); | |
84 videoElement().removeEventListener(EventTypeNames::webkitfullscreenchange, | |
85 this, true); | |
86 videoElement().removeEventListener(EventTypeNames::loadedmetadata, this, | |
87 true); | |
88 } | |
89 | |
90 bool MediaControlsOrientationLockDelegate::operator==( | |
91 const EventListener& other) const { | |
92 return this == &other; | |
93 } | |
94 | |
95 void MediaControlsOrientationLockDelegate::maybeLockOrientation() { | |
96 DCHECK(m_state != State::MaybeLockedFullscreen); | |
97 | |
98 if (videoElement().getReadyState() == HTMLMediaElement::kHaveNothing) { | |
99 recordMetadataAvailability(MetadataAvailabilityMetrics::Missing); | |
100 m_state = State::PendingMetadata; | |
101 return; | |
102 } | |
103 | |
104 if (m_state == State::PendingMetadata) | |
105 recordMetadataAvailability(MetadataAvailabilityMetrics::Received); | |
106 else | |
107 recordMetadataAvailability(MetadataAvailabilityMetrics::Available); | |
108 | |
109 m_state = State::MaybeLockedFullscreen; | |
110 | |
111 if (!document().frame()) | |
112 return; | |
113 | |
114 auto controller = ScreenOrientationController::from(*document().frame()); | |
115 if (controller->maybeHasActiveLock()) { | |
116 recordLockResult(LockResultMetrics::AlreadyLocked); | |
117 return; | |
118 } | |
119 | |
120 WebScreenOrientationLockType orientationLock = computeOrientationLock(); | |
121 controller->lock(orientationLock, | |
122 WTF::wrapUnique(new DummyScreenOrientationCallback)); | |
123 m_shouldUnlockOrientation = true; | |
124 | |
125 if (orientationLock == WebScreenOrientationLockLandscape) | |
126 recordLockResult(LockResultMetrics::Landscape); | |
127 else | |
128 recordLockResult(LockResultMetrics::Portrait); | |
129 } | |
130 | |
131 void MediaControlsOrientationLockDelegate::maybeUnlockOrientation() { | |
132 DCHECK(m_state != State::PendingFullscreen); | |
133 | |
134 m_state = State::PendingFullscreen; | |
135 | |
136 if (!m_shouldUnlockOrientation) | |
137 return; | |
138 | |
139 ScreenOrientationController::from(*document().frame())->unlock(); | |
140 m_shouldUnlockOrientation = false; | |
141 } | |
142 | |
143 HTMLVideoElement& MediaControlsOrientationLockDelegate::videoElement() const { | |
144 return *m_videoElement; | |
145 } | |
146 | |
147 Document& MediaControlsOrientationLockDelegate::document() const { | |
148 return videoElement().document(); | |
149 } | |
150 | |
151 void MediaControlsOrientationLockDelegate::handleEvent( | |
152 ExecutionContext* executionContext, | |
153 Event* event) { | |
154 if (event->type() == EventTypeNames::fullscreenchange || | |
155 event->type() == EventTypeNames::webkitfullscreenchange) { | |
156 if (videoElement().isFullscreen()) { | |
157 if (m_state == State::PendingFullscreen) | |
158 maybeLockOrientation(); | |
159 } else { | |
160 if (m_state != State::PendingFullscreen) | |
161 maybeUnlockOrientation(); | |
162 } | |
163 | |
164 return; | |
165 } | |
166 | |
167 if (event->type() == EventTypeNames::loadedmetadata) { | |
168 if (m_state == State::PendingMetadata) | |
169 maybeLockOrientation(); | |
170 | |
171 return; | |
172 } | |
173 | |
174 NOTREACHED(); | |
175 } | |
176 | |
177 WebScreenOrientationLockType | |
178 MediaControlsOrientationLockDelegate::computeOrientationLock() const { | |
179 DCHECK(videoElement().getReadyState() != HTMLMediaElement::kHaveNothing); | |
180 | |
181 const unsigned width = videoElement().videoWidth(); | |
182 const unsigned height = videoElement().videoHeight(); | |
183 | |
184 if (width > height) | |
185 return WebScreenOrientationLockLandscape; | |
186 | |
187 if (height > width) | |
188 return WebScreenOrientationLockPortrait; | |
189 | |
190 // For square videos, try to lock to the current screen orientation for | |
191 // consistency. Use WebScreenOrientationLockLandscape as a fallback value. | |
192 // TODO(mlamouri): we could improve this by having direct access to | |
193 // `window.screen.orientation.type`. | |
194 Frame* frame = document().frame(); | |
195 if (!frame) | |
196 return WebScreenOrientationLockLandscape; | |
197 | |
198 switch (frame->chromeClient().screenInfo().orientationType) { | |
199 case WebScreenOrientationPortraitPrimary: | |
200 case WebScreenOrientationPortraitSecondary: | |
201 return WebScreenOrientationLockPortrait; | |
202 case WebScreenOrientationLandscapePrimary: | |
203 case WebScreenOrientationLandscapeSecondary: | |
204 return WebScreenOrientationLockLandscape; | |
205 case WebScreenOrientationUndefined: | |
206 return WebScreenOrientationLockLandscape; | |
207 } | |
208 | |
209 NOTREACHED(); | |
210 return WebScreenOrientationLockLandscape; | |
211 } | |
212 | |
213 DEFINE_TRACE(MediaControlsOrientationLockDelegate) { | |
214 EventListener::trace(visitor); | |
215 visitor->trace(m_videoElement); | |
216 } | |
217 | |
218 } // namespace blink | |
OLD | NEW |