summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.h
blob: c8c1ab9c8698595ddabf602214f7e509acff8030 (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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright 2017 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_CORE_HTML_MEDIA_AUTOPLAY_POLICY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_AUTOPLAY_POLICY_H_

#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/heap/handle.h"

namespace blink {

class AutoplayUmaHelper;
class Document;
class ElementVisibilityObserver;
class HTMLMediaElement;

// AutoplayPolicy is the class for handles autoplay logics.
class AutoplayPolicy final : public GarbageCollected<AutoplayPolicy> {
 public:
  // Different autoplay policy types.
  enum class Type {
    kNoUserGestureRequired = 0,
    // A local user gesture on the element is required.
    kUserGestureRequired,
    // A local user gesture on the element is required when it is in a cross
    // origin iframe.
    kUserGestureRequiredForCrossOrigin,
    // The document needs to have received a user activation or received one
    // before navigating.
    kDocumentUserActivationRequired,
  };

  CORE_EXPORT static Type GetAutoplayPolicyForDocument(const Document&);

  // Return true if the given |document| is allowed to play.
  // This method may check parent frames if allow=autoplay (Feature Policy) was
  // used, in which case, the frame will be allowed to play if its parents are,
  // and so on.
  // Otherwise, frames are allowed to play if they have been activated or, for
  // the main frame, if it has a high MEI.
  CORE_EXPORT static bool IsDocumentAllowedToPlay(const Document&);

  // Returns true if the given |document| has high media engagement.
  static bool DocumentHasHighMediaEngagement(const Document&);

  // Returns true if the given |document| should force allow autoplay.
  static bool DocumentHasForceAllowFlag(const Document&);

  // Returns true if the given |document| has the user exception flag.
  static bool DocumentHasUserExceptionFlag(const Document&);

  // Returns true if the given |document| should autoplay muted videos.
  static bool DocumentShouldAutoplayMutedVideos(const Document&);

  explicit AutoplayPolicy(HTMLMediaElement*);

  void VideoWillBeDrawnToCanvas() const;

  // Called when the media element is moved to a new document.
  void DidMoveToNewDocument(Document& old_document);

  // Stop autoplaying the video element whenever its visible.
  // TODO(mlamouri): hide these methods from HTMLMediaElement.
  void StopAutoplayMutedWhenVisible();

  // Request autoplay by attribute. This method will check the autoplay
  // restrictions and record metrics. This method can only be called once per
  // time the readyState changes to HAVE_ENOUGH_DATA.
  bool RequestAutoplayByAttribute();

  // Request the playback via play() method. This method will check the autoplay
  // restrictions and record metrics. This method can only be called once
  // per call of play().
  base::Optional<DOMExceptionCode> RequestPlay();

  // Returns whether an umute action should pause an autoplaying element. The
  // method will check autoplay restrictions and record metrics. This method can
  // only be called once per call of setMuted().
  bool RequestAutoplayUnmute();

  // Indicates the media element is or will autoplay because of being
  // muted.
  CORE_EXPORT bool IsOrWillBeAutoplayingMuted() const;

  // Unlock user gesture if a user gesture can be utilized.
  void TryUnlockingUserGesture();

  // Return true if and only if a user gesture is requried for playback.  Even
  // if isLockedPendingUserGesture() return true, this might return false if
  // the requirement is currently overridden.  This does not check if a user
  // gesture is currently being processed.
  bool IsGestureNeededForPlayback() const;

  // Returns an error string to be used by the HTMLMediaElement when the play()
  // method fails because of autoplay restrictions.
  String GetPlayErrorMessage() const;

  // Returns whether the media element was initiated via autoplay.
  // In this context, autoplay means that it was initiated before any user
  // activation was received on the page and before a user initiated same-domain
  // navigation. In other words, with the unified autoplay policy applied, it
  // should only return `true` when MEI allowed autoplay.
  bool WasAutoplayInitiated() const;

  // Ensure that `autoplay_initiated_` has a value. It is set to `false` to
  // avoid false positives.
  void EnsureAutoplayInitiatedSet();

  virtual void Trace(blink::Visitor*);

 private:
  friend class AutoplayUmaHelper;
  friend class AutoplayUmaHelperTest;

  // Start autoplaying the video element whenever its visible.
  void StartAutoplayMutedWhenVisible();

  // Returns whether the media element is eligible to autoplay muted.
  bool IsEligibleForAutoplayMuted() const;

  bool ShouldAutoplay();

  // If the user gesture is required, then this will remove it.  Note that
  // one should not generally call this method directly; use the one on
  // m_helper and give it a reason.
  void UnlockUserGesture();

  // Return true if and only if a user gesture is required to unlock this
  // media element for unrestricted autoplay/script control.  Don't confuse
  // this with isGestureNeededForPlayback().  The latter is usually what one
  // should use, if checking to see if an action is allowed.
  bool IsLockedPendingUserGesture() const;

  bool IsLockedPendingUserGestureIfCrossOriginExperimentEnabled() const;

  bool IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled() const;

  bool IsGestureNeededForPlaybackIfPendingUserGestureIsLocked() const;

  // Return true if and only if the settings allow autoplay of media on this
  // frame.
  bool IsAutoplayAllowedPerSettings() const;

  bool IsAutoplayingMutedInternal(bool muted) const;
  bool IsOrWillBeAutoplayingMutedInternal(bool muted) const;

  // Called when the video visibility changes while autoplaying muted, will
  // pause the video when invisible and resume the video when visible.
  void OnVisibilityChangedForAutoplay(bool is_visible);

  // Returns whether the current autoplay policy is
  // kDocumentUserActivationRequired. This is a helper method for readability.
  bool IsUsingDocumentUserActivationRequiredPolicy() const;

  // Sets `autoplay_initiated_` if it wasn't already set.
  void MaybeSetAutoplayInitiated();

  bool locked_pending_user_gesture_ : 1;
  bool locked_pending_user_gesture_if_cross_origin_experiment_enabled_ : 1;

  Member<HTMLMediaElement> element_;
  Member<ElementVisibilityObserver> autoplay_visibility_observer_;

  Member<AutoplayUmaHelper> autoplay_uma_helper_;

  base::Optional<bool> autoplay_initiated_;

  DISALLOW_COPY_AND_ASSIGN(AutoplayPolicy);
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_AUTOPLAY_POLICY_H_