OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "config.h" | |
6 #include "core/html/AutoplayExperimentHelper.h" | |
7 | |
8 #include "core/dom/Document.h" | |
9 #include "core/frame/Settings.h" | |
10 #include "core/html/HTMLMediaElement.h" | |
11 #include "core/layout/LayoutBox.h" | |
12 #include "core/layout/LayoutObject.h" | |
13 #include "core/layout/LayoutVideo.h" | |
14 #include "core/layout/LayoutView.h" | |
15 #include "core/page/Page.h" | |
16 #include "platform/Logging.h" | |
17 #include "platform/UserGestureIndicator.h" | |
18 #include "platform/geometry/IntRect.h" | |
19 | |
20 namespace blink { | |
21 | |
22 using namespace HTMLNames; | |
23 | |
24 AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element) | |
25 : m_element(element) | |
26 , m_mode(AutoplayExperimentConfig::Mode::Off) | |
27 , m_playPending(false) | |
28 { | |
29 if (document().settings()) { | |
30 m_mode = AutoplayExperimentConfig::fromString(document().settings()->aut oplayExperimentMode()); | |
31 | |
32 if (m_mode != AutoplayExperimentConfig::Mode::Off) { | |
33 WTF_LOG(Media, "HTMLMediaElement: autoplay experiment set to %d", | |
34 m_mode); | |
35 } | |
36 } | |
37 } | |
38 | |
39 AutoplayExperimentHelper::~AutoplayExperimentHelper() | |
40 { | |
41 } | |
42 | |
43 void AutoplayExperimentHelper::becameReadyToPlay() | |
44 { | |
45 // Assuming that we're eligible to override the user gesture requirement, | |
46 // then play. | |
47 if (isEligible()) { | |
48 prepareToPlay(GesturelessPlaybackStartedByAutoplayFlagImmediately); | |
49 } | |
50 } | |
51 | |
52 void AutoplayExperimentHelper::playMethodCalled() | |
53 { | |
54 // Set the pending state, even if the play isn't going to be pending. | |
55 // Eligibility can change if, for example, the mute status changes. | |
56 // Having this set is okay. | |
57 m_playPending = true; | |
58 | |
59 if (!UserGestureIndicator::processingUserGesture()) { | |
60 | |
61 if (isEligible()) { | |
62 // Remember that userGestureRequiredForPlay is required for | |
63 // us to be eligible for the experiment. | |
64 // We are able to override the gesture requirement now, so | |
65 // do so. | |
66 prepareToPlay(GesturelessPlaybackStartedByPlayMethodImmediately); | |
67 } | |
68 | |
69 } | |
70 } | |
71 | |
72 void AutoplayExperimentHelper::pauseMethodCalled() | |
73 { | |
74 // Don't try to autoplay, if we would have. | |
75 m_playPending = false; | |
76 } | |
77 | |
78 void AutoplayExperimentHelper::mutedChanged() | |
79 { | |
80 // In other words, start playing if we just needed 'mute' to autoplay. | |
81 maybeStartPlaying(); | |
82 } | |
83 | |
84 bool AutoplayExperimentHelper::maybeStartPlaying() | |
85 { | |
86 // See if we're allowed to autoplay now. | |
87 if (!isEligible()) { | |
88 return false; | |
89 } | |
90 | |
91 // Start playing! | |
92 prepareToPlay(m_element.shouldAutoplay() | |
93 ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll | |
94 : GesturelessPlaybackStartedByPlayMethodAfterScroll); | |
95 m_element.playInternal(); | |
96 | |
97 return true; | |
98 } | |
99 | |
100 bool AutoplayExperimentHelper::isEligible() const | |
101 { | |
102 // If no user gesture is required, then the experiment doesn't apply. | |
103 // This is what prevents us from starting playback more than once. | |
104 // Since this flag is never set to true once it's cleared, it will block | |
105 // the autoplay experiment forever. | |
106 if (!m_element.isUserGestureRequiredForPlay()) | |
107 return false; | |
108 | |
109 if (m_mode == AutoplayExperimentConfig::Mode::Off) | |
110 return false; | |
111 | |
112 // Make sure that this is an element of the right type. | |
113 if (!enabled(AutoplayExperimentConfig::Mode::ForVideo) | |
114 && isHTMLVideoElement(m_element)) | |
115 return false; | |
116 | |
117 if (!enabled(AutoplayExperimentConfig::Mode::ForAudio) | |
118 && isHTMLAudioElement(m_element)) | |
119 return false; | |
120 | |
121 // If nobody has requested playback, either by the autoplay attribute or | |
122 // a play() call, then do nothing. | |
123 if (!m_playPending && !m_element.shouldAutoplay()) | |
124 return false; | |
125 | |
126 // If the video is already playing, then do nothing. Note that there | |
127 // is not a path where a user gesture is required but the video is | |
128 // playing. However, we check for completeness. | |
129 if (!m_element.paused()) | |
130 return false; | |
131 | |
132 // Note that the viewport test always returns false on desktop, which is | |
133 // why video-autoplay-experiment.html doesn't check -ifmobile . | |
134 if (enabled(AutoplayExperimentConfig::Mode::IfMobile) | |
135 && !document().viewportDescription().isLegacyViewportType()) | |
136 return false; | |
137 | |
138 // If media is muted, then autoplay when it comes into view. | |
philipj_slow
2015/09/04 09:24:27
This "when it comes into view" and other comments
liberato (no reviews please)
2015/09/08 21:58:01
done, and also this does the wrong thing. checkin
philipj_slow
2015/09/10 10:05:13
I can't see the change for this in PS28 either.
liberato (no reviews please)
2015/09/10 14:52:27
oh, bother. i inadvertently switched to the branc
| |
139 if (enabled(AutoplayExperimentConfig::Mode::IfMuted)) | |
140 return m_element.fastHasAttribute(mutedAttr) || m_element.muted(); | |
141 | |
142 // Autoplay when it comes into view (if needed), maybe muted. | |
143 return true; | |
144 } | |
145 | |
146 void AutoplayExperimentHelper::muteIfNeeded() | |
147 { | |
148 if (enabled(AutoplayExperimentConfig::Mode::PlayMuted)) { | |
149 ASSERT(!isEligible()); | |
150 // If we are actually changing the muted state, then this will call | |
151 // mutedChanged(). If isEligible(), then mutedChanged() will try | |
152 // to start playback, which we should not do here. | |
153 m_element.setMuted(true); | |
154 } | |
155 } | |
156 | |
157 void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric) | |
158 { | |
159 m_element.recordAutoplayMetric(metric); | |
160 | |
161 // This also causes !isEligible, so that we don't allow autoplay more than | |
162 // once. Be sure to do this before muteIfNeeded(). | |
163 m_element.removeUserGestureRequirement(); | |
164 | |
165 muteIfNeeded(); | |
166 | |
167 // Record that this autoplayed without a user gesture. This is normally | |
168 // set when we discover an autoplay attribute, but we include all cases | |
169 // where playback started without a user gesture, e.g., play(). | |
170 m_element.setInitialPlayWithoutUserGestures(true); | |
171 | |
172 // Do not actually start playback here. | |
173 } | |
174 | |
175 Document& AutoplayExperimentHelper::document() const | |
176 { | |
177 return m_element.document(); | |
178 } | |
179 | |
180 } | |
OLD | NEW |