[M120 Migration][MM] Handle live stream duration and currenttime
[platform/framework/web/chromium-efl.git] / third_party / blink / renderer / core / html / media / html_media_element.cc
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
28
29 #include <algorithm>
30 #include <limits>
31
32 #include "base/auto_reset.h"
33 #include "base/debug/crash_logging.h"
34 #include "base/feature_list.h"
35 #include "base/memory/ptr_util.h"
36 #include "base/metrics/histogram_functions.h"
37 #include "base/metrics/histogram_macros.h"
38 #include "base/synchronization/lock.h"
39 #include "base/time/time.h"
40 #include "cc/layers/layer.h"
41 #include "media/base/media_content_type.h"
42 #include "media/base/media_switches.h"
43 #include "services/media_session/public/mojom/media_session.mojom-blink.h"
44 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
45 #include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
46 #include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
47 #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
48 #include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom-shared.h"
49 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream.h"
50 #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h"
51 #include "third_party/blink/public/platform/task_type.h"
52 #include "third_party/blink/public/platform/web_media_player.h"
53 #include "third_party/blink/public/platform/web_media_player_source.h"
54 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
55 #include "third_party/blink/renderer/core/core_initializer.h"
56 #include "third_party/blink/renderer/core/core_probes_inl.h"
57 #include "third_party/blink/renderer/core/css/style_change_reason.h"
58 #include "third_party/blink/renderer/core/css/style_engine.h"
59 #include "third_party/blink/renderer/core/dom/attribute.h"
60 #include "third_party/blink/renderer/core/dom/dom_exception.h"
61 #include "third_party/blink/renderer/core/dom/element_traversal.h"
62 #include "third_party/blink/renderer/core/dom/events/event.h"
63 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
64 #include "third_party/blink/renderer/core/dom/shadow_root.h"
65 #include "third_party/blink/renderer/core/execution_context/agent.h"
66 #include "third_party/blink/renderer/core/fileapi/url_file_api.h"
67 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
68 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
69 #include "third_party/blink/renderer/core/frame/local_frame.h"
70 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
71 #include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
72 #include "third_party/blink/renderer/core/frame/settings.h"
73 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
74 #include "third_party/blink/renderer/core/html/html_source_element.h"
75 #include "third_party/blink/renderer/core/html/media/audio_output_device_controller.h"
76 #include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
77 #include "third_party/blink/renderer/core/html/media/html_media_element_controls_list.h"
78 #include "third_party/blink/renderer/core/html/media/media_controls.h"
79 #include "third_party/blink/renderer/core/html/media/media_error.h"
80 #include "third_party/blink/renderer/core/html/media/media_fragment_uri_parser.h"
81 #include "third_party/blink/renderer/core/html/media/media_source_attachment.h"
82 #include "third_party/blink/renderer/core/html/media/media_source_handle.h"
83 #include "third_party/blink/renderer/core/html/media/media_source_tracer.h"
84 #include "third_party/blink/renderer/core/html/time_ranges.h"
85 #include "third_party/blink/renderer/core/html/track/audio_track.h"
86 #include "third_party/blink/renderer/core/html/track/audio_track_list.h"
87 #include "third_party/blink/renderer/core/html/track/automatic_track_selection.h"
88 #include "third_party/blink/renderer/core/html/track/cue_timeline.h"
89 #include "third_party/blink/renderer/core/html/track/html_track_element.h"
90 #include "third_party/blink/renderer/core/html/track/loadable_text_track.h"
91 #include "third_party/blink/renderer/core/html/track/text_track_container.h"
92 #include "third_party/blink/renderer/core/html/track/text_track_list.h"
93 #include "third_party/blink/renderer/core/html/track/video_track.h"
94 #include "third_party/blink/renderer/core/html/track/video_track_list.h"
95 #include "third_party/blink/renderer/core/html_names.h"
96 #include "third_party/blink/renderer/core/inspector/console_message.h"
97 #include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h"
98 #include "third_party/blink/renderer/core/layout/layout_media.h"
99 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
100 #include "third_party/blink/renderer/core/page/chrome_client.h"
101 #include "third_party/blink/renderer/core/page/page.h"
102 #include "third_party/blink/renderer/core/speech/speech_synthesis_base.h"
103 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
104 #include "third_party/blink/renderer/platform/audio/audio_source_provider_client.h"
105 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
106 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
107 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
108 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
109 #include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
110 #include "third_party/blink/renderer/platform/network/mime/content_type.h"
111 #include "third_party/blink/renderer/platform/network/mime/mime_type_from_url.h"
112 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
113 #include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
114 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
115 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
116 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
117 #include "third_party/blink/renderer/platform/wtf/functional.h"
118 #include "third_party/blink/renderer/platform/wtf/vector.h"
119 #include "ui/accessibility/accessibility_features.h"
120 #include "ui/display/screen_info.h"
121
122 #if BUILDFLAG(IS_TIZEN_TV)
123 #include "third_party/blink/public/platform/web_application_type.h"
124 #endif
125
126 #ifndef LOG_MEDIA_EVENTS
127 // Default to not logging events because so many are generated they can
128 // overwhelm the rest of the logging.
129 #define LOG_MEDIA_EVENTS 0
130 #endif
131
132 #ifndef LOG_OFFICIAL_TIME_STATUS
133 // Default to not logging status of official time because it adds a fair amount
134 // of overhead and logging.
135 #define LOG_OFFICIAL_TIME_STATUS 0
136 #endif
137
138 namespace blink {
139
140 using WeakMediaElementSet = HeapHashSet<WeakMember<HTMLMediaElement>>;
141 using DocumentElementSetMap =
142     HeapHashMap<WeakMember<Document>, Member<WeakMediaElementSet>>;
143
144 namespace {
145
146 // When enabled, CSS media queries are supported in <source> elements.
147 BASE_FEATURE(kVideoSourceMediaQuerySupport,
148              "VideoSourceMediaQuerySupport",
149              base::FEATURE_ENABLED_BY_DEFAULT);
150
151 // This enum is used to record histograms. Do not reorder.
152 enum class MediaControlsShow {
153   kAttribute = 0,
154   kFullscreen,
155   kNoScript,
156   kNotShown,
157   kDisabledSettings,
158   kUserExplicitlyEnabled,
159   kUserExplicitlyDisabled,
160   kMaxValue = kUserExplicitlyDisabled,
161 };
162
163 // The state of the HTMLMediaElement when ProgressEventTimerFired is invoked.
164 // These values are histogrammed, so please only add values to the end.
165 enum class ProgressEventTimerState {
166   // networkState is not NETWORK_LOADING.
167   kNotLoading,
168   // MediaShouldBeOpaque() is true.
169   kMediaShouldBeOpaque,
170   // "progress" event was scheduled.
171   kProgress,
172   // No progress. The "stalled" event was scheduled.
173   kStalled,
174   // No progress. No "stalled" event scheduled because a Media Source Attachment
175   // is used.
176   kHasMediaSourceAttachment,
177   // No progress. No "stalled" event scheduled because there was recent
178   // progress.
179   kRecentProgress,
180   // No progress. No "stalled" event scheduled because it was already scheduled.
181   kStalledEventAlreadyScheduled,
182   kMaxValue = kStalledEventAlreadyScheduled
183 };
184
185 // Records the state of the HTMLMediaElement when its "progress event" timer
186 // fires.
187 // TODO(crbug.com/1143317): Remove once the bug is fixed.
188 void RecordProgressEventTimerState(ProgressEventTimerState state) {
189   UMA_HISTOGRAM_ENUMERATION("Media.ProgressEventTimerState", state);
190 }
191
192 static const base::TimeDelta kStalledNotificationInterval = base::Seconds(3);
193
194 String UrlForLoggingMedia(const KURL& url) {
195   static const unsigned kMaximumURLLengthForLogging = 128;
196
197   if (url.GetString().length() < kMaximumURLLengthForLogging)
198     return url.GetString();
199   return url.GetString().Substring(0, kMaximumURLLengthForLogging) + "...";
200 }
201
202 const char* BoolString(bool val) {
203   return val ? "true" : "false";
204 }
205
206 DocumentElementSetMap& DocumentToElementSetMap() {
207   DEFINE_STATIC_LOCAL(Persistent<DocumentElementSetMap>, map,
208                       (MakeGarbageCollected<DocumentElementSetMap>()));
209   return *map;
210 }
211
212 void AddElementToDocumentMap(HTMLMediaElement* element, Document* document) {
213   DocumentElementSetMap& map = DocumentToElementSetMap();
214   WeakMediaElementSet* set = nullptr;
215   auto it = map.find(document);
216   if (it == map.end()) {
217     set = MakeGarbageCollected<WeakMediaElementSet>();
218     map.insert(document, set);
219   } else {
220     set = it->value;
221   }
222   set->insert(element);
223 }
224
225 void RemoveElementFromDocumentMap(HTMLMediaElement* element,
226                                   Document* document) {
227   DocumentElementSetMap& map = DocumentToElementSetMap();
228   auto it = map.find(document);
229   DCHECK(it != map.end());
230   WeakMediaElementSet* set = it->value;
231   set->erase(element);
232   if (set->empty())
233     map.erase(it);
234 }
235
236 String BuildElementErrorMessage(const String& error) {
237   // Prepend a UA-specific-error code before the first ':', to enable better
238   // collection and aggregation of UA-specific-error codes from
239   // MediaError.message by web apps. WebMediaPlayer::GetErrorMessage() should
240   // similarly conform to this format.
241   DEFINE_STATIC_LOCAL(const String, element_error_prefix,
242                       ("MEDIA_ELEMENT_ERROR: "));
243   StringBuilder builder;
244   builder.Append(element_error_prefix);
245   builder.Append(error);
246   return builder.ToString();
247 }
248
249 class AudioSourceProviderClientLockScope {
250   STACK_ALLOCATED();
251
252  public:
253   explicit AudioSourceProviderClientLockScope(HTMLMediaElement& element)
254       : client_(element.AudioSourceNode()) {
255     if (client_)
256       client_->lock();
257   }
258   ~AudioSourceProviderClientLockScope() {
259     if (client_)
260       client_->unlock();
261   }
262
263  private:
264   AudioSourceProviderClient* client_;
265 };
266
267 const AtomicString& AudioKindToString(
268     WebMediaPlayerClient::AudioTrackKind kind) {
269   switch (kind) {
270     case WebMediaPlayerClient::kAudioTrackKindNone:
271       return g_empty_atom;
272     case WebMediaPlayerClient::kAudioTrackKindAlternative:
273       return AudioTrack::AlternativeKeyword();
274     case WebMediaPlayerClient::kAudioTrackKindDescriptions:
275       return AudioTrack::DescriptionsKeyword();
276     case WebMediaPlayerClient::kAudioTrackKindMain:
277       return AudioTrack::MainKeyword();
278     case WebMediaPlayerClient::kAudioTrackKindMainDescriptions:
279       return AudioTrack::MainDescriptionsKeyword();
280     case WebMediaPlayerClient::kAudioTrackKindTranslation:
281       return AudioTrack::TranslationKeyword();
282     case WebMediaPlayerClient::kAudioTrackKindCommentary:
283       return AudioTrack::CommentaryKeyword();
284   }
285
286   NOTREACHED();
287   return g_empty_atom;
288 }
289
290 const AtomicString& VideoKindToString(
291     WebMediaPlayerClient::VideoTrackKind kind) {
292   switch (kind) {
293     case WebMediaPlayerClient::kVideoTrackKindNone:
294       return g_empty_atom;
295     case WebMediaPlayerClient::kVideoTrackKindAlternative:
296       return VideoTrack::AlternativeKeyword();
297     case WebMediaPlayerClient::kVideoTrackKindCaptions:
298       return VideoTrack::CaptionsKeyword();
299     case WebMediaPlayerClient::kVideoTrackKindMain:
300       return VideoTrack::MainKeyword();
301     case WebMediaPlayerClient::kVideoTrackKindSign:
302       return VideoTrack::SignKeyword();
303     case WebMediaPlayerClient::kVideoTrackKindSubtitles:
304       return VideoTrack::SubtitlesKeyword();
305     case WebMediaPlayerClient::kVideoTrackKindCommentary:
306       return VideoTrack::CommentaryKeyword();
307   }
308
309   NOTREACHED();
310   return g_empty_atom;
311 }
312
313 bool CanLoadURL(const KURL& url, const String& content_type_str) {
314   DEFINE_STATIC_LOCAL(const String, codecs, ("codecs"));
315
316   ContentType content_type(content_type_str);
317   String content_mime_type = content_type.GetType().DeprecatedLower();
318   String content_type_codecs = content_type.Parameter(codecs);
319
320   // If the MIME type is missing or is not meaningful, try to figure it out from
321   // the URL.
322   if (content_mime_type.empty() ||
323       content_mime_type == "application/octet-stream" ||
324       content_mime_type == "text/plain") {
325     if (url.ProtocolIsData())
326       content_mime_type = MimeTypeFromDataURL(url.GetString());
327   }
328
329   // If no MIME type is specified, always attempt to load.
330   if (content_mime_type.empty())
331     return true;
332
333   // 4.8.12.3 MIME types - In the absence of a specification to the contrary,
334   // the MIME type "application/octet-stream" when used with parameters, e.g.
335   // "application/octet-stream;codecs=theora", is a type that the user agent
336   // knows it cannot render.
337   if (content_mime_type != "application/octet-stream" ||
338       content_type_codecs.empty()) {
339     return MIMETypeRegistry::SupportsMediaMIMEType(content_mime_type,
340                                                    content_type_codecs) !=
341            MIMETypeRegistry::kNotSupported;
342   }
343
344   return false;
345 }
346
347 String PreloadTypeToString(WebMediaPlayer::Preload preload_type) {
348   switch (preload_type) {
349     case WebMediaPlayer::kPreloadNone:
350       return "none";
351     case WebMediaPlayer::kPreloadMetaData:
352       return "metadata";
353     case WebMediaPlayer::kPreloadAuto:
354       return "auto";
355   }
356
357   NOTREACHED();
358   return String();
359 }
360
361 void RecordShowControlsUsage(const HTMLMediaElement* element,
362                              MediaControlsShow value) {
363   if (element->IsHTMLVideoElement()) {
364     base::UmaHistogramEnumeration("Media.Controls.Show.Video", value);
365     return;
366   }
367   base::UmaHistogramEnumeration("Media.Controls.Show.Audio", value);
368 }
369
370 bool IsValidPlaybackRate(double rate) {
371   return rate == 0.0 || (rate >= HTMLMediaElement::kMinPlaybackRate &&
372                          rate <= HTMLMediaElement::kMaxPlaybackRate);
373 }
374
375 std::ostream& operator<<(std::ostream& stream,
376                          HTMLMediaElement const& media_element) {
377   return stream << static_cast<void const*>(&media_element);
378 }
379
380 }  // anonymous namespace
381
382 // static
383 MIMETypeRegistry::SupportsType HTMLMediaElement::GetSupportsType(
384     const ContentType& content_type) {
385   // TODO(https://crbug.com/809912): Finding source of mime parsing crash.
386   static base::debug::CrashKeyString* content_type_crash_key =
387       base::debug::AllocateCrashKeyString("media_content_type",
388                                           base::debug::CrashKeySize::Size256);
389   base::debug::ScopedCrashKeyString scoped_crash_key(
390       content_type_crash_key, content_type.Raw().Utf8().c_str());
391
392   String type = content_type.GetType().DeprecatedLower();
393   // The codecs string is not lower-cased because MP4 values are case sensitive
394   // per http://tools.ietf.org/html/rfc4281#page-7.
395   String type_codecs = content_type.Parameter("codecs");
396
397   if (type.empty())
398     return MIMETypeRegistry::kNotSupported;
399
400   // 4.8.12.3 MIME types - The canPlayType(type) method must return the empty
401   // string if type is a type that the user agent knows it cannot render or is
402   // the type "application/octet-stream"
403   if (type == "application/octet-stream")
404     return MIMETypeRegistry::kNotSupported;
405
406   // |contentType| could be handled using ParsedContentType, but there are
407   // still a lot of sites using codec strings that don't work with the
408   // stricter parsing rules.
409   MIMETypeRegistry::SupportsType result =
410       MIMETypeRegistry::SupportsMediaMIMEType(type, type_codecs);
411   return result;
412 }
413
414 bool HTMLMediaElement::IsHLSURL(const KURL& url) {
415   // Keep the same logic as in media_codec_util.h.
416   if (url.IsNull() || url.IsEmpty())
417     return false;
418
419   if (!url.IsLocalFile() && !url.ProtocolIs("http") && !url.ProtocolIs("https"))
420     return false;
421
422   return url.GetPath().EndsWith(".m3u8");
423 }
424
425 // static
426 void HTMLMediaElement::OnMediaControlsEnabledChange(Document* document) {
427   auto it = DocumentToElementSetMap().find(document);
428   if (it == DocumentToElementSetMap().end())
429     return;
430   DCHECK(it->value);
431   WeakMediaElementSet& elements = *it->value;
432   for (const auto& element : elements) {
433     element->UpdateControlsVisibility();
434     if (element->GetMediaControls())
435       element->GetMediaControls()->OnMediaControlsEnabledChange();
436   }
437 }
438
439 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
440                                    Document& document)
441     : HTMLElement(tag_name, document),
442       ActiveScriptWrappable<HTMLMediaElement>({}),
443       ExecutionContextLifecycleStateObserver(GetExecutionContext()),
444       load_timer_(document.GetTaskRunner(TaskType::kInternalMedia),
445                   this,
446                   &HTMLMediaElement::LoadTimerFired),
447       audio_tracks_timer_(document.GetTaskRunner(TaskType::kInternalMedia),
448                           this,
449                           &HTMLMediaElement::AudioTracksTimerFired),
450       removed_from_document_timer_(
451           document.GetTaskRunner(TaskType::kInternalMedia),
452           this,
453           &HTMLMediaElement::OnRemovedFromDocumentTimerFired),
454       progress_event_timer_(
455           document.GetTaskRunner(TaskType::kInternalMedia),
456           WTF::BindRepeating(&HTMLMediaElement::ProgressEventTimerFired,
457                              WrapWeakPersistent(this))),
458       playback_progress_timer_(
459           document.GetTaskRunner(TaskType::kInternalMedia),
460           WTF::BindRepeating(&HTMLMediaElement::PlaybackProgressTimerFired,
461                              WrapWeakPersistent(this))),
462       async_event_queue_(
463           MakeGarbageCollected<EventQueue>(GetExecutionContext(),
464                                            TaskType::kMediaElementEvent)),
465       playback_rate_(1.0f),
466       default_playback_rate_(1.0f),
467       network_state_(kNetworkEmpty),
468       ready_state_(kHaveNothing),
469       ready_state_maximum_(kHaveNothing),
470       volume_(1.0f),
471       last_seek_time_(0),
472       duration_(std::numeric_limits<double>::quiet_NaN()),
473       last_time_update_event_media_time_(
474           std::numeric_limits<double>::quiet_NaN()),
475       default_playback_start_position_(0),
476       load_state_(kWaitingForSource),
477       deferred_load_state_(kNotDeferred),
478       deferred_load_timer_(document.GetTaskRunner(TaskType::kInternalMedia),
479                            this,
480                            &HTMLMediaElement::DeferredLoadTimerFired),
481       cc_layer_(nullptr),
482       official_playback_position_(0),
483       official_playback_position_needs_update_(true),
484       fragment_end_time_(std::numeric_limits<double>::quiet_NaN()),
485       pending_action_flags_(0),
486       playing_(false),
487       should_delay_load_event_(false),
488       have_fired_loaded_data_(false),
489       can_autoplay_(true),
490       muted_(false),
491       paused_(true),
492       seeking_(false),
493       paused_by_context_paused_(false),
494       show_poster_flag_(true),
495       sent_stalled_event_(false),
496       ignore_preload_none_(false),
497       text_tracks_visible_(false),
498       should_perform_automatic_track_selection_(true),
499       tracks_are_ready_(true),
500       processing_preference_change_(false),
501       was_always_muted_(true),
502 #if BUILDFLAG(IS_TIZEN_TV)
503       is_deactivate_(false),
504       is_translated_url_(false),
505 #endif
506 #if defined(TIZEN_MULTIMEDIA)
507       live_playback_complete_(false),
508 #endif
509       audio_tracks_(MakeGarbageCollected<AudioTrackList>(*this)),
510       video_tracks_(MakeGarbageCollected<VideoTrackList>(*this)),
511       audio_source_node_(nullptr),
512       speech_synthesis_(nullptr),
513       autoplay_policy_(MakeGarbageCollected<AutoplayPolicy>(this)),
514       remote_playback_client_(nullptr),
515       media_controls_(nullptr),
516       controls_list_(MakeGarbageCollected<HTMLMediaElementControlsList>(this)),
517       lazy_load_intersection_observer_(nullptr) {
518   DVLOG(1) << "HTMLMediaElement(" << *this << ")";
519
520   ResetMojoState();
521
522   LocalFrame* frame = document.GetFrame();
523   if (frame) {
524     remote_playback_client_ =
525         frame->Client()->CreateWebRemotePlaybackClient(*this);
526   }
527
528   SetHasCustomStyleCallbacks();
529   AddElementToDocumentMap(this, &document);
530
531   UseCounter::Count(document, WebFeature::kHTMLMediaElement);
532 }
533
534 HTMLMediaElement::~HTMLMediaElement() {
535   DVLOG(1) << "~HTMLMediaElement(" << *this << ")";
536 }
537
538 void HTMLMediaElement::Dispose() {
539   // Destroying the player may cause a resource load to be canceled,
540   // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being
541   // called via ResourceFetch::didLoadResource(), then
542   // FrameLoader::checkCompleted(). But it's guaranteed that the load event
543   // doesn't get dispatched during the object destruction.
544   // See Document::isDelayingLoadEvent().
545   // Also see http://crbug.com/275223 for more details.
546   ClearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
547
548   progress_event_timer_.Shutdown();
549   playback_progress_timer_.Shutdown();
550 }
551
552 void HTMLMediaElement::DidMoveToNewDocument(Document& old_document) {
553   DVLOG(3) << "didMoveToNewDocument(" << *this << ")";
554
555   load_timer_.MoveToNewTaskRunner(
556       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
557   progress_event_timer_.MoveToNewTaskRunner(
558       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
559   playback_progress_timer_.MoveToNewTaskRunner(
560       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
561   audio_tracks_timer_.MoveToNewTaskRunner(
562       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
563   deferred_load_timer_.MoveToNewTaskRunner(
564       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
565   removed_from_document_timer_.MoveToNewTaskRunner(
566       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
567
568   autoplay_policy_->DidMoveToNewDocument(old_document);
569
570   if (cue_timeline_) {
571     cue_timeline_->DidMoveToNewDocument(old_document);
572   }
573
574   // Stop speaking and set speech_synthesis_ to nullptr so that it is
575   // re-created on-demand when SpeechSynthesis() is called.
576   if (speech_synthesis_) {
577     speech_synthesis_->Cancel();
578     speech_synthesis_.Clear();
579   }
580
581   if (should_delay_load_event_) {
582     GetDocument().IncrementLoadEventDelayCount();
583     // Note: Keeping the load event delay count increment on oldDocument that
584     // was added when should_delay_load_event_ was set so that destruction of
585     // web_media_player_ can not cause load event dispatching in oldDocument.
586   } else {
587     // Incrementing the load event delay count so that destruction of
588     // web_media_player_ can not cause load event dispatching in oldDocument.
589     old_document.IncrementLoadEventDelayCount();
590   }
591
592   RemoveElementFromDocumentMap(this, &old_document);
593   AddElementToDocumentMap(this, &GetDocument());
594   SetExecutionContext(GetExecutionContext());
595
596   // FIXME: This is a temporary fix to prevent this object from causing the
597   // MediaPlayer to dereference LocalFrame and FrameLoader pointers from the
598   // previous document. This restarts the load, as if the src attribute had been
599   // set.  A proper fix would provide a mechanism to allow this object to
600   // refresh the MediaPlayer's LocalFrame and FrameLoader references on document
601   // changes so that playback can be resumed properly.
602   // TODO(liberato): Consider checking that the new document's opener is the old
603   // document: GetDocument().GetFrame()->Opener() == old_document.GetFrame().
604   ignore_preload_none_ = false;
605
606   // Experimental: Try to avoid destroying the media player when transferring a
607   // media element to a new document. This is a work in progress, and may cause
608   // security and/or stability issues.
609   // Normally, moving a player between documents requires destroying the
610   // media player because web media player cannot outlive the render frame that
611   // holds the element which creates the player. However, when transferring a
612   // media player to a same-origin picture-in-picture window opened by this
613   // document, it is safe to reuse because a picture-in-picture window is
614   // guaranteed not to outlive its opener document because
615   // DocumentPictureInPictureController watches the destruction and navigation
616   // of the opener's WebContents.
617   if (!ShouldReusePlayer(old_document, GetDocument())) {
618     // Don't worry about notifications from any previous document if we're not
619     // re-using the player.
620     if (opener_context_observer_)
621       opener_context_observer_->SetContextLifecycleNotifier(nullptr);
622     AttachToNewFrame();
623   } else if (opener_document_ == GetDocument()) {
624     // The element is moving back to the player's opener, so stop worrying.
625     DCHECK(opener_context_observer_);
626     opener_context_observer_->SetContextLifecycleNotifier(
627         opener_document_->GetExecutionContext());
628     opener_context_observer_ = nullptr;
629     opener_document_ = nullptr;
630   } else {
631     // Moving to a new document, so make sure that the player's opener is not
632     // closed while we're still using it.
633     if (!opener_context_observer_) {
634       DCHECK(!opener_document_);
635       // Only set this when we're going from "original opener" to "elsewhere",
636       // in case we're moved from one same-origin window to another.
637       opener_document_ = old_document;
638       opener_context_observer_ =
639           MakeGarbageCollected<OpenerContextObserver>(this);
640     }
641     opener_context_observer_->SetContextLifecycleNotifier(
642         opener_document_->GetExecutionContext());
643   }
644
645   // Decrement the load event delay count on oldDocument now that
646   // web_media_player_ has been destroyed and there is no risk of dispatching a
647   // load event from within the destructor.
648   old_document.DecrementLoadEventDelayCount();
649
650   HTMLElement::DidMoveToNewDocument(old_document);
651 }
652
653 bool HTMLMediaElement::ShouldReusePlayer(Document& old_document,
654                                          Document& new_document) const {
655   // A NULL frame implies a NULL domWindow, so just check one of them
656   if (!old_document.GetFrame() || !new_document.GetFrame()) {
657     return false;
658   }
659
660   // Don't reuse player if the Document Picture-in-Picture API is disabled for
661   // both documents.
662   if (!RuntimeEnabledFeatures::DocumentPictureInPictureAPIEnabled(
663           old_document.domWindow()->GetExecutionContext()) &&
664       !RuntimeEnabledFeatures::DocumentPictureInPictureAPIEnabled(
665           new_document.domWindow()->GetExecutionContext())) {
666     return false;
667   }
668
669   auto* new_origin = new_document.GetFrame()
670                          ->LocalFrameRoot()
671                          .GetSecurityContext()
672                          ->GetSecurityOrigin();
673   auto* old_origin = old_document.GetFrame()
674                          ->LocalFrameRoot()
675                          .GetSecurityContext()
676                          ->GetSecurityOrigin();
677
678   if (!old_origin || !new_origin || !old_origin->IsSameOriginWith(new_origin)) {
679     return false;
680   }
681
682   // Reuse player if the two documents have opener-pip relationship (for either
683   // direction).
684   return (new_document.domWindow()->IsPictureInPictureWindow() &&
685           new_document.GetFrame()->Opener() == old_document.GetFrame()) ||
686          (old_document.domWindow()->IsPictureInPictureWindow() &&
687           old_document.GetFrame()->Opener() == new_document.GetFrame());
688 }
689
690 void HTMLMediaElement::AttachToNewFrame() {
691   // The opener has closed, so definitely nothing else should use this.
692   opener_document_ = nullptr;
693   // Do not ask it to stop notifying us -- if this is a callback from the
694   // listener, then it's ExecutionContext has been destroyed and it's not
695   // allowed to unregister.
696   opener_context_observer_ = nullptr;
697   // Reset mojo state that is coupled to |old_document|'s execution context.
698   // NOTE: |media_player_host_remote_| is also coupled to |old_document|'s
699   // frame.
700   ResetMojoState();
701   InvokeLoadAlgorithm();
702 }
703
704 void HTMLMediaElement::ResetMojoState() {
705   if (media_player_host_remote_)
706     media_player_host_remote_->Value().reset();
707   media_player_host_remote_ = MakeGarbageCollected<DisallowNewWrapper<
708       HeapMojoAssociatedRemote<media::mojom::blink::MediaPlayerHost>>>(
709       GetExecutionContext());
710   if (media_player_observer_remote_set_)
711     media_player_observer_remote_set_->Value().Clear();
712   media_player_observer_remote_set_ = MakeGarbageCollected<DisallowNewWrapper<
713       HeapMojoAssociatedRemoteSet<media::mojom::blink::MediaPlayerObserver>>>(
714       GetExecutionContext());
715   if (media_player_receiver_set_)
716     media_player_receiver_set_->Value().Clear();
717   media_player_receiver_set_ =
718       MakeGarbageCollected<DisallowNewWrapper<HeapMojoAssociatedReceiverSet<
719           media::mojom::blink::MediaPlayer, HTMLMediaElement>>>(
720           this, GetExecutionContext());
721 }
722
723 bool HTMLMediaElement::SupportsFocus() const {
724   // TODO(https://crbug.com/911882): Depending on result of discussion, remove.
725   if (ownerDocument()->IsMediaDocument())
726     return false;
727
728   // If no controls specified, we should still be able to focus the element if
729   // it has tabIndex.
730   return ShouldShowControls() || HTMLElement::SupportsFocus();
731 }
732
733 bool HTMLMediaElement::IsFocusable(
734     bool disallow_layout_updates_for_accessibility_only) const {
735   if (!SupportsFocus()) {
736     return false;
737   }
738   return !IsFullscreen() || HTMLElement::IsFocusable(
739                                 disallow_layout_updates_for_accessibility_only);
740 }
741
742 bool HTMLMediaElement::IsKeyboardFocusable() const {
743   // Media elements are keyboard focusable if they are focusable at all,
744   // and don't have a negative tabindex set.
745   return IsFocusable() && tabIndex() >= 0;
746 }
747
748 int HTMLMediaElement::DefaultTabIndex() const {
749   return 0;
750 }
751
752 void HTMLMediaElement::ParseAttribute(
753     const AttributeModificationParams& params) {
754   const QualifiedName& name = params.name;
755   if (name == html_names::kSrcAttr) {
756     DVLOG(2) << "parseAttribute(" << *this
757              << ", kSrcAttr, old=" << params.old_value
758              << ", new=" << params.new_value << ")";
759     // A change to the src attribute can affect intrinsic size, which in turn
760     // requires a style recalc.
761     SetNeedsStyleRecalc(kLocalStyleChange,
762                         StyleChangeReasonForTracing::FromAttribute(name));
763     // Trigger a reload, as long as the 'src' attribute is present.
764     if (!params.new_value.IsNull()) {
765       ignore_preload_none_ = false;
766       InvokeLoadAlgorithm();
767     }
768   } else if (name == html_names::kControlsAttr) {
769     UseCounter::Count(GetDocument(),
770                       WebFeature::kHTMLMediaElementControlsAttribute);
771     UpdateControlsVisibility();
772   } else if (name == html_names::kControlslistAttr) {
773     UseCounter::Count(GetDocument(),
774                       WebFeature::kHTMLMediaElementControlsListAttribute);
775     if (params.old_value != params.new_value) {
776       controls_list_->DidUpdateAttributeValue(params.old_value,
777                                               params.new_value);
778       if (GetMediaControls())
779         GetMediaControls()->OnControlsListUpdated();
780     }
781   } else if (name == html_names::kPreloadAttr) {
782     SetPlayerPreload();
783   } else if (name == html_names::kDisableremoteplaybackAttr) {
784     // This attribute is an extension described in the Remote Playback API spec.
785     // Please see: https://w3c.github.io/remote-playback
786     UseCounter::Count(GetDocument(),
787                       WebFeature::kDisableRemotePlaybackAttribute);
788     if (params.old_value != params.new_value) {
789       if (web_media_player_) {
790         web_media_player_->RequestRemotePlaybackDisabled(
791             !params.new_value.IsNull());
792       }
793     }
794   } else if (name == html_names::kLatencyhintAttr &&
795              RuntimeEnabledFeatures::MediaLatencyHintEnabled()) {
796     if (web_media_player_)
797       web_media_player_->SetLatencyHint(latencyHint());
798   } else {
799     HTMLElement::ParseAttribute(params);
800   }
801 }
802
803 void HTMLMediaElement::ParserDidSetAttributes() {
804   HTMLElement::ParserDidSetAttributes();
805
806   if (FastHasAttribute(html_names::kMutedAttr))
807     muted_ = true;
808 }
809
810 // This method is being used as a way to know that cloneNode finished cloning
811 // attribute as there is no callback notifying about the end of a cloning
812 // operation. Indeed, it is required per spec to set the muted state based on
813 // the content attribute when the object is created.
814 void HTMLMediaElement::CloneNonAttributePropertiesFrom(const Element& other,
815                                                        NodeCloningData& data) {
816   HTMLElement::CloneNonAttributePropertiesFrom(other, data);
817
818   if (FastHasAttribute(html_names::kMutedAttr))
819     muted_ = true;
820 }
821
822 void HTMLMediaElement::FinishParsingChildren() {
823   HTMLElement::FinishParsingChildren();
824
825   if (Traversal<HTMLTrackElement>::FirstChild(*this))
826     ScheduleTextTrackResourceLoad();
827 }
828
829 bool HTMLMediaElement::LayoutObjectIsNeeded(const DisplayStyle& style) const {
830   return ShouldShowControls() && HTMLElement::LayoutObjectIsNeeded(style);
831 }
832
833 LayoutObject* HTMLMediaElement::CreateLayoutObject(const ComputedStyle&) {
834   return MakeGarbageCollected<LayoutMedia>(this);
835 }
836
837 Node::InsertionNotificationRequest HTMLMediaElement::InsertedInto(
838     ContainerNode& insertion_point) {
839   DVLOG(3) << "insertedInto(" << *this << ", " << insertion_point << ")";
840
841   HTMLElement::InsertedInto(insertion_point);
842   if (insertion_point.isConnected()) {
843     UseCounter::Count(GetDocument(), WebFeature::kHTMLMediaElementInDocument);
844     if ((!FastGetAttribute(html_names::kSrcAttr).empty() ||
845          src_object_stream_descriptor_ || src_object_media_source_handle_) &&
846         network_state_ == kNetworkEmpty) {
847       ignore_preload_none_ = false;
848       InvokeLoadAlgorithm();
849     }
850   }
851
852   return kInsertionShouldCallDidNotifySubtreeInsertions;
853 }
854
855 void HTMLMediaElement::DidNotifySubtreeInsertionsToDocument() {
856   UpdateControlsVisibility();
857 }
858
859 void HTMLMediaElement::RemovedFrom(ContainerNode& insertion_point) {
860   DVLOG(3) << "removedFrom(" << *this << ", " << insertion_point << ")";
861
862   removed_from_document_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
863
864   HTMLElement::RemovedFrom(insertion_point);
865 }
866
867 void HTMLMediaElement::AttachLayoutTree(AttachContext& context) {
868   HTMLElement::AttachLayoutTree(context);
869
870   UpdateLayoutObject();
871 }
872
873 void HTMLMediaElement::DidRecalcStyle(const StyleRecalcChange change) {
874   if (!change.ReattachLayoutTree())
875     UpdateLayoutObject();
876 }
877
878 void HTMLMediaElement::ScheduleTextTrackResourceLoad() {
879   DVLOG(3) << "scheduleTextTrackResourceLoad(" << *this << ")";
880
881   pending_action_flags_ |= kLoadTextTrackResource;
882
883   if (!load_timer_.IsActive())
884     load_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
885 }
886
887 void HTMLMediaElement::ScheduleNextSourceChild() {
888   // Schedule the timer to try the next <source> element WITHOUT resetting state
889   // ala invokeLoadAlgorithm.
890   pending_action_flags_ |= kLoadMediaResource;
891   load_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
892 }
893
894 void HTMLMediaElement::ScheduleEvent(const AtomicString& event_name) {
895   Event* event = Event::CreateCancelable(event_name);
896   event->SetTarget(this);
897   ScheduleEvent(event);
898 }
899
900 void HTMLMediaElement::ScheduleEvent(Event* event) {
901 #if LOG_MEDIA_EVENTS
902   DVLOG(3) << "ScheduleEvent(" << (void*)this << ")"
903            << " - scheduling '" << event->type() << "'";
904 #endif
905   async_event_queue_->EnqueueEvent(FROM_HERE, *event);
906 }
907
908 void HTMLMediaElement::LoadTimerFired(TimerBase*) {
909   if (pending_action_flags_ & kLoadTextTrackResource)
910     HonorUserPreferencesForAutomaticTextTrackSelection();
911
912   if (pending_action_flags_ & kLoadMediaResource) {
913     if (load_state_ == kLoadingFromSourceElement)
914       LoadNextSourceChild();
915     else
916       LoadInternal();
917   }
918
919   pending_action_flags_ = 0;
920 }
921
922 MediaError* HTMLMediaElement::error() const {
923   return error_.Get();
924 }
925
926 void HTMLMediaElement::SetSrc(const AtomicString& url) {
927   setAttribute(html_names::kSrcAttr, url);
928 }
929
930 void HTMLMediaElement::SetSrcObjectVariant(
931     SrcObjectVariant src_object_variant) {
932   DVLOG(1) << __func__ << "(" << *this << ")";
933   src_object_stream_descriptor_ = nullptr;
934   src_object_media_source_handle_ = nullptr;
935   if (auto** desc = absl::get_if<MediaStreamDescriptor*>(&src_object_variant)) {
936     src_object_stream_descriptor_ = *desc;
937   } else if (auto** handle =
938                  absl::get_if<MediaSourceHandle*>(&src_object_variant)) {
939     src_object_media_source_handle_ = *handle;
940   }
941
942   DVLOG(2) << __func__
943            << ": stream_descriptor=" << src_object_stream_descriptor_
944            << ", media_source_handle=" << src_object_media_source_handle_;
945
946   InvokeLoadAlgorithm();
947 }
948
949 HTMLMediaElement::SrcObjectVariant HTMLMediaElement::GetSrcObjectVariant()
950     const {
951   DVLOG(1) << __func__ << "(" << *this << ")"
952            << ": stream_descriptor=" << src_object_stream_descriptor_
953            << ", media_source_handle=" << src_object_media_source_handle_;
954
955   // At most one is set.
956   DCHECK(!(src_object_stream_descriptor_ && src_object_media_source_handle_));
957
958   if (src_object_media_source_handle_)
959     return SrcObjectVariant(src_object_media_source_handle_.Get());
960
961   return SrcObjectVariant(src_object_stream_descriptor_.Get());
962 }
963
964 HTMLMediaElement::NetworkState HTMLMediaElement::getNetworkState() const {
965   return network_state_;
966 }
967
968 String HTMLMediaElement::canPlayType(const String& mime_type) const {
969   MIMETypeRegistry::SupportsType support =
970       GetSupportsType(ContentType(mime_type));
971
972   if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
973           blink::IdentifiableSurface::Type::kHTMLMediaElement_CanPlayType)) {
974     blink::IdentifiabilityMetricBuilder(GetDocument().UkmSourceID())
975         .Add(
976             blink::IdentifiableSurface::FromTypeAndToken(
977                 blink::IdentifiableSurface::Type::kHTMLMediaElement_CanPlayType,
978                 IdentifiabilityBenignStringToken(mime_type)),
979             static_cast<uint64_t>(support))
980         .Record(GetDocument().UkmRecorder());
981   }
982   String can_play;
983
984   // 4.8.12.3
985   switch (support) {
986     case MIMETypeRegistry::kNotSupported:
987       can_play = g_empty_string;
988       break;
989     case MIMETypeRegistry::kMaybeSupported:
990       can_play = "maybe";
991       break;
992     case MIMETypeRegistry::kSupported:
993       can_play = "probably";
994       break;
995   }
996
997   DVLOG(2) << "canPlayType(" << *this << ", " << mime_type << ") -> "
998            << can_play;
999
1000   return can_play;
1001 }
1002
1003 void HTMLMediaElement::load() {
1004   DVLOG(1) << "load(" << *this << ")";
1005
1006   autoplay_policy_->TryUnlockingUserGesture();
1007
1008   ignore_preload_none_ = true;
1009   InvokeLoadAlgorithm();
1010 }
1011
1012 // Implements the "media element load algorithm" as defined by
1013 // https://html.spec.whatwg.org/multipage/media.html#media-element-load-algorithm
1014 // TODO(srirama.m): Currently ignore_preload_none_ is reset before calling
1015 // invokeLoadAlgorithm() in all places except load(). Move it inside here
1016 // once microtask is implemented for "Await a stable state" step
1017 // in resource selection algorithm.
1018 void HTMLMediaElement::InvokeLoadAlgorithm() {
1019   DVLOG(3) << "invokeLoadAlgorithm(" << *this << ")";
1020
1021   // Perform the cleanup required for the resource load algorithm to run.
1022   StopPeriodicTimers();
1023   load_timer_.Stop();
1024   CancelDeferredLoad();
1025   // FIXME: Figure out appropriate place to reset LoadTextTrackResource if
1026   // necessary and set pending_action_flags_ to 0 here.
1027   pending_action_flags_ &= ~kLoadMediaResource;
1028   sent_stalled_event_ = false;
1029   have_fired_loaded_data_ = false;
1030
1031   autoplay_policy_->StopAutoplayMutedWhenVisible();
1032
1033   // 1 - Abort any already-running instance of the resource selection algorithm
1034   // for this element.
1035   load_state_ = kWaitingForSource;
1036   current_source_node_ = nullptr;
1037
1038   // 2 - Let pending tasks be a list of tasks from the media element's media
1039   // element task source in one of the task queues.
1040   //
1041   // 3 - For each task in the pending tasks that would run resolve pending
1042   // play promises or project pending play prmoises algorithms, immediately
1043   // resolve or reject those promises in the order the corresponding tasks
1044   // were queued.
1045   //
1046   // TODO(mlamouri): the promises are first resolved then rejected but the
1047   // order between resolved/rejected promises isn't respected. This could be
1048   // improved when the same task is used for both cases.
1049   //
1050   // TODO(mlamouri): don't run the callback synchronously if we are not allowed
1051   // to run scripts. It can happen in some edge cases. https://crbug.com/660382
1052   if (play_promise_resolve_task_handle_.IsActive() &&
1053       !ScriptForbiddenScope::IsScriptForbidden()) {
1054     play_promise_resolve_task_handle_.Cancel();
1055     ResolveScheduledPlayPromises();
1056   }
1057   if (play_promise_reject_task_handle_.IsActive() &&
1058       !ScriptForbiddenScope::IsScriptForbidden()) {
1059     play_promise_reject_task_handle_.Cancel();
1060     RejectScheduledPlayPromises();
1061   }
1062
1063   // 4 - Remove each task in pending tasks from its task queue.
1064   CancelPendingEventsAndCallbacks();
1065
1066   // 5 - If the media element's networkState is set to NETWORK_LOADING or
1067   // NETWORK_IDLE, queue a task to fire a simple event named abort at the media
1068   // element.
1069   if (network_state_ == kNetworkLoading || network_state_ == kNetworkIdle)
1070     ScheduleEvent(event_type_names::kAbort);
1071
1072   ResetMediaPlayerAndMediaSource();
1073
1074   // 6 - If the media element's networkState is not set to NETWORK_EMPTY, then
1075   // run these substeps
1076   if (network_state_ != kNetworkEmpty) {
1077     // 4.1 - Queue a task to fire a simple event named emptied at the media
1078     // element.
1079     ScheduleEvent(event_type_names::kEmptied);
1080
1081     // 4.2 - If a fetching process is in progress for the media element, the
1082     // user agent should stop it.
1083     SetNetworkState(kNetworkEmpty);
1084
1085     // 4.4 - Forget the media element's media-resource-specific tracks.
1086     ForgetResourceSpecificTracks();
1087
1088     // 4.5 - If readyState is not set to kHaveNothing, then set it to that
1089     // state.
1090     ready_state_ = kHaveNothing;
1091     ready_state_maximum_ = kHaveNothing;
1092
1093     DCHECK(!paused_ || play_promise_resolvers_.empty());
1094
1095     // 4.6 - If the paused attribute is false, then run these substeps
1096     if (!paused_) {
1097       // 4.6.1 - Set the paused attribute to true.
1098       paused_ = true;
1099
1100       // 4.6.2 - Take pending play promises and reject pending play promises
1101       // with the result and an "AbortError" DOMException.
1102       RejectPlayPromises(DOMExceptionCode::kAbortError,
1103                          "The play() request was interrupted by a new load "
1104                          "request. https://goo.gl/LdLk22");
1105     }
1106
1107     // 4.7 - If seeking is true, set it to false.
1108     seeking_ = false;
1109
1110     // 4.8 - Set the current playback position to 0.
1111     //       Set the official playback position to 0.
1112     //       If this changed the official playback position, then queue a task
1113     //       to fire a simple event named timeupdate at the media element.
1114     // 4.9 - Set the initial playback position to 0.
1115     SetOfficialPlaybackPosition(0);
1116     ScheduleTimeupdateEvent(false);
1117     GetCueTimeline().OnReadyStateReset();
1118
1119     // 4.10 - Set the timeline offset to Not-a-Number (NaN).
1120     // 4.11 - Update the duration attribute to Not-a-Number (NaN).
1121   } else if (!paused_) {
1122     // TODO(foolip): There is a proposal to always reset the paused state
1123     // in the media element load algorithm, to avoid a bogus play() promise
1124     // rejection: https://github.com/whatwg/html/issues/869
1125     // This is where that change would have an effect, and it is measured to
1126     // verify the assumption that it's a very rare situation.
1127     UseCounter::Count(GetDocument(),
1128                       WebFeature::kHTMLMediaElementLoadNetworkEmptyNotPaused);
1129   }
1130
1131   // 7 - Set the playbackRate attribute to the value of the defaultPlaybackRate
1132   // attribute.
1133   setPlaybackRate(defaultPlaybackRate());
1134
1135   // 8 - Set the error attribute to null and the can autoplay flag to true.
1136   SetError(nullptr);
1137   can_autoplay_ = true;
1138
1139   // 9 - Invoke the media element's resource selection algorithm.
1140   InvokeResourceSelectionAlgorithm();
1141
1142   // 10 - Note: Playback of any previously playing media resource for this
1143   // element stops.
1144 }
1145
1146 void HTMLMediaElement::InvokeResourceSelectionAlgorithm() {
1147   DVLOG(3) << "invokeResourceSelectionAlgorithm(" << *this << ")";
1148   // The resource selection algorithm
1149   // 1 - Set the networkState to NETWORK_NO_SOURCE
1150   SetNetworkState(kNetworkNoSource);
1151
1152   // 2 - Set the element's show poster flag to true
1153   SetShowPosterFlag(true);
1154
1155   played_time_ranges_ = MakeGarbageCollected<TimeRanges>();
1156
1157   // FIXME: Investigate whether these can be moved into network_state_ !=
1158   // kNetworkEmpty block above
1159   // so they are closer to the relevant spec steps.
1160   last_seek_time_ = 0;
1161   duration_ = std::numeric_limits<double>::quiet_NaN();
1162
1163   // 3 - Set the media element's delaying-the-load-event flag to true (this
1164   // delays the load event)
1165   SetShouldDelayLoadEvent(true);
1166   if (GetMediaControls() && isConnected())
1167     GetMediaControls()->Reset();
1168
1169   // 4 - Await a stable state, allowing the task that invoked this algorithm to
1170   // continue
1171   // TODO(srirama.m): Remove scheduleNextSourceChild() and post a microtask
1172   // instead.  See http://crbug.com/593289 for more details.
1173   ScheduleNextSourceChild();
1174 }
1175
1176 void HTMLMediaElement::LoadInternal() {
1177   // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose
1178   // mode was not in the disabled state when the element's resource selection
1179   // algorithm last started".
1180   text_tracks_when_resource_selection_began_.clear();
1181   if (text_tracks_) {
1182     for (unsigned i = 0; i < text_tracks_->length(); ++i) {
1183       TextTrack* track = text_tracks_->AnonymousIndexedGetter(i);
1184       if (track->mode() != TextTrackMode::kDisabled)
1185         text_tracks_when_resource_selection_began_.push_back(track);
1186     }
1187   }
1188
1189   SelectMediaResource();
1190 }
1191
1192 void HTMLMediaElement::SelectMediaResource() {
1193   DVLOG(3) << "selectMediaResource(" << *this << ")";
1194
1195   enum Mode { kObject, kAttribute, kChildren, kNothing };
1196   Mode mode = kNothing;
1197
1198   // 6 - If the media element has an assigned media provider object, then let
1199   //     mode be object.
1200   if (src_object_stream_descriptor_ || src_object_media_source_handle_) {
1201     mode = kObject;
1202   } else if (FastHasAttribute(html_names::kSrcAttr)) {
1203     // Otherwise, if the media element has no assigned media provider object
1204     // but has a src attribute, then let mode be attribute.
1205     mode = kAttribute;
1206   } else if (HTMLSourceElement* element =
1207                  Traversal<HTMLSourceElement>::FirstChild(*this)) {
1208     // Otherwise, if the media element does not have an assigned media
1209     // provider object and does not have a src attribute, but does have a
1210     // source element child, then let mode be children and let candidate be
1211     // the first such source element child in tree order.
1212     mode = kChildren;
1213     next_child_node_to_consider_ = element;
1214     current_source_node_ = nullptr;
1215   } else {
1216     // Otherwise the media element has no assigned media provider object and
1217     // has neither a src attribute nor a source element child: set the
1218     // networkState to kNetworkEmpty, and abort these steps; the synchronous
1219     // section ends.
1220     // TODO(mlamouri): Setting the network state to empty implies that there
1221     // should be no |web_media_player_|. However, if a previous playback ended
1222     // due to an error, we can get here and still have one. Decide on a plan
1223     // to deal with this properly. https://crbug.com/789737
1224     load_state_ = kWaitingForSource;
1225     SetShouldDelayLoadEvent(false);
1226     if (!web_media_player_ || (ready_state_ < kHaveFutureData &&
1227                                ready_state_maximum_ < kHaveFutureData)) {
1228       SetNetworkState(kNetworkEmpty);
1229     } else {
1230       UseCounter::Count(GetDocument(),
1231                         WebFeature::kHTMLMediaElementEmptyLoadWithFutureData);
1232     }
1233     UpdateLayoutObject();
1234
1235     DVLOG(3) << "selectMediaResource(" << *this << "), nothing to load";
1236     return;
1237   }
1238
1239   // 7 - Set the media element's networkState to NETWORK_LOADING.
1240   SetNetworkState(kNetworkLoading);
1241
1242   // 8 - Queue a task to fire a simple event named loadstart at the media
1243   // element.
1244   ScheduleEvent(event_type_names::kLoadstart);
1245
1246   // 9 - Run the appropriate steps...
1247   switch (mode) {
1248     case kObject:
1249       LoadSourceFromObject();
1250       DVLOG(3) << "selectMediaResource(" << *this
1251                << ", using 'srcObject' attribute";
1252       break;
1253     case kAttribute:
1254       LoadSourceFromAttribute();
1255       DVLOG(3) << "selectMediaResource(" << *this
1256                << "), using 'src' attribute url";
1257       break;
1258     case kChildren:
1259       LoadNextSourceChild();
1260       DVLOG(3) << "selectMediaResource(" << *this << "), using source element";
1261       break;
1262     default:
1263       NOTREACHED();
1264   }
1265 }
1266
1267 void HTMLMediaElement::LoadSourceFromObject() {
1268   DCHECK(src_object_stream_descriptor_ || src_object_media_source_handle_);
1269   load_state_ = kLoadingFromSrcObject;
1270
1271   if (src_object_media_source_handle_) {
1272     DCHECK(!src_object_stream_descriptor_);
1273
1274     // Retrieve the internal blob URL from the handle that was created in the
1275     // context where the referenced MediaSource is owned, for the purposes of
1276     // using existing security and logging logic for loading media from a
1277     // MediaSource with a blob URL.
1278     const String media_source_handle_url_ =
1279         src_object_media_source_handle_->GetInternalBlobURL();
1280     DCHECK(!media_source_handle_url_.empty());
1281
1282     KURL media_url = GetDocument().CompleteURL(media_source_handle_url_);
1283     if (!IsSafeToLoadURL(media_url, kComplain)) {
1284       MediaLoadingFailed(
1285           WebMediaPlayer::kNetworkStateFormatError,
1286           BuildElementErrorMessage(
1287               "Media load from MediaSourceHandle rejected by safety check"));
1288       return;
1289     }
1290
1291     // No type is available when loading from a MediaSourceHandle, via
1292     // srcObject, even with an internal MediaSource blob URL.
1293     LoadResource(WebMediaPlayerSource(WebURL(media_url)), String());
1294     return;
1295   }
1296
1297   // No type is available when the resource comes from the 'srcObject'
1298   // attribute.
1299   LoadResource(
1300       WebMediaPlayerSource(WebMediaStream(src_object_stream_descriptor_)),
1301       String());
1302 }
1303
1304 void HTMLMediaElement::LoadSourceFromAttribute() {
1305   load_state_ = kLoadingFromSrcAttr;
1306   const AtomicString& src_value = FastGetAttribute(html_names::kSrcAttr);
1307
1308   // If the src attribute's value is the empty string ... jump down to the
1309   // failed step below
1310   if (src_value.empty()) {
1311     DVLOG(3) << "LoadSourceFromAttribute(" << *this << "), empty 'src'";
1312     MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError,
1313                        BuildElementErrorMessage("Empty src attribute"));
1314     return;
1315   }
1316
1317   KURL media_url = GetDocument().CompleteURL(src_value);
1318   if (!IsSafeToLoadURL(media_url, kComplain)) {
1319     MediaLoadingFailed(
1320         WebMediaPlayer::kNetworkStateFormatError,
1321         BuildElementErrorMessage("Media load rejected by URL safety check"));
1322     return;
1323   }
1324
1325   // No type is available when the url comes from the 'src' attribute so
1326   // MediaPlayer will have to pick a media engine based on the file extension.
1327   LoadResource(WebMediaPlayerSource(WebURL(media_url)), String());
1328 }
1329
1330 void HTMLMediaElement::LoadNextSourceChild() {
1331   String content_type;
1332   KURL media_url = SelectNextSourceChild(&content_type, kComplain);
1333   if (!media_url.IsValid()) {
1334     WaitForSourceChange();
1335     return;
1336   }
1337
1338   // Reset the MediaPlayer and MediaSource if any
1339   ResetMediaPlayerAndMediaSource();
1340
1341   load_state_ = kLoadingFromSourceElement;
1342   LoadResource(WebMediaPlayerSource(WebURL(media_url)), content_type);
1343 }
1344
1345 void HTMLMediaElement::LoadResource(const WebMediaPlayerSource& source,
1346                                     const String& content_type) {
1347   DCHECK(IsMainThread());
1348   KURL url;
1349   if (source.IsURL()) {
1350     url = source.GetAsURL();
1351     DCHECK(IsSafeToLoadURL(url, kComplain));
1352     DVLOG(3) << "loadResource(" << *this << ", " << UrlForLoggingMedia(url)
1353              << ", " << content_type << ")";
1354   }
1355
1356   LocalFrame* frame = GetDocument().GetFrame();
1357   if (!frame) {
1358     MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError,
1359                        BuildElementErrorMessage(
1360                            "Resource load failure: document has no frame"));
1361     return;
1362   }
1363
1364 #if BUILDFLAG(IS_TIZEN_TV)
1365   ContentType cont_type(content_type);
1366   content_mime_type_ = cont_type.GetType().DeprecatedLower();
1367 #endif
1368
1369   // The resource fetch algorithm
1370   SetNetworkState(kNetworkLoading);
1371
1372   // Set |current_src_| *before* changing to the cache url, the fact that we are
1373   // loading from the app cache is an internal detail not exposed through the
1374   // media element API. If loading from an internal MediaSourceHandle object
1375   // URL, then do not expose that URL to app, but instead hold it for use later
1376   // in StartPlayerLoad and elsewhere (for origin, security etc checks normally
1377   // done on |current_src_|.)
1378   if (src_object_media_source_handle_) {
1379     DCHECK(!url.IsEmpty());
1380     current_src_.SetSource(url,
1381                            SourceMetadata::SourceVisibility::kInvisibleToApp);
1382   } else {
1383     current_src_.SetSource(url,
1384                            SourceMetadata::SourceVisibility::kVisibleToApp);
1385   }
1386
1387   // Default this to empty, so that we use |current_src_| unless the player
1388   // provides one later.
1389   current_src_after_redirects_ = KURL();
1390
1391   if (audio_source_node_)
1392     audio_source_node_->OnCurrentSrcChanged(current_src_.GetSourceIfVisible());
1393
1394   // Update remote playback client with the new src and consider it incompatible
1395   // until proved otherwise.
1396   RemotePlaybackCompatibilityChanged(current_src_.GetSourceIfVisible(), false);
1397
1398   DVLOG(3) << "loadResource(" << *this << ") - current src if visible="
1399            << UrlForLoggingMedia(current_src_.GetSourceIfVisible())
1400            << ", current src =" << UrlForLoggingMedia(current_src_.GetSource())
1401            << ", src_object_media_source_handle_="
1402            << src_object_media_source_handle_
1403            << ", src_object_stream_descriptor_="
1404            << src_object_stream_descriptor_;
1405
1406   StartProgressEventTimer();
1407
1408   SetPlayerPreload();
1409
1410   DCHECK(!media_source_attachment_);
1411   DCHECK(!media_source_tracer_);
1412   DCHECK(!error_);
1413
1414   bool attempt_load = true;
1415
1416   if (src_object_media_source_handle_) {
1417     media_source_attachment_ =
1418         src_object_media_source_handle_->TakeAttachment();
1419
1420     // If the attachment is nullptr, then fail the load.
1421     if (!media_source_attachment_) {
1422       attempt_load = false;
1423     }
1424   } else {
1425     media_source_attachment_ =
1426         MediaSourceAttachment::LookupMediaSource(url.GetString());
1427   }
1428   if (media_source_attachment_) {
1429     bool start_result = false;
1430     media_source_tracer_ =
1431         media_source_attachment_->StartAttachingToMediaElement(this,
1432                                                                &start_result);
1433     if (start_result) {
1434       // If the associated feature is enabled, auto-revoke the MediaSource
1435       // object URL that was used for attachment on successful (start of)
1436       // attachment. This can help reduce memory bloat later if the app does not
1437       // revoke the object URL explicitly and the object URL was the only
1438       // remaining strong reference to an attached HTMLMediaElement+MediaSource
1439       // cycle of objects that could otherwise be garbage-collectable. Don't
1440       // auto-revoke the internal, unregistered, object URL used to attach via
1441       // srcObject with a MediaSourceHandle, though.
1442       if (base::FeatureList::IsEnabled(
1443               media::kRevokeMediaSourceObjectURLOnAttach) &&
1444           !src_object_media_source_handle_) {
1445         URLFileAPI::revokeObjectURL(GetExecutionContext(), url.GetString());
1446       }
1447     } else {
1448       // Forget our reference to the MediaSourceAttachment, so we leave it alone
1449       // while processing remainder of load failure.
1450       media_source_attachment_.reset();
1451       media_source_tracer_ = nullptr;
1452       attempt_load = false;
1453     }
1454   }
1455
1456   bool can_load_resource =
1457       source.IsMediaStream() || CanLoadURL(url, content_type);
1458   if (attempt_load && can_load_resource) {
1459     DCHECK(!web_media_player_);
1460
1461     // Conditionally defer the load if effective preload is 'none'.
1462     // Skip this optional deferral for MediaStream sources or any blob URL,
1463     // including MediaSource blob URLs.
1464     if (!source.IsMediaStream() && !url.ProtocolIs("blob") &&
1465         EffectivePreloadType() == WebMediaPlayer::kPreloadNone) {
1466       DVLOG(3) << "loadResource(" << *this
1467                << ") : Delaying load because preload == 'none'";
1468       DeferLoad();
1469     } else {
1470       StartPlayerLoad();
1471     }
1472   } else {
1473     MediaLoadingFailed(
1474         WebMediaPlayer::kNetworkStateFormatError,
1475         BuildElementErrorMessage(attempt_load
1476                                      ? "Unable to load URL due to content type"
1477                                      : "Unable to attach MediaSource"));
1478   }
1479 }
1480
1481 LocalFrame* HTMLMediaElement::LocalFrameForPlayer() {
1482   return opener_document_ ? opener_document_->GetFrame()
1483                           : GetDocument().GetFrame();
1484 }
1485
1486 void HTMLMediaElement::StartPlayerLoad() {
1487   DCHECK(!web_media_player_);
1488
1489   WebMediaPlayerSource source;
1490   if (src_object_stream_descriptor_) {
1491     source =
1492         WebMediaPlayerSource(WebMediaStream(src_object_stream_descriptor_));
1493   } else if (src_object_media_source_handle_) {
1494     DCHECK(current_src_.GetSourceIfVisible().IsEmpty());
1495     const KURL& internal_url = current_src_.GetSource();
1496     DCHECK(!internal_url.IsEmpty());
1497
1498     source = WebMediaPlayerSource(WebURL(internal_url));
1499   } else {
1500     // Filter out user:pass as those two URL components aren't
1501     // considered for media resource fetches (including for the CORS
1502     // use-credentials mode.) That behavior aligns with Gecko, with IE
1503     // being more restrictive and not allowing fetches to such URLs.
1504     //
1505     // Spec reference: http://whatwg.org/c/#concept-media-load-resource
1506     //
1507     // FIXME: when the HTML spec switches to specifying resource
1508     // fetches in terms of Fetch (http://fetch.spec.whatwg.org), and
1509     // along with that potentially also specifying a setting for its
1510     // 'authentication flag' to control how user:pass embedded in a
1511     // media resource URL should be treated, then update the handling
1512     // here to match.
1513     KURL request_url = current_src_.GetSourceIfVisible();
1514     if (!request_url.User().empty())
1515       request_url.SetUser(String());
1516     if (!request_url.Pass().empty())
1517       request_url.SetPass(String());
1518
1519     KURL kurl(request_url);
1520     source = WebMediaPlayerSource(WebURL(kurl));
1521   }
1522
1523   LocalFrame* frame = LocalFrameForPlayer();
1524   if (!frame || !GetExecutionContext()) {
1525     MediaLoadingFailed(
1526         WebMediaPlayer::kNetworkStateFormatError,
1527         BuildElementErrorMessage("Player load failure: document has no frame"));
1528     return;
1529   }
1530
1531   web_media_player_ =
1532       frame->Client()->CreateWebMediaPlayer(*this, source, this);
1533
1534   if (!web_media_player_) {
1535     MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError,
1536                        BuildElementErrorMessage(
1537                            "Player load failure: error creating media player"));
1538     return;
1539   }
1540
1541   OnWebMediaPlayerCreated();
1542
1543   // Setup the communication channels between the renderer and browser processes
1544   // via the MediaPlayer and MediaPlayerObserver mojo interfaces.
1545   DCHECK(media_player_receiver_set_->Value().empty());
1546   mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayer>
1547       media_player_remote;
1548   BindMediaPlayerReceiver(
1549       media_player_remote.InitWithNewEndpointAndPassReceiver());
1550
1551   GetMediaPlayerHostRemote().OnMediaPlayerAdded(
1552       std::move(media_player_remote), AddMediaPlayerObserverAndPassReceiver(),
1553       web_media_player_->GetDelegateId());
1554
1555   if (GetLayoutObject())
1556     GetLayoutObject()->SetShouldDoFullPaintInvalidation();
1557   // Make sure if we create/re-create the WebMediaPlayer that we update our
1558   // wrapper.
1559   audio_source_provider_.Wrap(web_media_player_->GetAudioSourceProvider());
1560   web_media_player_->SetVolume(EffectiveMediaVolume());
1561
1562   web_media_player_->SetPoster(PosterImageURL());
1563
1564   const auto preload = EffectivePreloadType();
1565   web_media_player_->SetPreload(preload);
1566
1567   web_media_player_->RequestRemotePlaybackDisabled(
1568       FastHasAttribute(html_names::kDisableremoteplaybackAttr));
1569
1570   bool is_cache_disabled = false;
1571   probe::IsCacheDisabled(GetDocument().GetExecutionContext(),
1572                          &is_cache_disabled);
1573   auto load_timing = web_media_player_->Load(GetLoadType(), source, CorsMode(),
1574                                              is_cache_disabled);
1575   if (load_timing == WebMediaPlayer::LoadTiming::kDeferred) {
1576     // Deferred media loading is not part of the spec, but intuition is that
1577     // this should not hold up the Window's "load" event (similar to user
1578     // gesture requirements).
1579     SetShouldDelayLoadEvent(false);
1580   }
1581
1582   if (IsFullscreen())
1583     web_media_player_->EnteredFullscreen();
1584
1585   web_media_player_->SetLatencyHint(latencyHint());
1586
1587   web_media_player_->SetPreservesPitch(preservesPitch());
1588
1589   OnLoadStarted();
1590 }
1591
1592 void HTMLMediaElement::SetPlayerPreload() {
1593   if (web_media_player_)
1594     web_media_player_->SetPreload(EffectivePreloadType());
1595
1596   if (LoadIsDeferred() &&
1597       EffectivePreloadType() != WebMediaPlayer::kPreloadNone)
1598     StartDeferredLoad();
1599 }
1600
1601 bool HTMLMediaElement::LoadIsDeferred() const {
1602   return deferred_load_state_ != kNotDeferred;
1603 }
1604
1605 void HTMLMediaElement::DeferLoad() {
1606   // This implements the "optional" step 4 from the resource fetch algorithm
1607   // "If mode is remote".
1608   DCHECK(!deferred_load_timer_.IsActive());
1609   DCHECK_EQ(deferred_load_state_, kNotDeferred);
1610   // 1. Set the networkState to NETWORK_IDLE.
1611   // 2. Queue a task to fire a simple event named suspend at the element.
1612   ChangeNetworkStateFromLoadingToIdle();
1613   // 3. Queue a task to set the element's delaying-the-load-event
1614   // flag to false. This stops delaying the load event.
1615   deferred_load_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
1616   // 4. Wait for the task to be run.
1617   deferred_load_state_ = kWaitingForStopDelayingLoadEventTask;
1618   // Continued in executeDeferredLoad().
1619 }
1620
1621 void HTMLMediaElement::CancelDeferredLoad() {
1622   deferred_load_timer_.Stop();
1623   deferred_load_state_ = kNotDeferred;
1624 }
1625
1626 void HTMLMediaElement::ExecuteDeferredLoad() {
1627   DCHECK_GE(deferred_load_state_, kWaitingForTrigger);
1628
1629   // resource fetch algorithm step 4 - continued from deferLoad().
1630
1631   // 5. Wait for an implementation-defined event (e.g. the user requesting that
1632   // the media element begin playback).  This is assumed to be whatever 'event'
1633   // ended up calling this method.
1634   CancelDeferredLoad();
1635   // 6. Set the element's delaying-the-load-event flag back to true (this
1636   // delays the load event again, in case it hasn't been fired yet).
1637   SetShouldDelayLoadEvent(true);
1638   // 7. Set the networkState to NETWORK_LOADING.
1639   SetNetworkState(kNetworkLoading);
1640
1641   StartProgressEventTimer();
1642
1643   StartPlayerLoad();
1644 }
1645
1646 void HTMLMediaElement::StartDeferredLoad() {
1647   if (deferred_load_state_ == kWaitingForTrigger) {
1648     ExecuteDeferredLoad();
1649     return;
1650   }
1651   if (deferred_load_state_ == kExecuteOnStopDelayingLoadEventTask)
1652     return;
1653   DCHECK_EQ(deferred_load_state_, kWaitingForStopDelayingLoadEventTask);
1654   deferred_load_state_ = kExecuteOnStopDelayingLoadEventTask;
1655 }
1656
1657 void HTMLMediaElement::DeferredLoadTimerFired(TimerBase*) {
1658   SetShouldDelayLoadEvent(false);
1659
1660   if (deferred_load_state_ == kExecuteOnStopDelayingLoadEventTask) {
1661     ExecuteDeferredLoad();
1662     return;
1663   }
1664   DCHECK_EQ(deferred_load_state_, kWaitingForStopDelayingLoadEventTask);
1665   deferred_load_state_ = kWaitingForTrigger;
1666 }
1667
1668 WebMediaPlayer::LoadType HTMLMediaElement::GetLoadType() const {
1669   if (media_source_attachment_)
1670     return WebMediaPlayer::kLoadTypeMediaSource;  // Either via src or srcObject
1671
1672   if (src_object_stream_descriptor_)
1673     return WebMediaPlayer::kLoadTypeMediaStream;
1674
1675   return WebMediaPlayer::kLoadTypeURL;
1676 }
1677
1678 bool HTMLMediaElement::PausedWhenVisible() const {
1679   return paused_ && web_media_player_ && !web_media_player_->PausedWhenHidden();
1680 }
1681
1682 void HTMLMediaElement::DidAudioOutputSinkChanged(
1683     const String& hashed_device_id) {
1684   for (auto& observer : media_player_observer_remote_set_->Value())
1685     observer->OnAudioOutputSinkChanged(hashed_device_id);
1686 }
1687
1688 void HTMLMediaElement::SetMediaPlayerHostForTesting(
1689     mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayerHost> host) {
1690   media_player_host_remote_->Value().Bind(
1691       std::move(host), GetDocument().GetTaskRunner(TaskType::kInternalMedia));
1692 }
1693
1694 bool HTMLMediaElement::TextTracksAreReady() const {
1695   // 4.8.12.11.1 Text track model
1696   // ...
1697   // The text tracks of a media element are ready if all the text tracks whose
1698   // mode was not in the disabled state when the element's resource selection
1699   // algorithm last started now have a text track readiness state of loaded or
1700   // failed to load.
1701   for (const auto& text_track : text_tracks_when_resource_selection_began_) {
1702     if (text_track->GetReadinessState() == TextTrack::kLoading ||
1703         text_track->GetReadinessState() == TextTrack::kNotLoaded)
1704       return false;
1705   }
1706
1707   return true;
1708 }
1709
1710 void HTMLMediaElement::TextTrackReadyStateChanged(TextTrack* track) {
1711   if (web_media_player_ &&
1712       text_tracks_when_resource_selection_began_.Contains(track)) {
1713     if (track->GetReadinessState() != TextTrack::kLoading) {
1714       SetReadyState(
1715           static_cast<ReadyState>(web_media_player_->GetReadyState()));
1716     }
1717   } else {
1718     // The track readiness state might have changed as a result of the user
1719     // clicking the captions button. In this case, a check whether all the
1720     // resources have failed loading should be done in order to hide the CC
1721     // button.
1722     // TODO(mlamouri): when an HTMLTrackElement fails to load, it is not
1723     // propagated to the TextTrack object in a web exposed fashion. We have to
1724     // keep relying on a custom glue to the controls while this is taken care
1725     // of on the web side. See https://crbug.com/669977
1726     if (GetMediaControls() &&
1727         track->GetReadinessState() == TextTrack::kFailedToLoad) {
1728       GetMediaControls()->OnTrackElementFailedToLoad();
1729     }
1730   }
1731 }
1732
1733 void HTMLMediaElement::TextTrackModeChanged(TextTrack* track) {
1734   // Mark this track as "configured" so configureTextTracks won't change the
1735   // mode again.
1736   if (IsA<LoadableTextTrack>(track))
1737     track->SetHasBeenConfigured(true);
1738
1739   if (track->IsRendered()) {
1740     GetDocument().GetStyleEngine().AddTextTrack(track);
1741   } else {
1742     GetDocument().GetStyleEngine().RemoveTextTrack(track);
1743   }
1744
1745   ConfigureTextTrackDisplay();
1746
1747   DCHECK(textTracks()->Contains(track));
1748   textTracks()->ScheduleChangeEvent();
1749 }
1750
1751 void HTMLMediaElement::DisableAutomaticTextTrackSelection() {
1752   should_perform_automatic_track_selection_ = false;
1753 }
1754
1755 bool HTMLMediaElement::IsSafeToLoadURL(const KURL& url,
1756                                        InvalidURLAction action_if_invalid) {
1757   if (!url.IsValid()) {
1758     DVLOG(3) << "isSafeToLoadURL(" << *this << ", " << UrlForLoggingMedia(url)
1759              << ") -> FALSE because url is invalid";
1760     return false;
1761   }
1762
1763   LocalDOMWindow* window = GetDocument().domWindow();
1764   if (!window || !window->GetSecurityOrigin()->CanDisplay(url)) {
1765     if (action_if_invalid == kComplain) {
1766       GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
1767           mojom::ConsoleMessageSource::kSecurity,
1768           mojom::ConsoleMessageLevel::kError,
1769           "Not allowed to load local resource: " + url.ElidedString()));
1770     }
1771     DVLOG(3) << "isSafeToLoadURL(" << *this << ", " << UrlForLoggingMedia(url)
1772              << ") -> FALSE rejected by SecurityOrigin";
1773     return false;
1774   }
1775
1776   if (!GetExecutionContext()->GetContentSecurityPolicy()->AllowMediaFromSource(
1777           url)) {
1778     DVLOG(3) << "isSafeToLoadURL(" << *this << ", " << UrlForLoggingMedia(url)
1779              << ") -> rejected by Content Security Policy";
1780     return false;
1781   }
1782
1783   return true;
1784 }
1785
1786 bool HTMLMediaElement::IsMediaDataCorsSameOrigin() const {
1787   if (!web_media_player_)
1788     return true;
1789
1790   const auto network_state = web_media_player_->GetNetworkState();
1791   if (network_state == WebMediaPlayer::kNetworkStateNetworkError)
1792     return false;
1793
1794   return !web_media_player_->WouldTaintOrigin();
1795 }
1796
1797 void HTMLMediaElement::StartProgressEventTimer() {
1798   if (progress_event_timer_.IsActive())
1799     return;
1800
1801   previous_progress_time_ = base::ElapsedTimer();
1802   // 350ms is not magic, it is in the spec!
1803   progress_event_timer_.StartRepeating(base::Milliseconds(350));
1804 }
1805
1806 void HTMLMediaElement::WaitForSourceChange() {
1807   DVLOG(3) << "waitForSourceChange(" << *this << ")";
1808
1809   StopPeriodicTimers();
1810   load_state_ = kWaitingForSource;
1811
1812   // 17 - Waiting: Set the element's networkState attribute to the
1813   // NETWORK_NO_SOURCE value
1814   SetNetworkState(kNetworkNoSource);
1815
1816   // 18 - Set the element's show poster flag to true.
1817   SetShowPosterFlag(true);
1818
1819   // 19 - Set the element's delaying-the-load-event flag to false. This stops
1820   // delaying the load event.
1821   SetShouldDelayLoadEvent(false);
1822
1823   UpdateLayoutObject();
1824 }
1825
1826 void HTMLMediaElement::NoneSupported(const String& input_message) {
1827   DVLOG(3) << "NoneSupported(" << *this << ", message='" << input_message
1828            << "')";
1829
1830   StopPeriodicTimers();
1831   load_state_ = kWaitingForSource;
1832   current_source_node_ = nullptr;
1833
1834   String empty_string;
1835   const String& message = MediaShouldBeOpaque() ? empty_string : input_message;
1836
1837   // 4.8.12.5
1838   // The dedicated media source failure steps are the following steps:
1839
1840   // 1 - Set the error attribute to a new MediaError object whose code attribute
1841   // is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
1842   SetError(MakeGarbageCollected<MediaError>(
1843       MediaError::kMediaErrSrcNotSupported, message));
1844
1845   // 2 - Forget the media element's media-resource-specific text tracks.
1846   ForgetResourceSpecificTracks();
1847
1848   // 3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE
1849   // value.
1850   SetNetworkState(kNetworkNoSource);
1851
1852   // 4 - Set the element's show poster flag to true.
1853   SetShowPosterFlag(true);
1854
1855   // 5 - Fire a simple event named error at the media element.
1856   ScheduleEvent(event_type_names::kError);
1857
1858   // 6 - Reject pending play promises with NotSupportedError.
1859   ScheduleRejectPlayPromises(PlayPromiseError::kNotSupported);
1860
1861   CloseMediaSource();
1862
1863   // 7 - Set the element's delaying-the-load-event flag to false. This stops
1864   // delaying the load event.
1865   SetShouldDelayLoadEvent(false);
1866
1867   UpdateLayoutObject();
1868 }
1869
1870 void HTMLMediaElement::MediaEngineError(MediaError* err) {
1871   DCHECK_GE(ready_state_, kHaveMetadata);
1872   DVLOG(3) << "mediaEngineError(" << *this << ", "
1873            << static_cast<int>(err->code()) << ")";
1874
1875   // 1 - The user agent should cancel the fetching process.
1876   StopPeriodicTimers();
1877   load_state_ = kWaitingForSource;
1878
1879   // 2 - Set the error attribute to a new MediaError object whose code attribute
1880   // is set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
1881   SetError(err);
1882
1883   // 3 - Queue a task to fire a simple event named error at the media element.
1884   ScheduleEvent(event_type_names::kError);
1885
1886   // 4 - Set the element's networkState attribute to the NETWORK_IDLE value.
1887   SetNetworkState(kNetworkIdle);
1888
1889   // 5 - Set the element's delaying-the-load-event flag to false. This stops
1890   // delaying the load event.
1891   SetShouldDelayLoadEvent(false);
1892
1893   // 6 - Abort the overall resource selection algorithm.
1894   current_source_node_ = nullptr;
1895 }
1896
1897 void HTMLMediaElement::CancelPendingEventsAndCallbacks() {
1898   DVLOG(3) << "cancelPendingEventsAndCallbacks(" << *this << ")";
1899   async_event_queue_->CancelAllEvents();
1900
1901   for (HTMLSourceElement* source =
1902            Traversal<HTMLSourceElement>::FirstChild(*this);
1903        source; source = Traversal<HTMLSourceElement>::NextSibling(*source))
1904     source->CancelPendingErrorEvent();
1905 }
1906
1907 void HTMLMediaElement::NetworkStateChanged() {
1908   SetNetworkState(web_media_player_->GetNetworkState());
1909 }
1910
1911 void HTMLMediaElement::MediaLoadingFailed(WebMediaPlayer::NetworkState error,
1912                                           const String& input_message) {
1913   DVLOG(3) << "MediaLoadingFailed(" << *this << ", " << int{error}
1914            << ", message='" << input_message << "')";
1915
1916   bool should_be_opaque = MediaShouldBeOpaque();
1917   if (should_be_opaque)
1918     error = WebMediaPlayer::kNetworkStateNetworkError;
1919   String empty_string;
1920   const String& message = should_be_opaque ? empty_string : input_message;
1921
1922   StopPeriodicTimers();
1923
1924   // If we failed while trying to load a <source> element, the movie was never
1925   // parsed, and there are more <source> children, schedule the next one
1926   if (ready_state_ < kHaveMetadata &&
1927       load_state_ == kLoadingFromSourceElement) {
1928     // resource selection algorithm
1929     // Step 9.Otherwise.9 - Failed with elements: Queue a task, using the DOM
1930     // manipulation task source, to fire a simple event named error at the
1931     // candidate element.
1932     if (current_source_node_) {
1933       current_source_node_->ScheduleErrorEvent();
1934     } else {
1935       DVLOG(3) << "mediaLoadingFailed(" << *this
1936                << ") - error event not sent, <source> was removed";
1937     }
1938
1939     // 9.Otherwise.10 - Asynchronously await a stable state. The synchronous
1940     // section consists of all the remaining steps of this algorithm until the
1941     // algorithm says the synchronous section has ended.
1942
1943     // 9.Otherwise.11 - Forget the media element's media-resource-specific
1944     // tracks.
1945     ForgetResourceSpecificTracks();
1946
1947     if (HavePotentialSourceChild()) {
1948       DVLOG(3) << "mediaLoadingFailed(" << *this
1949                << ") - scheduling next <source>";
1950       ScheduleNextSourceChild();
1951     } else {
1952       DVLOG(3) << "mediaLoadingFailed(" << *this
1953                << ") - no more <source> elements, waiting";
1954       WaitForSourceChange();
1955     }
1956
1957     return;
1958   }
1959
1960   if (error == WebMediaPlayer::kNetworkStateNetworkError &&
1961       ready_state_ >= kHaveMetadata) {
1962     MediaEngineError(MakeGarbageCollected<MediaError>(
1963         MediaError::kMediaErrNetwork, message));
1964   } else if (error == WebMediaPlayer::kNetworkStateDecodeError) {
1965     MediaEngineError(
1966         MakeGarbageCollected<MediaError>(MediaError::kMediaErrDecode, message));
1967   } else if ((error == WebMediaPlayer::kNetworkStateFormatError ||
1968               error == WebMediaPlayer::kNetworkStateNetworkError) &&
1969              (load_state_ == kLoadingFromSrcAttr ||
1970               (load_state_ == kLoadingFromSrcObject &&
1971                src_object_media_source_handle_))) {
1972     if (message.empty()) {
1973       // Generate a more meaningful error message to differentiate the two types
1974       // of MEDIA_SRC_ERR_NOT_SUPPORTED.
1975       NoneSupported(BuildElementErrorMessage(
1976           error == WebMediaPlayer::kNetworkStateFormatError ? "Format error"
1977                                                             : "Network error"));
1978     } else {
1979       NoneSupported(message);
1980     }
1981   }
1982
1983   UpdateLayoutObject();
1984 }
1985
1986 void HTMLMediaElement::SetNetworkState(WebMediaPlayer::NetworkState state) {
1987   DVLOG(3) << "setNetworkState(" << *this << ", " << static_cast<int>(state)
1988            << ") - current state is " << int{network_state_};
1989
1990   if (state == WebMediaPlayer::kNetworkStateEmpty) {
1991     // Just update the cached state and leave, we can't do anything.
1992     SetNetworkState(kNetworkEmpty);
1993     return;
1994   }
1995
1996   if (state == WebMediaPlayer::kNetworkStateFormatError ||
1997       state == WebMediaPlayer::kNetworkStateNetworkError ||
1998       state == WebMediaPlayer::kNetworkStateDecodeError) {
1999     MediaLoadingFailed(state, web_media_player_->GetErrorMessage());
2000     return;
2001   }
2002
2003   if (state == WebMediaPlayer::kNetworkStateIdle) {
2004     if (network_state_ > kNetworkIdle) {
2005       ChangeNetworkStateFromLoadingToIdle();
2006     } else {
2007       SetNetworkState(kNetworkIdle);
2008     }
2009   }
2010
2011   if (state == WebMediaPlayer::kNetworkStateLoading) {
2012     if (network_state_ < kNetworkLoading || network_state_ == kNetworkNoSource)
2013       StartProgressEventTimer();
2014     SetNetworkState(kNetworkLoading);
2015   }
2016
2017   if (state == WebMediaPlayer::kNetworkStateLoaded) {
2018     if (network_state_ != kNetworkIdle)
2019       ChangeNetworkStateFromLoadingToIdle();
2020   }
2021 }
2022
2023 void HTMLMediaElement::ChangeNetworkStateFromLoadingToIdle() {
2024   progress_event_timer_.Stop();
2025
2026   if (!MediaShouldBeOpaque()) {
2027     // Schedule one last progress event so we guarantee that at least one is
2028     // fired for files that load very quickly.
2029     if (web_media_player_ && web_media_player_->DidLoadingProgress())
2030       ScheduleEvent(event_type_names::kProgress);
2031     ScheduleEvent(event_type_names::kSuspend);
2032     SetNetworkState(kNetworkIdle);
2033   } else {
2034     // TODO(dalecurtis): Replace c-style casts in follow up patch.
2035     DVLOG(1) << __func__ << "(" << *this
2036              << ") - Deferred network state change to idle for opaque media";
2037   }
2038 }
2039
2040 void HTMLMediaElement::ReadyStateChanged() {
2041   SetReadyState(static_cast<ReadyState>(web_media_player_->GetReadyState()));
2042 }
2043
2044 void HTMLMediaElement::SetReadyState(ReadyState state) {
2045   DVLOG(3) << "setReadyState(" << *this << ", " << int{state}
2046            << ") - current state is " << int{ready_state_};
2047
2048   // Set "wasPotentiallyPlaying" BEFORE updating ready_state_,
2049   // potentiallyPlaying() uses it
2050   bool was_potentially_playing = PotentiallyPlaying();
2051
2052   ReadyState old_state = ready_state_;
2053   ReadyState new_state = state;
2054
2055   bool tracks_are_ready = TextTracksAreReady();
2056
2057   if (new_state == old_state && tracks_are_ready_ == tracks_are_ready)
2058     return;
2059
2060   tracks_are_ready_ = tracks_are_ready;
2061
2062   if (tracks_are_ready) {
2063     ready_state_ = new_state;
2064   } else {
2065     // If a media file has text tracks the readyState may not progress beyond
2066     // kHaveFutureData until the text tracks are ready, regardless of the state
2067     // of the media file.
2068     if (new_state <= kHaveMetadata)
2069       ready_state_ = new_state;
2070     else
2071       ready_state_ = kHaveCurrentData;
2072   }
2073
2074   // If we're transitioning to / past kHaveMetadata, then cache the final URL.
2075   if (old_state < kHaveMetadata && new_state >= kHaveMetadata &&
2076       web_media_player_) {
2077     current_src_after_redirects_ =
2078         KURL(web_media_player_->GetSrcAfterRedirects());
2079
2080     // Sometimes WebMediaPlayer may load a URL from an in memory cache, which
2081     // skips notification of insecure content. Ensure we always notify the
2082     // MixedContentChecker of what happened, even if the load was skipped.
2083     if (LocalFrame* frame = GetDocument().GetFrame()) {
2084       const KURL& current_src_for_check = current_src_.GetSource();
2085       // We don't care about the return value here. The MixedContentChecker will
2086       // internally notify for insecure content if it needs to regardless of
2087       // what the return value ends up being for this call.
2088       MixedContentChecker::ShouldBlockFetch(
2089           frame,
2090           HasVideo() ? mojom::blink::RequestContextType::VIDEO
2091                      : mojom::blink::RequestContextType::AUDIO,
2092           network::mojom::blink::IPAddressSpace::kUnknown,
2093           current_src_for_check,
2094           // Strictly speaking, this check is an approximation; a request could
2095           // have have redirected back to its original URL, for example.
2096           // However, the redirect status is only used to prevent leaking
2097           // information cross-origin via CSP reports, so comparing URLs is
2098           // sufficient for that purpose.
2099           current_src_after_redirects_ == current_src_for_check
2100               ? ResourceRequest::RedirectStatus::kNoRedirect
2101               : ResourceRequest::RedirectStatus::kFollowedRedirect,
2102           current_src_after_redirects_, /* devtools_id= */ String(),
2103           ReportingDisposition::kReport,
2104           GetDocument().Loader()->GetContentSecurityNotifier());
2105     }
2106
2107     // Prior to kHaveMetadata |network_state_| may be inaccurate to avoid side
2108     // channel leaks. This be a no-op if nothing has changed.
2109     NetworkStateChanged();
2110   }
2111
2112   if (new_state > ready_state_maximum_)
2113     ready_state_maximum_ = new_state;
2114
2115   if (network_state_ == kNetworkEmpty)
2116     return;
2117
2118   if (seeking_) {
2119     // 4.8.12.9, step 9 note: If the media element was potentially playing
2120     // immediately before it started seeking, but seeking caused its readyState
2121     // attribute to change to a value lower than kHaveFutureData, then a waiting
2122     // will be fired at the element.
2123     if (was_potentially_playing && ready_state_ < kHaveFutureData)
2124       ScheduleEvent(event_type_names::kWaiting);
2125
2126     // 4.8.12.9 steps 12-14
2127     if (ready_state_ >= kHaveCurrentData)
2128       FinishSeek();
2129   } else {
2130     if (was_potentially_playing && ready_state_ < kHaveFutureData) {
2131       // Force an update to official playback position. Automatic updates from
2132       // currentPlaybackPosition() will be blocked while ready_state_ remains
2133       // < kHaveFutureData. This blocking is desired after 'waiting' has been
2134       // fired, but its good to update it one final time to accurately reflect
2135       // media time at the moment we ran out of data to play.
2136       SetOfficialPlaybackPosition(CurrentPlaybackPosition());
2137
2138       // 4.8.12.8
2139       ScheduleTimeupdateEvent(false);
2140       ScheduleEvent(event_type_names::kWaiting);
2141     }
2142   }
2143
2144   // Once enough of the media data has been fetched to determine the duration of
2145   // the media resource, its dimensions, and other metadata...
2146   if (ready_state_ >= kHaveMetadata && old_state < kHaveMetadata) {
2147     CreatePlaceholderTracksIfNecessary();
2148
2149     MediaFragmentURIParser fragment_parser(current_src_.GetSource());
2150     fragment_end_time_ = fragment_parser.EndTime();
2151
2152     // Set the current playback position and the official playback position to
2153     // the earliest possible position.
2154     SetOfficialPlaybackPosition(EarliestPossiblePosition());
2155
2156     duration_ = web_media_player_->Duration();
2157     ScheduleEvent(event_type_names::kDurationchange);
2158
2159     if (IsHTMLVideoElement())
2160       ScheduleEvent(event_type_names::kResize);
2161     ScheduleEvent(event_type_names::kLoadedmetadata);
2162
2163     bool jumped = false;
2164     if (default_playback_start_position_ > 0) {
2165       Seek(default_playback_start_position_);
2166       jumped = true;
2167     }
2168     default_playback_start_position_ = 0;
2169
2170     double initial_playback_position = fragment_parser.StartTime();
2171     if (std::isnan(initial_playback_position))
2172       initial_playback_position = 0;
2173
2174     if (!jumped && initial_playback_position > 0) {
2175       UseCounter::Count(GetDocument(),
2176                         WebFeature::kHTMLMediaElementSeekToFragmentStart);
2177       Seek(initial_playback_position);
2178       jumped = true;
2179     }
2180
2181     UpdateLayoutObject();
2182   }
2183
2184   bool is_potentially_playing = PotentiallyPlaying();
2185   if (ready_state_ >= kHaveCurrentData && old_state < kHaveCurrentData &&
2186       !have_fired_loaded_data_) {
2187     // Force an update to official playback position to catch non-zero start
2188     // times that were not known at kHaveMetadata, but are known now that the
2189     // first packets have been demuxed.
2190     SetOfficialPlaybackPosition(CurrentPlaybackPosition());
2191
2192     have_fired_loaded_data_ = true;
2193     ScheduleEvent(event_type_names::kLoadeddata);
2194     SetShouldDelayLoadEvent(false);
2195
2196     OnLoadFinished();
2197   }
2198
2199   if (ready_state_ == kHaveFutureData && old_state <= kHaveCurrentData &&
2200       tracks_are_ready) {
2201     ScheduleEvent(event_type_names::kCanplay);
2202     if (is_potentially_playing)
2203       ScheduleNotifyPlaying();
2204
2205 // for CASD url, when play, Webmedia pass the CASD url to hbbtv and
2206 // waiting for hbbtv parse and notify Webmedia the translated url when
2207 // translated url was set, replace the video tag src and cause the
2208 // previous MediaPlayerBridgeCapi destroy and then reload the new url So
2209 // when the translated url preload complete, we should call "play"
2210 // manually to make play continue
2211 #if BUILDFLAG(IS_TIZEN_TV)
2212     if (IsHbbTV() && is_translated_url_) {
2213       LOG(INFO) << "this is translated url,call play manually";
2214       is_translated_url_ = false;
2215       Play();
2216     }
2217 #endif
2218   }
2219
2220   if (ready_state_ == kHaveEnoughData && old_state < kHaveEnoughData &&
2221       tracks_are_ready) {
2222     if (old_state <= kHaveCurrentData) {
2223       ScheduleEvent(event_type_names::kCanplay);
2224       if (is_potentially_playing)
2225         ScheduleNotifyPlaying();
2226     }
2227
2228     if (autoplay_policy_->RequestAutoplayByAttribute()) {
2229       paused_ = false;
2230       SetShowPosterFlag(false);
2231       GetCueTimeline().InvokeTimeMarchesOn();
2232       ScheduleEvent(event_type_names::kPlay);
2233       ScheduleNotifyPlaying();
2234       can_autoplay_ = false;
2235     }
2236
2237     ScheduleEvent(event_type_names::kCanplaythrough);
2238   }
2239
2240   UpdatePlayState();
2241 }
2242
2243 void HTMLMediaElement::SetShowPosterFlag(bool value) {
2244   DVLOG(3) << "SetShowPosterFlag(" << *this << ", " << value
2245            << ") - current state is " << show_poster_flag_;
2246
2247   if (value == show_poster_flag_)
2248     return;
2249
2250   show_poster_flag_ = value;
2251   UpdateLayoutObject();
2252 }
2253
2254 void HTMLMediaElement::UpdateLayoutObject() {
2255   if (GetLayoutObject())
2256     GetLayoutObject()->UpdateFromElement();
2257 }
2258
2259 void HTMLMediaElement::ProgressEventTimerFired() {
2260   // The spec doesn't require to dispatch the "progress" or "stalled" events
2261   // when the resource fetch mode is "local".
2262   // https://html.spec.whatwg.org/multipage/media.html#concept-media-load-resource
2263   // The mode is "local" for these sources:
2264   //
2265   // MediaStream: The timer is stopped below to prevent the "progress" event
2266   // from being dispatched more than once. It is dispatched once to match
2267   // Safari's behavior, even though that's not required by the spec.
2268   //
2269   // MediaSource: The "stalled" event is not dispatched but a conscious decision
2270   // was made to periodically dispatch the "progress" event to allow updates to
2271   // buffering UIs. Therefore, the timer is not stopped below.
2272   // https://groups.google.com/a/chromium.org/g/media-dev/c/Y8ITyIFmUC0/m/avBYOy_UFwAJ
2273   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream) {
2274     progress_event_timer_.Stop();
2275   }
2276
2277   if (network_state_ != kNetworkLoading) {
2278     RecordProgressEventTimerState(ProgressEventTimerState::kNotLoading);
2279     return;
2280   }
2281
2282   // If this is an cross-origin request, and we haven't discovered whether
2283   // the media is actually playable yet, don't fire any progress events as
2284   // those may let the page know information about the resource that it's
2285   // not supposed to know.
2286   if (MediaShouldBeOpaque()) {
2287     RecordProgressEventTimerState(
2288         ProgressEventTimerState::kMediaShouldBeOpaque);
2289     return;
2290   }
2291
2292   DCHECK(previous_progress_time_);
2293
2294   if (web_media_player_ && web_media_player_->DidLoadingProgress()) {
2295     ScheduleEvent(event_type_names::kProgress);
2296     previous_progress_time_ = base::ElapsedTimer();
2297     sent_stalled_event_ = false;
2298     UpdateLayoutObject();
2299     RecordProgressEventTimerState(ProgressEventTimerState::kProgress);
2300   } else if (media_source_attachment_) {
2301     RecordProgressEventTimerState(
2302         ProgressEventTimerState::kHasMediaSourceAttachment);
2303   } else if (previous_progress_time_->Elapsed() <=
2304              kStalledNotificationInterval) {
2305     RecordProgressEventTimerState(ProgressEventTimerState::kRecentProgress);
2306   } else if (sent_stalled_event_) {
2307     RecordProgressEventTimerState(
2308         ProgressEventTimerState::kStalledEventAlreadyScheduled);
2309   } else {
2310     // Note the !media_source_attachment_ condition above. The 'stalled' event
2311     // is not fired when using MSE. MSE's resource is considered 'local' (we
2312     // don't manage the download - the app does), so the HTML5 spec text around
2313     // 'stalled' does not apply. See discussion in https://crbug.com/517240 We
2314     // also don't need to take any action wrt delaying-the-load-event.
2315     // MediaSource disables the delayed load when first attached.
2316     ScheduleEvent(event_type_names::kStalled);
2317     sent_stalled_event_ = true;
2318     SetShouldDelayLoadEvent(false);
2319     RecordProgressEventTimerState(ProgressEventTimerState::kStalled);
2320   }
2321 }
2322
2323 void HTMLMediaElement::AddPlayedRange(double start, double end) {
2324   DVLOG(3) << "addPlayedRange(" << *this << ", " << start << ", " << end << ")";
2325   if (!played_time_ranges_)
2326     played_time_ranges_ = MakeGarbageCollected<TimeRanges>();
2327   played_time_ranges_->Add(start, end);
2328 }
2329
2330 bool HTMLMediaElement::SupportsSave() const {
2331   // Check if download is disabled per settings.
2332   if (GetDocument().GetSettings() &&
2333       GetDocument().GetSettings()->GetHideDownloadUI()) {
2334     return false;
2335   }
2336
2337   // Get the URL that we'll use for downloading.
2338   const KURL url = downloadURL();
2339
2340   // URLs that lead to nowhere are ignored.
2341   if (url.IsNull() || url.IsEmpty())
2342     return false;
2343
2344   // If we have no source, we can't download.
2345   if (network_state_ == kNetworkEmpty || network_state_ == kNetworkNoSource)
2346     return false;
2347
2348   // It is not useful to offer a save feature on local files.
2349   if (url.IsLocalFile())
2350     return false;
2351
2352   // MediaStream can't be downloaded.
2353   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2354     return false;
2355
2356   // MediaSource can't be downloaded.
2357   if (HasMediaSource())
2358     return false;
2359
2360   // HLS stream shouldn't have a download button.
2361   if (IsHLSURL(url))
2362     return false;
2363
2364   // Infinite streams don't have a clear end at which to finish the download.
2365   if (duration() == std::numeric_limits<double>::infinity())
2366     return false;
2367
2368   return true;
2369 }
2370
2371 bool HTMLMediaElement::SupportsLoop() const {
2372   // MediaStream can't be looped.
2373   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2374     return false;
2375
2376   // Infinite streams don't have a clear end at which to loop.
2377   if (duration() == std::numeric_limits<double>::infinity())
2378     return false;
2379
2380   return true;
2381 }
2382
2383 void HTMLMediaElement::SetIgnorePreloadNone() {
2384   DVLOG(3) << "setIgnorePreloadNone(" << *this << ")";
2385   ignore_preload_none_ = true;
2386   SetPlayerPreload();
2387 }
2388
2389 void HTMLMediaElement::Seek(double time) {
2390   DVLOG(2) << "seek(" << *this << ", " << time << ")";
2391
2392   // 1 - Set the media element's show poster flag to false.
2393   SetShowPosterFlag(false);
2394
2395   // 2 - If the media element's readyState is HAVE_NOTHING, abort these steps.
2396   // FIXME: remove web_media_player_ check once we figure out how
2397   // web_media_player_ is going out of sync with readystate.
2398   // web_media_player_ is cleared but readystate is not set to HAVE_NOTHING.
2399   if (!web_media_player_ || ready_state_ == kHaveNothing)
2400     return;
2401
2402   // Ignore preload none and start load if necessary.
2403   SetIgnorePreloadNone();
2404
2405   // Get the current time before setting seeking_, last_seek_time_ is returned
2406   // once it is set.
2407   double now = currentTime();
2408
2409   // 3 - If the element's seeking IDL attribute is true, then another instance
2410   // of this algorithm is already running. Abort that other instance of the
2411   // algorithm without waiting for the step that it is running to complete.
2412   // Nothing specific to be done here.
2413
2414   // 4 - Set the seeking IDL attribute to true.
2415   // The flag will be cleared when the engine tells us the time has actually
2416   // changed.
2417   seeking_ = true;
2418
2419   // 6 - If the new playback position is later than the end of the media
2420   // resource, then let it be the end of the media resource instead.
2421   time = std::min(time, duration());
2422
2423   // 7 - If the new playback position is less than the earliest possible
2424   // position, let it be that position instead.
2425   time = std::max(time, EarliestPossiblePosition());
2426
2427   // Ask the media engine for the time value in the movie's time scale before
2428   // comparing with current time. This is necessary because if the seek time is
2429   // not equal to currentTime but the delta is less than the movie's time scale,
2430   // we will ask the media engine to "seek" to the current movie time, which may
2431   // be a noop and not generate a timechanged callback. This means seeking_
2432   // will never be cleared and we will never fire a 'seeked' event.
2433   double media_time = web_media_player_->MediaTimeForTimeValue(time);
2434   if (time != media_time) {
2435     DVLOG(3) << "seek(" << *this << ", " << time
2436              << ") - media timeline equivalent is " << media_time;
2437     time = media_time;
2438   }
2439
2440   // 8 - If the (possibly now changed) new playback position is not in one of
2441   // the ranges given in the seekable attribute, then let it be the position in
2442   // one of the ranges given in the seekable attribute that is the nearest to
2443   // the new playback position. ... If there are no ranges given in the seekable
2444   // attribute then set the seeking IDL attribute to false and abort these
2445   // steps.
2446   WebTimeRanges seekable_ranges = SeekableInternal();
2447
2448   if (seekable_ranges.empty()) {
2449     seeking_ = false;
2450     return;
2451   }
2452   time = seekable_ranges.Nearest(time, now);
2453
2454   if (playing_ && last_seek_time_ < now)
2455     AddPlayedRange(last_seek_time_, now);
2456
2457   last_seek_time_ = time;
2458
2459   // 10 - Queue a task to fire a simple event named seeking at the element.
2460   ScheduleEvent(event_type_names::kSeeking);
2461
2462   // 11 - Set the current playback position to the given new playback position.
2463   web_media_player_->Seek(time);
2464   web_media_player_->OnTimeUpdate();
2465
2466   // 14-17 are handled, if necessary, when the engine signals a readystate
2467   // change or otherwise satisfies seek completion and signals a time change.
2468 }
2469
2470 void HTMLMediaElement::FinishSeek() {
2471   DVLOG(3) << "finishSeek(" << *this << ")";
2472
2473   // 14 - Set the seeking IDL attribute to false.
2474   seeking_ = false;
2475
2476   // Force an update to officialPlaybackPosition. Periodic updates generally
2477   // handle this, but may be skipped paused or waiting for data.
2478   SetOfficialPlaybackPosition(CurrentPlaybackPosition());
2479
2480   // 15 - Run the time marches on steps.
2481   GetCueTimeline().InvokeTimeMarchesOn();
2482
2483   // 16 - Queue a task to fire a simple event named timeupdate at the element.
2484   ScheduleTimeupdateEvent(false);
2485
2486   // 17 - Queue a task to fire a simple event named seeked at the element.
2487   ScheduleEvent(event_type_names::kSeeked);
2488 }
2489
2490 HTMLMediaElement::ReadyState HTMLMediaElement::getReadyState() const {
2491   return ready_state_;
2492 }
2493
2494 bool HTMLMediaElement::HasVideo() const {
2495   return web_media_player_ && web_media_player_->HasVideo();
2496 }
2497
2498 bool HTMLMediaElement::HasAudio() const {
2499   return web_media_player_ && web_media_player_->HasAudio();
2500 }
2501
2502 bool HTMLMediaElement::IsEncrypted() const {
2503   return is_encrypted_media_;
2504 }
2505
2506 bool HTMLMediaElement::seeking() const {
2507   return seeking_;
2508 }
2509
2510 // https://www.w3.org/TR/html51/semantics-embedded-content.html#earliest-possible-position
2511 // The earliest possible position is not explicitly exposed in the API; it
2512 // corresponds to the start time of the first range in the seekable attribute’s
2513 // TimeRanges object, if any, or the current playback position otherwise.
2514 double HTMLMediaElement::EarliestPossiblePosition() const {
2515   WebTimeRanges seekable_ranges = SeekableInternal();
2516   if (!seekable_ranges.empty())
2517     return seekable_ranges.front().start;
2518
2519   return CurrentPlaybackPosition();
2520 }
2521
2522 double HTMLMediaElement::CurrentPlaybackPosition() const {
2523   // "Official" playback position won't take updates from "current" playback
2524   // position until ready_state_ > kHaveMetadata, but other callers (e.g.
2525   // pauseInternal) may still request currentPlaybackPosition at any time.
2526   // From spec: "Media elements have a current playback position, which must
2527   // initially (i.e., in the absence of media data) be zero seconds."
2528   if (ready_state_ == kHaveNothing)
2529     return 0;
2530
2531   if (web_media_player_)
2532     return web_media_player_->CurrentTime();
2533
2534   if (ready_state_ >= kHaveMetadata) {
2535     DVLOG(3) << __func__ << " readyState = " << ready_state_
2536              << " but no webMediaPlayer to provide currentPlaybackPosition";
2537   }
2538
2539   return 0;
2540 }
2541
2542 double HTMLMediaElement::OfficialPlaybackPosition() const {
2543   // Hold updates to official playback position while paused or waiting for more
2544   // data. The underlying media player may continue to make small advances in
2545   // currentTime (e.g. as samples in the last rendered audio buffer are played
2546   // played out), but advancing currentTime while paused/waiting sends a mixed
2547   // signal about the state of playback.
2548   bool waiting_for_data = ready_state_ <= kHaveCurrentData;
2549   if (official_playback_position_needs_update_ && !paused_ &&
2550       !waiting_for_data) {
2551     SetOfficialPlaybackPosition(CurrentPlaybackPosition());
2552   }
2553
2554 #if LOG_OFFICIAL_TIME_STATUS
2555   static const double kMinCachedDeltaForWarning = 0.01;
2556   double delta =
2557       std::abs(official_playback_position_ - CurrentPlaybackPosition());
2558   if (delta > kMinCachedDeltaForWarning) {
2559     DVLOG(3) << "CurrentTime(" << (void*)this << ") - WARNING, cached time is "
2560              << delta << "seconds off of media time when paused/waiting";
2561   }
2562 #endif
2563
2564   return official_playback_position_;
2565 }
2566
2567 void HTMLMediaElement::SetOfficialPlaybackPosition(double position) const {
2568 #if LOG_OFFICIAL_TIME_STATUS
2569   DVLOG(3) << "SetOfficialPlaybackPosition(" << (void*)this
2570            << ") was:" << official_playback_position_ << " now:" << position;
2571 #endif
2572
2573   // Internal player position may advance slightly beyond duration because
2574   // many files use imprecise duration. Clamp official position to duration when
2575   // known. Duration may be unknown when readyState < HAVE_METADATA.
2576   official_playback_position_ =
2577       std::isnan(duration()) ? position : std::min(duration(), position);
2578
2579   if (official_playback_position_ != position) {
2580     DVLOG(3) << "setOfficialPlaybackPosition(" << *this
2581              << ") position:" << position
2582              << " truncated to duration:" << official_playback_position_;
2583   }
2584
2585   // Once set, official playback position should hold steady until the next
2586   // stable state. We approximate this by using a microtask to mark the
2587   // need for an update after the current (micro)task has completed. When
2588   // needed, the update is applied in the next call to
2589   // officialPlaybackPosition().
2590   official_playback_position_needs_update_ = false;
2591   GetDocument().GetAgent().event_loop()->EnqueueMicrotask(
2592       WTF::BindOnce(&HTMLMediaElement::RequireOfficialPlaybackPositionUpdate,
2593                     WrapWeakPersistent(this)));
2594 }
2595
2596 void HTMLMediaElement::RequireOfficialPlaybackPositionUpdate() const {
2597   official_playback_position_needs_update_ = true;
2598 }
2599
2600 double HTMLMediaElement::currentTime() const {
2601   if (default_playback_start_position_)
2602     return default_playback_start_position_;
2603
2604   if (seeking_) {
2605     DVLOG(3) << "currentTime(" << *this << ") - seeking, returning "
2606              << last_seek_time_;
2607     return last_seek_time_;
2608   }
2609
2610   return OfficialPlaybackPosition();
2611 }
2612
2613 void HTMLMediaElement::setCurrentTime(double time) {
2614   // If the media element's readyState is kHaveNothing, then set the default
2615   // playback start position to that time.
2616   if (ready_state_ == kHaveNothing) {
2617     default_playback_start_position_ = time;
2618   } else {
2619     Seek(time);
2620   }
2621
2622   ReportCurrentTimeToMediaSource();
2623 }
2624
2625 double HTMLMediaElement::duration() const {
2626   return duration_;
2627 }
2628
2629 bool HTMLMediaElement::paused() const {
2630   return paused_;
2631 }
2632
2633 double HTMLMediaElement::defaultPlaybackRate() const {
2634   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2635     return 1.0;
2636   return default_playback_rate_;
2637 }
2638
2639 void HTMLMediaElement::setDefaultPlaybackRate(double rate) {
2640   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2641     return;
2642
2643   if (default_playback_rate_ == rate || !IsValidPlaybackRate(rate))
2644     return;
2645
2646   default_playback_rate_ = rate;
2647   ScheduleEvent(event_type_names::kRatechange);
2648 }
2649
2650 double HTMLMediaElement::playbackRate() const {
2651   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2652     return 1.0;
2653   return playback_rate_;
2654 }
2655
2656 void HTMLMediaElement::setPlaybackRate(double rate,
2657                                        ExceptionState& exception_state) {
2658   DVLOG(3) << "setPlaybackRate(" << *this << ", " << rate << ")";
2659   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2660     return;
2661
2662   if (!IsValidPlaybackRate(rate)) {
2663     UseCounter::Count(GetDocument(),
2664                       WebFeature::kHTMLMediaElementMediaPlaybackRateOutOfRange);
2665
2666     // When the proposed playbackRate is unsupported, throw a NotSupportedError
2667     // DOMException and don't update the value.
2668     exception_state.ThrowDOMException(
2669         DOMExceptionCode::kNotSupportedError,
2670         "The provided playback rate (" + String::Number(rate) +
2671             ") is not in the " + "supported playback range.");
2672
2673     // Do not update |playback_rate_|.
2674     return;
2675   }
2676
2677   if (playback_rate_ != rate) {
2678     playback_rate_ = rate;
2679     ScheduleEvent(event_type_names::kRatechange);
2680   }
2681
2682   // FIXME: remove web_media_player_ check once we figure out how
2683   // web_media_player_ is going out of sync with readystate.
2684   // web_media_player_ is cleared but readystate is not set to kHaveNothing.
2685   if (web_media_player_) {
2686     if (PotentiallyPlaying())
2687       web_media_player_->SetRate(playbackRate());
2688
2689     web_media_player_->OnTimeUpdate();
2690   }
2691
2692   if (cue_timeline_ && PotentiallyPlaying())
2693     cue_timeline_->OnPlaybackRateUpdated();
2694 }
2695
2696 HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::GetDirectionOfPlayback()
2697     const {
2698   return playback_rate_ >= 0 ? kForward : kBackward;
2699 }
2700
2701 bool HTMLMediaElement::ended() const {
2702   // 4.8.12.8 Playing the media resource
2703   // The ended attribute must return true if the media element has ended
2704   // playback and the direction of playback is forwards, and false otherwise.
2705   return EndedPlayback() && GetDirectionOfPlayback() == kForward;
2706 }
2707
2708 bool HTMLMediaElement::Autoplay() const {
2709   return FastHasAttribute(html_names::kAutoplayAttr);
2710 }
2711
2712 String HTMLMediaElement::preload() const {
2713   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2714     return PreloadTypeToString(WebMediaPlayer::kPreloadNone);
2715   return PreloadTypeToString(PreloadType());
2716 }
2717
2718 void HTMLMediaElement::setPreload(const AtomicString& preload) {
2719   DVLOG(2) << "setPreload(" << *this << ", " << preload << ")";
2720   if (GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
2721     return;
2722   setAttribute(html_names::kPreloadAttr, preload);
2723 }
2724
2725 WebMediaPlayer::Preload HTMLMediaElement::PreloadType() const {
2726   const AtomicString& preload = FastGetAttribute(html_names::kPreloadAttr);
2727   if (EqualIgnoringASCIICase(preload, "none")) {
2728     UseCounter::Count(GetDocument(), WebFeature::kHTMLMediaElementPreloadNone);
2729     return WebMediaPlayer::kPreloadNone;
2730   }
2731
2732   if (EqualIgnoringASCIICase(preload, "metadata")) {
2733     UseCounter::Count(GetDocument(),
2734                       WebFeature::kHTMLMediaElementPreloadMetadata);
2735     return WebMediaPlayer::kPreloadMetaData;
2736   }
2737
2738   // Force preload to 'metadata' on cellular connections.
2739   if (GetNetworkStateNotifier().IsCellularConnectionType()) {
2740     UseCounter::Count(GetDocument(),
2741                       WebFeature::kHTMLMediaElementPreloadForcedMetadata);
2742     return WebMediaPlayer::kPreloadMetaData;
2743   }
2744
2745   // Per HTML spec, "The empty string ... maps to the Automatic state."
2746   // https://html.spec.whatwg.org/C/#attr-media-preload
2747   if (EqualIgnoringASCIICase(preload, "auto") ||
2748       EqualIgnoringASCIICase(preload, "")) {
2749     UseCounter::Count(GetDocument(), WebFeature::kHTMLMediaElementPreloadAuto);
2750     return WebMediaPlayer::kPreloadAuto;
2751   }
2752
2753   // "The attribute's missing value default is user-agent defined, though the
2754   // Metadata state is suggested as a compromise between reducing server load
2755   // and providing an optimal user experience."
2756
2757   // The spec does not define an invalid value default:
2758   // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28950
2759   UseCounter::Count(GetDocument(), WebFeature::kHTMLMediaElementPreloadDefault);
2760   return WebMediaPlayer::kPreloadMetaData;
2761 }
2762
2763 String HTMLMediaElement::EffectivePreload() const {
2764   return PreloadTypeToString(EffectivePreloadType());
2765 }
2766
2767 WebMediaPlayer::Preload HTMLMediaElement::EffectivePreloadType() const {
2768   if (Autoplay() && !autoplay_policy_->IsGestureNeededForPlayback())
2769     return WebMediaPlayer::kPreloadAuto;
2770
2771   WebMediaPlayer::Preload preload = PreloadType();
2772   if (ignore_preload_none_ && preload == WebMediaPlayer::kPreloadNone)
2773     return WebMediaPlayer::kPreloadMetaData;
2774
2775   return preload;
2776 }
2777
2778 ScriptPromise HTMLMediaElement::playForBindings(ScriptState* script_state) {
2779   // We have to share the same logic for internal and external callers. The
2780   // internal callers do not want to receive a Promise back but when ::play()
2781   // is called, |play_promise_resolvers_| needs to be populated. What this code
2782   // does is to populate |play_promise_resolvers_| before calling ::play() and
2783   // remove the Promise if ::play() failed.
2784   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
2785   ScriptPromise promise = resolver->Promise();
2786   play_promise_resolvers_.push_back(resolver);
2787
2788   absl::optional<DOMExceptionCode> code = Play();
2789   if (code) {
2790     DCHECK(!play_promise_resolvers_.empty());
2791     play_promise_resolvers_.pop_back();
2792
2793     String message;
2794     switch (code.value()) {
2795       case DOMExceptionCode::kNotAllowedError:
2796         message = autoplay_policy_->GetPlayErrorMessage();
2797         break;
2798       case DOMExceptionCode::kNotSupportedError:
2799         message = "The element has no supported sources.";
2800         break;
2801       default:
2802         NOTREACHED();
2803     }
2804     resolver->Reject(MakeGarbageCollected<DOMException>(code.value(), message));
2805     return promise;
2806   }
2807
2808   return promise;
2809 }
2810
2811 absl::optional<DOMExceptionCode> HTMLMediaElement::Play() {
2812   DVLOG(2) << "play(" << *this << ")";
2813
2814   absl::optional<DOMExceptionCode> exception_code =
2815       autoplay_policy_->RequestPlay();
2816 #if BUILDFLAG(IS_TIZEN_TV)
2817   is_deactivate_ = false;
2818 #endif
2819
2820   if (exception_code == DOMExceptionCode::kNotAllowedError) {
2821     // If we're already playing, then this play would do nothing anyway.
2822     // Call playInternal to handle scheduling the promise resolution.
2823     if (!paused_) {
2824       PlayInternal();
2825       return absl::nullopt;
2826     }
2827     return exception_code;
2828   }
2829
2830   autoplay_policy_->StopAutoplayMutedWhenVisible();
2831
2832   if (error_ && error_->code() == MediaError::kMediaErrSrcNotSupported)
2833     return DOMExceptionCode::kNotSupportedError;
2834
2835   DCHECK(!exception_code.has_value());
2836
2837   PlayInternal();
2838
2839   return absl::nullopt;
2840 }
2841
2842 void HTMLMediaElement::PlayInternal() {
2843   DVLOG(3) << "playInternal(" << *this << ")";
2844
2845   if (web_media_player_) {
2846     web_media_player_->SetWasPlayedWithUserActivation(
2847         LocalFrame::HasTransientUserActivation(GetDocument().GetFrame()));
2848   }
2849
2850   // Playback aborts any lazy loading.
2851   if (lazy_load_intersection_observer_) {
2852     lazy_load_intersection_observer_->disconnect();
2853     lazy_load_intersection_observer_ = nullptr;
2854   }
2855
2856   // 4.8.12.8. Playing the media resource
2857   if (network_state_ == kNetworkEmpty)
2858     InvokeResourceSelectionAlgorithm();
2859
2860   // Generally "ended" and "looping" are exclusive. Here, the loop attribute
2861   // is ignored to seek back to start in case loop was set after playback
2862   // ended. See http://crbug.com/364442
2863   if (EndedPlayback(LoopCondition::kIgnored))
2864     Seek(0);
2865
2866   if (paused_) {
2867     paused_ = false;
2868     SetShowPosterFlag(false);
2869     GetCueTimeline().InvokeTimeMarchesOn();
2870     ScheduleEvent(event_type_names::kPlay);
2871
2872     if (ready_state_ <= kHaveCurrentData)
2873       ScheduleEvent(event_type_names::kWaiting);
2874     else if (ready_state_ >= kHaveFutureData)
2875       ScheduleNotifyPlaying();
2876   } else if (ready_state_ >= kHaveFutureData) {
2877     ScheduleResolvePlayPromises();
2878   }
2879
2880   can_autoplay_ = false;
2881
2882   OnPlay();
2883
2884   SetIgnorePreloadNone();
2885   UpdatePlayState();
2886 }
2887
2888 void HTMLMediaElement::pause() {
2889   DVLOG(2) << "pause(" << *this << ")";
2890
2891   // When updating pause, be sure to update PauseToLetDescriptionFinish().
2892   autoplay_policy_->StopAutoplayMutedWhenVisible();
2893   PauseInternal(PlayPromiseError::kPaused_PauseCalled);
2894 }
2895
2896 void HTMLMediaElement::PauseToLetDescriptionFinish() {
2897   DVLOG(2) << "pauseExceptSpeech(" << *this << ")";
2898
2899   autoplay_policy_->StopAutoplayMutedWhenVisible();
2900
2901   // Passing in pause_speech as false to pause everything except the speech.
2902   PauseInternal(PlayPromiseError::kPaused_PauseCalled, false);
2903 }
2904
2905 void HTMLMediaElement::PauseInternal(PlayPromiseError code,
2906                                      bool pause_speech /* = true */) {
2907   DVLOG(3) << "pauseInternal(" << *this << ")";
2908
2909   if (network_state_ == kNetworkEmpty)
2910     InvokeResourceSelectionAlgorithm();
2911
2912   can_autoplay_ = false;
2913
2914   if (!paused_) {
2915     paused_ = true;
2916     ScheduleTimeupdateEvent(false);
2917     ScheduleEvent(event_type_names::kPause);
2918
2919     // Force an update to official playback position. Automatic updates from
2920     // currentPlaybackPosition() will be blocked while paused_ = true. This
2921     // blocking is desired while paused, but its good to update it one final
2922     // time to accurately reflect movie time at the moment we paused.
2923     SetOfficialPlaybackPosition(CurrentPlaybackPosition());
2924
2925     ScheduleRejectPlayPromises(code);
2926   }
2927
2928   UpdatePlayState(pause_speech);
2929 }
2930
2931 bool HTMLMediaElement::preservesPitch() const {
2932   return preserves_pitch_;
2933 }
2934
2935 void HTMLMediaElement::setPreservesPitch(bool preserves_pitch) {
2936   preserves_pitch_ = preserves_pitch;
2937
2938   if (web_media_player_)
2939     web_media_player_->SetPreservesPitch(preserves_pitch_);
2940 }
2941
2942 double HTMLMediaElement::latencyHint() const {
2943   // Parse error will fallback to std::numeric_limits<double>::quiet_NaN()
2944   double seconds = GetFloatingPointAttribute(html_names::kLatencyhintAttr);
2945
2946   // Return NaN for invalid values.
2947   if (!std::isfinite(seconds) || seconds < 0)
2948     return std::numeric_limits<double>::quiet_NaN();
2949
2950   return seconds;
2951 }
2952
2953 void HTMLMediaElement::setLatencyHint(double seconds) {
2954   SetFloatingPointAttribute(html_names::kLatencyhintAttr, seconds);
2955 }
2956
2957 void HTMLMediaElement::FlingingStarted() {
2958   if (web_media_player_)
2959     web_media_player_->FlingingStarted();
2960 }
2961
2962 void HTMLMediaElement::FlingingStopped() {
2963   if (web_media_player_)
2964     web_media_player_->FlingingStopped();
2965 }
2966
2967 void HTMLMediaElement::CloseMediaSource() {
2968   if (!media_source_attachment_)
2969     return;
2970
2971   media_source_attachment_->Close(media_source_tracer_);
2972   media_source_attachment_.reset();
2973   media_source_tracer_ = nullptr;
2974 }
2975
2976 bool HTMLMediaElement::Loop() const {
2977   return FastHasAttribute(html_names::kLoopAttr);
2978 }
2979
2980 void HTMLMediaElement::SetLoop(bool b) {
2981   DVLOG(3) << "setLoop(" << *this << ", " << BoolString(b) << ")";
2982   SetBooleanAttribute(html_names::kLoopAttr, b);
2983 }
2984
2985 bool HTMLMediaElement::ShouldShowControls(
2986     const RecordMetricsBehavior record_metrics) const {
2987   Settings* settings = GetDocument().GetSettings();
2988   if (settings && !settings->GetMediaControlsEnabled()) {
2989     if (record_metrics == RecordMetricsBehavior::kDoRecord)
2990       RecordShowControlsUsage(this, MediaControlsShow::kDisabledSettings);
2991     return false;
2992   }
2993
2994   // If the user has explicitly shown or hidden the controls, then force that
2995   // choice.
2996   if (user_wants_controls_visible_.has_value()) {
2997     if (record_metrics == RecordMetricsBehavior::kDoRecord) {
2998       RecordShowControlsUsage(this,
2999                               *user_wants_controls_visible_
3000                                   ? MediaControlsShow::kUserExplicitlyEnabled
3001                                   : MediaControlsShow::kUserExplicitlyDisabled);
3002     }
3003     return *user_wants_controls_visible_;
3004   }
3005
3006   if (FastHasAttribute(html_names::kControlsAttr)) {
3007     if (record_metrics == RecordMetricsBehavior::kDoRecord)
3008       RecordShowControlsUsage(this, MediaControlsShow::kAttribute);
3009     return true;
3010   }
3011
3012   if (IsFullscreen()) {
3013     if (record_metrics == RecordMetricsBehavior::kDoRecord)
3014       RecordShowControlsUsage(this, MediaControlsShow::kFullscreen);
3015     return true;
3016   }
3017
3018   ExecutionContext* context = GetExecutionContext();
3019   if (context && !context->CanExecuteScripts(kNotAboutToExecuteScript)) {
3020     if (record_metrics == RecordMetricsBehavior::kDoRecord)
3021       RecordShowControlsUsage(this, MediaControlsShow::kNoScript);
3022     return true;
3023   }
3024
3025   if (record_metrics == RecordMetricsBehavior::kDoRecord)
3026     RecordShowControlsUsage(this, MediaControlsShow::kNotShown);
3027   return false;
3028 }
3029
3030 bool HTMLMediaElement::ShouldShowAllControls() const {
3031   // If the user has explicitly shown or hidden the controls, then force that
3032   // choice. Otherwise returns whether controls should be shown and no controls
3033   // are meant to be hidden.
3034   return user_wants_controls_visible_.value_or(
3035       ShouldShowControls() && !ControlsListInternal()->CanShowAllControls());
3036 }
3037
3038 DOMTokenList* HTMLMediaElement::controlsList() const {
3039   return controls_list_.Get();
3040 }
3041
3042 HTMLMediaElementControlsList* HTMLMediaElement::ControlsListInternal() const {
3043   return controls_list_.Get();
3044 }
3045
3046 double HTMLMediaElement::volume() const {
3047   return volume_;
3048 }
3049
3050 void HTMLMediaElement::setVolume(double vol, ExceptionState& exception_state) {
3051   DVLOG(2) << "setVolume(" << *this << ", " << vol << ")";
3052
3053   if (volume_ == vol)
3054     return;
3055
3056   if (RuntimeEnabledFeatures::MediaElementVolumeGreaterThanOneEnabled()) {
3057     if (vol < 0.0f) {
3058       exception_state.ThrowDOMException(
3059           DOMExceptionCode::kIndexSizeError,
3060           ExceptionMessages::IndexExceedsMinimumBound("volume", vol, 0.0));
3061       return;
3062     }
3063   } else if (vol < 0.0f || vol > 1.0f) {
3064     exception_state.ThrowDOMException(
3065         DOMExceptionCode::kIndexSizeError,
3066         ExceptionMessages::IndexOutsideRange(
3067             "volume", vol, 0.0, ExceptionMessages::kInclusiveBound, 1.0,
3068             ExceptionMessages::kInclusiveBound));
3069     return;
3070   }
3071
3072   volume_ = vol;
3073
3074   ScheduleEvent(event_type_names::kVolumechange);
3075
3076   // If it setting volume to audible and AutoplayPolicy doesn't want the
3077   // playback to continue, pause the playback.
3078   if (EffectiveMediaVolume() && !autoplay_policy_->RequestAutoplayUnmute())
3079     pause();
3080
3081   // If playback was not paused by the autoplay policy and got audible, the
3082   // element is marked as being allowed to play unmuted.
3083   if (EffectiveMediaVolume() && PotentiallyPlaying())
3084     was_always_muted_ = false;
3085
3086   if (web_media_player_)
3087     web_media_player_->SetVolume(EffectiveMediaVolume());
3088
3089   autoplay_policy_->StopAutoplayMutedWhenVisible();
3090 }
3091
3092 bool HTMLMediaElement::muted() const {
3093   return muted_;
3094 }
3095
3096 void HTMLMediaElement::setMuted(bool muted) {
3097   DVLOG(2) << "setMuted(" << *this << ", " << BoolString(muted) << ")";
3098
3099   if (muted_ == muted)
3100     return;
3101
3102   muted_ = muted;
3103
3104   ScheduleEvent(event_type_names::kVolumechange);
3105
3106   // If it is unmute and AutoplayPolicy doesn't want the playback to continue,
3107   // pause the playback.
3108   if (EffectiveMediaVolume() && !autoplay_policy_->RequestAutoplayUnmute())
3109     pause();
3110
3111   // If playback was not paused by the autoplay policy and got unmuted, the
3112   // element is marked as being allowed to play unmuted.
3113   if (EffectiveMediaVolume() && PotentiallyPlaying())
3114     was_always_muted_ = false;
3115
3116   // This is called at the end to make sure the WebMediaPlayer has the right
3117   // information.
3118   if (web_media_player_)
3119     web_media_player_->SetVolume(EffectiveMediaVolume());
3120
3121   autoplay_policy_->StopAutoplayMutedWhenVisible();
3122 }
3123
3124 void HTMLMediaElement::SetUserWantsControlsVisible(bool visible) {
3125   user_wants_controls_visible_ = visible;
3126   UpdateControlsVisibility();
3127 }
3128
3129 bool HTMLMediaElement::UserWantsControlsVisible() const {
3130   return user_wants_controls_visible_.value_or(false);
3131 }
3132
3133 double HTMLMediaElement::EffectiveMediaVolume() const {
3134   if (muted_)
3135     return 0;
3136
3137   return volume_;
3138 }
3139
3140 // The spec says to fire periodic timeupdate events (those sent while playing)
3141 // every "15 to 250ms", we choose the slowest frequency
3142 static const base::TimeDelta kMaxTimeupdateEventFrequency =
3143     base::Milliseconds(250);
3144
3145 void HTMLMediaElement::StartPlaybackProgressTimer() {
3146   if (playback_progress_timer_.IsActive())
3147     return;
3148
3149   previous_progress_time_ = base::ElapsedTimer();
3150   playback_progress_timer_.StartRepeating(kMaxTimeupdateEventFrequency);
3151 }
3152
3153 void HTMLMediaElement::PlaybackProgressTimerFired() {
3154   if (!std::isnan(fragment_end_time_) && currentTime() >= fragment_end_time_ &&
3155       GetDirectionOfPlayback() == kForward) {
3156     fragment_end_time_ = std::numeric_limits<double>::quiet_NaN();
3157     if (!paused_) {
3158       UseCounter::Count(GetDocument(),
3159                         WebFeature::kHTMLMediaElementPauseAtFragmentEnd);
3160       // changes paused to true and fires a simple event named pause at the
3161       // media element.
3162       PauseInternal(PlayPromiseError::kPaused_EndOfPlayback);
3163     }
3164   }
3165
3166   if (!seeking_)
3167     ScheduleTimeupdateEvent(true);
3168
3169   // Playback progress is chosen here for simplicity as a proxy for a good
3170   // periodic time to also update the attached MediaSource, if any, with our
3171   // currentTime so that it can continue to have a "recent media time".
3172   ReportCurrentTimeToMediaSource();
3173 }
3174
3175 void HTMLMediaElement::ScheduleTimeupdateEvent(bool periodic_event) {
3176   if (web_media_player_)
3177     web_media_player_->OnTimeUpdate();
3178
3179   // Per spec, consult current playback position to check for changing time.
3180   double media_time = CurrentPlaybackPosition();
3181   bool media_time_has_progressed =
3182       std::isnan(last_time_update_event_media_time_)
3183           ? media_time != 0
3184           : media_time != last_time_update_event_media_time_;
3185
3186   if (periodic_event && !media_time_has_progressed)
3187     return;
3188
3189   ScheduleEvent(event_type_names::kTimeupdate);
3190
3191   last_time_update_event_media_time_ = media_time;
3192
3193   // Restart the timer to ensure periodic event fires 250ms from _this_ event.
3194   if (!periodic_event && playback_progress_timer_.IsActive()) {
3195     playback_progress_timer_.Stop();
3196     playback_progress_timer_.StartRepeating(kMaxTimeupdateEventFrequency);
3197   }
3198 }
3199
3200 void HTMLMediaElement::TogglePlayState() {
3201   if (paused())
3202     Play();
3203   else
3204     pause();
3205 }
3206
3207 AudioTrackList& HTMLMediaElement::audioTracks() {
3208   return *audio_tracks_;
3209 }
3210
3211 void HTMLMediaElement::AudioTrackChanged(AudioTrack* track) {
3212   DVLOG(3) << "audioTrackChanged(" << *this
3213            << ") trackId= " << String(track->id())
3214            << " enabled=" << BoolString(track->enabled());
3215
3216   audioTracks().ScheduleChangeEvent();
3217
3218   if (media_source_attachment_)
3219     media_source_attachment_->OnTrackChanged(media_source_tracer_, track);
3220
3221   if (!audio_tracks_timer_.IsActive())
3222     audio_tracks_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
3223 }
3224
3225 void HTMLMediaElement::AudioTracksTimerFired(TimerBase*) {
3226   Vector<WebMediaPlayer::TrackId> enabled_track_ids;
3227   for (unsigned i = 0; i < audioTracks().length(); ++i) {
3228     AudioTrack* track = audioTracks().AnonymousIndexedGetter(i);
3229     if (track->enabled())
3230       enabled_track_ids.push_back(track->id());
3231   }
3232
3233   web_media_player_->EnabledAudioTracksChanged(enabled_track_ids);
3234 }
3235
3236 WebMediaPlayer::TrackId HTMLMediaElement::AddAudioTrack(
3237     const WebString& id,
3238     WebMediaPlayerClient::AudioTrackKind kind,
3239     const WebString& label,
3240     const WebString& language,
3241     bool enabled) {
3242   AtomicString kind_string = AudioKindToString(kind);
3243   DVLOG(3) << "addAudioTrack(" << *this << ", '" << String(id) << "', ' "
3244            << kind_string << "', '" << String(label) << "', '"
3245            << String(language) << "', " << BoolString(enabled) << ")";
3246
3247   auto* audio_track = MakeGarbageCollected<AudioTrack>(id, kind_string, label,
3248                                                        language, enabled);
3249   audioTracks().Add(audio_track);
3250
3251   return audio_track->id();
3252 }
3253
3254 void HTMLMediaElement::RemoveAudioTrack(WebMediaPlayer::TrackId track_id) {
3255   DVLOG(3) << "removeAudioTrack(" << *this << ")";
3256
3257   audioTracks().Remove(track_id);
3258 }
3259
3260 VideoTrackList& HTMLMediaElement::videoTracks() {
3261   return *video_tracks_;
3262 }
3263
3264 void HTMLMediaElement::SelectedVideoTrackChanged(VideoTrack* track) {
3265   DVLOG(3) << "selectedVideoTrackChanged(" << *this << ") selectedTrackId="
3266            << (track->selected() ? String(track->id()) : "none");
3267
3268   if (track->selected())
3269     videoTracks().TrackSelected(track->id());
3270
3271   videoTracks().ScheduleChangeEvent();
3272
3273   if (media_source_attachment_)
3274     media_source_attachment_->OnTrackChanged(media_source_tracer_, track);
3275
3276   WebMediaPlayer::TrackId id = track->id();
3277   web_media_player_->SelectedVideoTrackChanged(track->selected() ? &id
3278                                                                  : nullptr);
3279 }
3280
3281 WebMediaPlayer::TrackId HTMLMediaElement::AddVideoTrack(
3282     const WebString& id,
3283     WebMediaPlayerClient::VideoTrackKind kind,
3284     const WebString& label,
3285     const WebString& language,
3286     bool selected) {
3287   AtomicString kind_string = VideoKindToString(kind);
3288   DVLOG(3) << "addVideoTrack(" << *this << ", '" << String(id) << "', '"
3289            << kind_string << "', '" << String(label) << "', '"
3290            << String(language) << "', " << BoolString(selected) << ")";
3291
3292   // If another track was selected (potentially by the user), leave it selected.
3293   if (selected && videoTracks().selectedIndex() != -1)
3294     selected = false;
3295
3296   auto* video_track = MakeGarbageCollected<VideoTrack>(id, kind_string, label,
3297                                                        language, selected);
3298   videoTracks().Add(video_track);
3299
3300   return video_track->id();
3301 }
3302
3303 void HTMLMediaElement::RemoveVideoTrack(WebMediaPlayer::TrackId track_id) {
3304   DVLOG(3) << "removeVideoTrack(" << *this << ")";
3305
3306   videoTracks().Remove(track_id);
3307 }
3308
3309 void HTMLMediaElement::ForgetResourceSpecificTracks() {
3310   audio_tracks_->RemoveAll();
3311   video_tracks_->RemoveAll();
3312
3313   audio_tracks_timer_.Stop();
3314 }
3315
3316 TextTrack* HTMLMediaElement::addTextTrack(const AtomicString& kind,
3317                                           const AtomicString& label,
3318                                           const AtomicString& language,
3319                                           ExceptionState& exception_state) {
3320   // https://html.spec.whatwg.org/C/#dom-media-addtexttrack
3321
3322   // The addTextTrack(kind, label, language) method of media elements, when
3323   // invoked, must run the following steps:
3324
3325   // 1. Create a new TextTrack object.
3326   // 2. Create a new text track corresponding to the new object, and set its
3327   //    text track kind to kind, its text track label to label, its text
3328   //    track language to language, ..., and its text track list of cues to
3329   //    an empty list.
3330   auto* text_track =
3331       MakeGarbageCollected<TextTrack>(kind, label, language, *this);
3332   //    ..., its text track readiness state to the text track loaded state, ...
3333   text_track->SetReadinessState(TextTrack::kLoaded);
3334
3335   // 3. Add the new text track to the media element's list of text tracks.
3336   // 4. Queue a task to fire a trusted event with the name addtrack, that
3337   //    does not bubble and is not cancelable, and that uses the TrackEvent
3338   //    interface, with the track attribute initialised to the new text
3339   //    track's TextTrack object, at the media element's textTracks
3340   //    attribute's TextTrackList object.
3341   textTracks()->Append(text_track);
3342
3343   // Note: Due to side effects when changing track parameters, we have to
3344   // first append the track to the text track list.
3345   // FIXME: Since setMode() will cause a 'change' event to be queued on the
3346   // same task source as the 'addtrack' event (see above), the order is
3347   // wrong. (The 'change' event shouldn't be fired at all in this case...)
3348
3349   // ..., its text track mode to the text track hidden mode, ...
3350   text_track->SetModeEnum(TextTrackMode::kHidden);
3351
3352   // 5. Return the new TextTrack object.
3353   return text_track;
3354 }
3355
3356 TextTrackList* HTMLMediaElement::textTracks() {
3357   if (!text_tracks_) {
3358     UseCounter::Count(GetDocument(), WebFeature::kMediaElementTextTrackList);
3359     text_tracks_ = MakeGarbageCollected<TextTrackList>(this);
3360   }
3361
3362   return text_tracks_.Get();
3363 }
3364
3365 void HTMLMediaElement::DidAddTrackElement(HTMLTrackElement* track_element) {
3366   // 4.8.12.11.3 Sourcing out-of-band text tracks
3367   // When a track element's parent element changes and the new parent is a media
3368   // element, then the user agent must add the track element's corresponding
3369   // text track to the media element's list of text tracks ... [continues in
3370   // TextTrackList::append]
3371   TextTrack* text_track = track_element->track();
3372   if (!text_track)
3373     return;
3374
3375   textTracks()->Append(text_track);
3376
3377   // Do not schedule the track loading until parsing finishes so we don't start
3378   // before all tracks in the markup have been added.
3379   if (IsFinishedParsingChildren())
3380     ScheduleTextTrackResourceLoad();
3381 }
3382
3383 void HTMLMediaElement::DidRemoveTrackElement(HTMLTrackElement* track_element) {
3384   KURL url = track_element->GetNonEmptyURLAttribute(html_names::kSrcAttr);
3385   DVLOG(3) << "didRemoveTrackElement(" << *this << ") - 'src' is "
3386            << UrlForLoggingMedia(url);
3387
3388   TextTrack* text_track = track_element->track();
3389   if (!text_track)
3390     return;
3391
3392   text_track->SetHasBeenConfigured(false);
3393
3394   if (!text_tracks_)
3395     return;
3396
3397   // 4.8.12.11.3 Sourcing out-of-band text tracks
3398   // When a track element's parent element changes and the old parent was a
3399   // media element, then the user agent must remove the track element's
3400   // corresponding text track from the media element's list of text tracks.
3401   text_tracks_->Remove(text_track);
3402
3403   wtf_size_t index =
3404       text_tracks_when_resource_selection_began_.Find(text_track);
3405   if (index != kNotFound)
3406     text_tracks_when_resource_selection_began_.EraseAt(index);
3407 }
3408
3409 void HTMLMediaElement::HonorUserPreferencesForAutomaticTextTrackSelection() {
3410   if (!text_tracks_ || !text_tracks_->length())
3411     return;
3412
3413   if (!should_perform_automatic_track_selection_)
3414     return;
3415
3416   AutomaticTrackSelection::Configuration configuration;
3417   if (processing_preference_change_)
3418     configuration.disable_currently_enabled_tracks = true;
3419   if (text_tracks_visible_)
3420     configuration.force_enable_subtitle_or_caption_track = true;
3421
3422   Settings* settings = GetDocument().GetSettings();
3423   if (settings) {
3424     configuration.text_track_kind_user_preference =
3425         settings->GetTextTrackKindUserPreference();
3426   }
3427
3428   AutomaticTrackSelection track_selection(configuration);
3429   track_selection.Perform(*text_tracks_);
3430 }
3431
3432 bool HTMLMediaElement::HavePotentialSourceChild() {
3433   // Stash the current <source> node and next nodes so we can restore them after
3434   // checking to see there is another potential.
3435   HTMLSourceElement* current_source_node = current_source_node_;
3436   Node* next_node = next_child_node_to_consider_;
3437
3438   KURL next_url = SelectNextSourceChild(nullptr, kDoNothing);
3439
3440   current_source_node_ = current_source_node;
3441   next_child_node_to_consider_ = next_node;
3442
3443   return next_url.IsValid();
3444 }
3445
3446 KURL HTMLMediaElement::SelectNextSourceChild(
3447     String* content_type,
3448     InvalidURLAction action_if_invalid) {
3449   // Don't log if this was just called to find out if there are any valid
3450   // <source> elements.
3451   bool should_log = action_if_invalid != kDoNothing;
3452   if (should_log)
3453     DVLOG(3) << "selectNextSourceChild(" << *this << ")";
3454
3455   if (!next_child_node_to_consider_) {
3456     if (should_log) {
3457       DVLOG(3) << "selectNextSourceChild(" << *this << ") -> 0x0000, \"\"";
3458     }
3459     return KURL();
3460   }
3461
3462   KURL media_url;
3463   Node* node;
3464   HTMLSourceElement* source = nullptr;
3465   String type;
3466   bool looking_for_start_node = next_child_node_to_consider_ != nullptr;
3467   bool can_use_source_element = false;
3468
3469   NodeVector potential_source_nodes;
3470   GetChildNodes(*this, potential_source_nodes);
3471
3472   for (unsigned i = 0;
3473        !can_use_source_element && i < potential_source_nodes.size(); ++i) {
3474     node = potential_source_nodes[i].Get();
3475     if (looking_for_start_node && next_child_node_to_consider_ != node)
3476       continue;
3477     looking_for_start_node = false;
3478
3479     source = DynamicTo<HTMLSourceElement>(node);
3480     if (!source || node->parentNode() != this) {
3481       continue;
3482     }
3483
3484     // 2. If candidate does not have a src attribute, or if its src
3485     // attribute's value is the empty string ... jump down to the failed
3486     // step below
3487     const AtomicString& src_value =
3488         source->FastGetAttribute(html_names::kSrcAttr);
3489     if (should_log) {
3490       DVLOG(3) << "selectNextSourceChild(" << *this << ") - 'src' is "
3491                << UrlForLoggingMedia(media_url);
3492     }
3493     if (src_value.empty()) {
3494       goto checkAgain;
3495     }
3496
3497     // 3. If candidate has a media attribute whose value does not match the
3498     // environment, then end the synchronous section, and jump down to the
3499     // failed with elements step below.
3500     if (!source->MediaQueryMatches() &&
3501         base::FeatureList::IsEnabled(kVideoSourceMediaQuerySupport)) {
3502       goto checkAgain;
3503     }
3504
3505     // 4. Let urlRecord be the result of encoding-parsing a URL given
3506     // candidate's src attribute's value, relative to candidate's node document
3507     // when the src attribute was last changed.
3508     media_url = source->GetDocument().CompleteURL(src_value);
3509
3510     // 5. If urlRecord is failure, then end the synchronous section, and jump
3511     // down to the failed with elements step below.
3512     if (!IsSafeToLoadURL(media_url, action_if_invalid)) {
3513       goto checkAgain;
3514     }
3515
3516     // 6. If candidate has a type attribute whose value, when parsed as a
3517     // MIME type ...
3518     type = source->type();
3519     if (type.empty() && media_url.ProtocolIsData())
3520       type = MimeTypeFromDataURL(media_url);
3521     if (!type.empty()) {
3522       if (should_log) {
3523         DVLOG(3) << "selectNextSourceChild(" << *this << ") - 'type' is '"
3524                  << type << "'";
3525       }
3526       if (!GetSupportsType(ContentType(type)))
3527         goto checkAgain;
3528     }
3529
3530     // Making it this far means the <source> looks reasonable.
3531     can_use_source_element = true;
3532
3533   checkAgain:
3534     if (!can_use_source_element && action_if_invalid == kComplain && source)
3535       source->ScheduleErrorEvent();
3536   }
3537
3538   if (can_use_source_element) {
3539     if (content_type)
3540       *content_type = type;
3541     current_source_node_ = source;
3542     next_child_node_to_consider_ = source->nextSibling();
3543   } else {
3544     current_source_node_ = nullptr;
3545     next_child_node_to_consider_ = nullptr;
3546   }
3547
3548   if (should_log) {
3549     DVLOG(3) << "selectNextSourceChild(" << *this << ") -> "
3550              << current_source_node_.Get() << ", "
3551              << (can_use_source_element ? UrlForLoggingMedia(media_url) : "");
3552   }
3553
3554   return can_use_source_element ? media_url : KURL();
3555 }
3556
3557 void HTMLMediaElement::SourceWasAdded(HTMLSourceElement* source) {
3558   DVLOG(3) << "sourceWasAdded(" << *this << ", " << source << ")";
3559
3560   KURL url = source->GetNonEmptyURLAttribute(html_names::kSrcAttr);
3561   DVLOG(3) << "sourceWasAdded(" << *this << ") - 'src' is "
3562            << UrlForLoggingMedia(url);
3563
3564   // We should only consider a <source> element when there is not src attribute
3565   // at all.
3566   if (FastHasAttribute(html_names::kSrcAttr))
3567     return;
3568
3569   // 4.8.8 - If a source element is inserted as a child of a media element that
3570   // has no src attribute and whose networkState has the value NETWORK_EMPTY,
3571   // the user agent must invoke the media element's resource selection
3572   // algorithm.
3573   if (getNetworkState() == HTMLMediaElement::kNetworkEmpty) {
3574     InvokeResourceSelectionAlgorithm();
3575     // Ignore current |next_child_node_to_consider_| and consider |source|.
3576     next_child_node_to_consider_ = source;
3577     return;
3578   }
3579
3580   if (current_source_node_ && source == current_source_node_->nextSibling()) {
3581     DVLOG(3) << "sourceWasAdded(" << *this
3582              << ") - <source> inserted immediately after current source";
3583     // Ignore current |next_child_node_to_consider_| and consider |source|.
3584     next_child_node_to_consider_ = source;
3585     return;
3586   }
3587
3588   // Consider current |next_child_node_to_consider_| as it is already in the
3589   // middle of processing.
3590   if (next_child_node_to_consider_)
3591     return;
3592
3593   if (load_state_ != kWaitingForSource)
3594     return;
3595
3596   // 4.8.9.5, resource selection algorithm, source elements section:
3597   // 21. Wait until the node after pointer is a node other than the end of the
3598   // list. (This step might wait forever.)
3599   // 22. Asynchronously await a stable state...
3600   // 23. Set the element's delaying-the-load-event flag back to true (this
3601   // delays the load event again, in case it hasn't been fired yet).
3602   SetShouldDelayLoadEvent(true);
3603
3604   // 24. Set the networkState back to NETWORK_LOADING.
3605   // Changing the network state might trigger media controls to add new nodes
3606   // to the DOM which is forbidden while source is being inserted into this
3607   // node. This is a problem as ContainerNode::NotifyNodeInsertedInternal,
3608   // which is always indirectly triggering this function, prohibits event
3609   // dispatch and adding new nodes will run
3610   // blink::DispatchChildInsertionEvents.
3611   //
3612   // We still need to update the media controls. This will be done after
3613   // load_timer_ fires a new event - which is setup in ScheduleNextSourceChild
3614   // below so skipping that step here should be OK.
3615   SetNetworkState(kNetworkLoading, false /* update_media_controls */);
3616
3617   // 25. Jump back to the find next candidate step above.
3618   next_child_node_to_consider_ = source;
3619   ScheduleNextSourceChild();
3620 }
3621
3622 void HTMLMediaElement::SourceWasRemoved(HTMLSourceElement* source) {
3623   DVLOG(3) << "sourceWasRemoved(" << *this << ", " << source << ")";
3624
3625   KURL url = source->GetNonEmptyURLAttribute(html_names::kSrcAttr);
3626   DVLOG(3) << "sourceWasRemoved(" << *this << ") - 'src' is "
3627            << UrlForLoggingMedia(url);
3628
3629   if (source != current_source_node_ && source != next_child_node_to_consider_)
3630     return;
3631
3632   if (source == next_child_node_to_consider_) {
3633     if (current_source_node_)
3634       next_child_node_to_consider_ = current_source_node_->nextSibling();
3635     DVLOG(3) << "sourceWasRemoved(" << *this
3636              << ") - next_child_node_to_consider_ set to "
3637              << next_child_node_to_consider_.Get();
3638   } else if (source == current_source_node_) {
3639     // Clear the current source node pointer, but don't change the movie as the
3640     // spec says:
3641     // 4.8.8 - Dynamically modifying a source element and its attribute when the
3642     // element is already inserted in a video or audio element will have no
3643     // effect.
3644     current_source_node_ = nullptr;
3645     DVLOG(3) << "SourceWasRemoved(" << *this
3646              << ") - current_source_node_ set to 0";
3647   }
3648 }
3649
3650 void HTMLMediaElement::TimeChanged() {
3651   DVLOG(3) << "timeChanged(" << *this << ")";
3652
3653   // 4.8.12.9 steps 12-14. Needed if no ReadyState change is associated with the
3654   // seek.
3655   if (seeking_ && ready_state_ >= kHaveCurrentData &&
3656       !web_media_player_->Seeking()) {
3657     FinishSeek();
3658   }
3659
3660   // When the current playback position reaches the end of the media resource
3661   // when the direction of playback is forwards, then the user agent must follow
3662   // these steps:
3663 #if defined(TIZEN_MULTIMEDIA)
3664   // mmplayer return duration = 0 for some normal stream. Media will set
3665   // duration = max for this case. And now = max also, this case is also
3666   // regarded as playback complete.
3667   const double now = CurrentPlaybackPosition();
3668   const double dur = duration();
3669   bool is_duration_exception_case =
3670       (now == std::numeric_limits<double>::infinity()) &&
3671       (dur == std::numeric_limits<double>::infinity());
3672
3673   if (live_playback_complete_ || is_duration_exception_case ||
3674       (EndedPlayback(LoopCondition::kIgnored))) {
3675 #else
3676   if (EndedPlayback(LoopCondition::kIgnored)) {
3677 #endif
3678     // If the media element has a loop attribute specified
3679     if (Loop() && EarliestPossiblePosition() != CurrentPlaybackPosition()) {
3680       //  then seek to the earliest possible position of the media resource and
3681       //  abort these steps.
3682       Seek(EarliestPossiblePosition());
3683     } else {
3684       // Queue a task to fire a simple event named timeupdate at the media
3685       // element.
3686       ScheduleTimeupdateEvent(false);
3687
3688       // If the media element has still ended playback, and the direction of
3689       // playback is still forwards, and paused is false,
3690       if (!paused_) {
3691         // Trigger an update to `official_playback_position_` (if necessary)
3692         // BEFORE setting `paused_ = false`, to ensure a final sync with
3693         // `WebMediaPlayer()->CurrentPlaybackPosition()`.
3694         OfficialPlaybackPosition();
3695
3696         // changes paused to true and fires a simple event named pause at the
3697         // media element.
3698         paused_ = true;
3699         ScheduleEvent(event_type_names::kPause);
3700         ScheduleRejectPlayPromises(PlayPromiseError::kPaused_EndOfPlayback);
3701       }
3702       // Queue a task to fire a simple event named ended at the media element.
3703       ScheduleEvent(event_type_names::kEnded);
3704     }
3705   }
3706   UpdatePlayState();
3707
3708 #if defined(TIZEN_MULTIMEDIA)
3709   live_playback_complete_ = false;
3710 #endif
3711 }
3712
3713 void HTMLMediaElement::DurationChanged() {
3714   DVLOG(3) << "durationChanged(" << *this << ")";
3715
3716   // durationChanged() is triggered by media player.
3717   CHECK(web_media_player_);
3718   double new_duration = web_media_player_->Duration();
3719
3720   // If the duration is changed such that the *current playback position* ends
3721   // up being greater than the time of the end of the media resource, then the
3722   // user agent must also seek to the time of the end of the media resource.
3723   DurationChanged(new_duration, CurrentPlaybackPosition() > new_duration);
3724 }
3725
3726 void HTMLMediaElement::DurationChanged(double duration, bool request_seek) {
3727   DVLOG(3) << "durationChanged(" << *this << ", " << duration << ", "
3728            << BoolString(request_seek) << ")";
3729
3730   // Abort if duration unchanged.
3731   if (duration_ == duration)
3732     return;
3733
3734   DVLOG(3) << "durationChanged(" << *this << ") : " << duration_ << " -> "
3735            << duration;
3736   duration_ = duration;
3737   ScheduleEvent(event_type_names::kDurationchange);
3738
3739   if (web_media_player_)
3740     web_media_player_->OnTimeUpdate();
3741
3742   UpdateLayoutObject();
3743
3744   if (request_seek)
3745     Seek(duration);
3746 }
3747
3748 void HTMLMediaElement::RemotePlaybackCompatibilityChanged(const WebURL& url,
3749                                                           bool is_compatible) {
3750   if (RemotePlaybackClient())
3751     RemotePlaybackClient()->SourceChanged(url, is_compatible);
3752 }
3753
3754 bool HTMLMediaElement::HasSelectedVideoTrack() {
3755   return video_tracks_ && video_tracks_->selectedIndex() != -1;
3756 }
3757
3758 WebMediaPlayer::TrackId HTMLMediaElement::GetSelectedVideoTrackId() {
3759   DCHECK(HasSelectedVideoTrack());
3760
3761   int selected_track_index = video_tracks_->selectedIndex();
3762   VideoTrack* track =
3763       video_tracks_->AnonymousIndexedGetter(selected_track_index);
3764   return track->id();
3765 }
3766
3767 bool HTMLMediaElement::WasAlwaysMuted() {
3768   return was_always_muted_;
3769 }
3770
3771 // MediaPlayerPresentation methods
3772 void HTMLMediaElement::Repaint() {
3773   if (cc_layer_)
3774     cc_layer_->SetNeedsDisplay();
3775
3776   UpdateLayoutObject();
3777   if (GetLayoutObject())
3778     GetLayoutObject()->SetShouldDoFullPaintInvalidation();
3779 }
3780
3781 void HTMLMediaElement::SizeChanged() {
3782   DVLOG(3) << "sizeChanged(" << *this << ")";
3783
3784   DCHECK(HasVideo());  // "resize" makes no sense in absence of video.
3785   if (ready_state_ > kHaveNothing && IsHTMLVideoElement())
3786     ScheduleEvent(event_type_names::kResize);
3787
3788   UpdateLayoutObject();
3789 }
3790
3791 WebTimeRanges HTMLMediaElement::BufferedInternal() const {
3792   if (media_source_attachment_) {
3793     return media_source_attachment_->BufferedInternal(
3794         media_source_tracer_.Get());
3795   }
3796
3797   if (!web_media_player_)
3798     return {};
3799
3800   return web_media_player_->Buffered();
3801 }
3802
3803 TimeRanges* HTMLMediaElement::buffered() const {
3804   return MakeGarbageCollected<TimeRanges>(BufferedInternal());
3805 }
3806
3807 TimeRanges* HTMLMediaElement::played() {
3808   if (playing_) {
3809     double time = currentTime();
3810     if (time > last_seek_time_)
3811       AddPlayedRange(last_seek_time_, time);
3812   }
3813
3814   if (!played_time_ranges_)
3815     played_time_ranges_ = MakeGarbageCollected<TimeRanges>();
3816
3817   return played_time_ranges_->Copy();
3818 }
3819
3820 WebTimeRanges HTMLMediaElement::SeekableInternal() const {
3821   if (!web_media_player_)
3822     return {};
3823
3824   if (media_source_attachment_) {
3825     return media_source_attachment_->SeekableInternal(
3826         media_source_tracer_.Get());
3827   }
3828
3829   return web_media_player_->Seekable();
3830 }
3831
3832 TimeRanges* HTMLMediaElement::seekable() const {
3833   return MakeGarbageCollected<TimeRanges>(SeekableInternal());
3834 }
3835
3836 bool HTMLMediaElement::PotentiallyPlaying() const {
3837   // Once we've reached the metadata state the WebMediaPlayer is ready to accept
3838   // play state changes.
3839   return ready_state_ >= kHaveMetadata && CouldPlayIfEnoughData();
3840 }
3841
3842 bool HTMLMediaElement::CouldPlayIfEnoughData() const {
3843   return !paused() && !EndedPlayback() && !StoppedDueToErrors();
3844 }
3845
3846 bool HTMLMediaElement::EndedPlayback(LoopCondition loop_condition) const {
3847   // If we have infinite duration, we'll never have played for long enough to
3848   // have ended playback.
3849   const double dur = duration();
3850   if (std::isnan(dur) || dur == std::numeric_limits<double>::infinity())
3851     return false;
3852
3853   // 4.8.12.8 Playing the media resource
3854
3855   // A media element is said to have ended playback when the element's
3856   // readyState attribute is HAVE_METADATA or greater,
3857   if (ready_state_ < kHaveMetadata)
3858     return false;
3859
3860   DCHECK_EQ(GetDirectionOfPlayback(), kForward);
3861   if (web_media_player_) {
3862     return web_media_player_->IsEnded() && dur > 0 &&
3863            (loop_condition == LoopCondition::kIgnored || !Loop() ||
3864             dur <= std::numeric_limits<double>::epsilon());
3865   }
3866
3867   return false;
3868 }
3869
3870 bool HTMLMediaElement::StoppedDueToErrors() const {
3871   if (ready_state_ >= kHaveMetadata && error_) {
3872     WebTimeRanges seekable_ranges = SeekableInternal();
3873     if (!seekable_ranges.Contain(currentTime()))
3874       return true;
3875   }
3876
3877   return false;
3878 }
3879
3880 void HTMLMediaElement::UpdatePlayState(bool pause_speech /* = true */) {
3881   bool is_playing = web_media_player_ && !web_media_player_->Paused();
3882   bool should_be_playing = PotentiallyPlaying();
3883
3884   DVLOG(3) << "updatePlayState(" << *this
3885            << ") - shouldBePlaying = " << BoolString(should_be_playing)
3886            << ", isPlaying = " << BoolString(is_playing);
3887
3888   if (should_be_playing && !muted_)
3889     was_always_muted_ = false;
3890
3891   if (should_be_playing) {
3892     if (!is_playing) {
3893       // Set rate, muted before calling play in case they were set before the
3894       // media engine was setup.  The media engine should just stash the rate
3895       // and muted values since it isn't already playing.
3896       web_media_player_->SetRate(playbackRate());
3897       web_media_player_->SetVolume(EffectiveMediaVolume());
3898       web_media_player_->Play();
3899       if (::features::IsTextBasedAudioDescriptionEnabled())
3900         SpeechSynthesis()->Resume();
3901
3902       // These steps should not be necessary, but if `play()` is called before
3903       // a source change, we may get into a state where `paused_ == false` and
3904       // `show_poster_flag_ == true`. My (cassew@google.com) interpretation of
3905       // the spec is that we should not be playing in this scenario.
3906       // https://crbug.com/633591
3907       SetShowPosterFlag(false);
3908       GetCueTimeline().InvokeTimeMarchesOn();
3909     }
3910
3911     StartPlaybackProgressTimer();
3912     playing_ = true;
3913   } else {  // Should not be playing right now
3914     if (is_playing) {
3915       web_media_player_->Pause();
3916
3917       if (pause_speech && ::features::IsTextBasedAudioDescriptionEnabled())
3918         SpeechSynthesis()->Pause();
3919     }
3920
3921     playback_progress_timer_.Stop();
3922     playing_ = false;
3923     double time = currentTime();
3924     if (time > last_seek_time_)
3925       AddPlayedRange(last_seek_time_, time);
3926
3927     GetCueTimeline().OnPause();
3928   }
3929
3930   UpdateLayoutObject();
3931
3932   if (web_media_player_)
3933     web_media_player_->OnTimeUpdate();
3934
3935   ReportCurrentTimeToMediaSource();
3936   PseudoStateChanged(CSSSelector::kPseudoPaused);
3937   PseudoStateChanged(CSSSelector::kPseudoPlaying);
3938 }
3939
3940 void HTMLMediaElement::StopPeriodicTimers() {
3941   progress_event_timer_.Stop();
3942   playback_progress_timer_.Stop();
3943   if (lazy_load_intersection_observer_) {
3944     lazy_load_intersection_observer_->disconnect();
3945     lazy_load_intersection_observer_ = nullptr;
3946   }
3947 }
3948
3949 void HTMLMediaElement::
3950     ClearMediaPlayerAndAudioSourceProviderClientWithoutLocking() {
3951   GetAudioSourceProvider().SetClient(nullptr);
3952   if (web_media_player_) {
3953     audio_source_provider_.Wrap(nullptr);
3954     web_media_player_.reset();
3955     // Do not clear `opener_document_` here; new players might still use it.
3956
3957     // The lifetime of the mojo endpoints are tied to the WebMediaPlayer's, so
3958     // we need to reset those as well.
3959     media_player_receiver_set_->Value().Clear();
3960     media_player_observer_remote_set_->Value().Clear();
3961   }
3962
3963   OnWebMediaPlayerCleared();
3964 }
3965
3966 void HTMLMediaElement::ClearMediaPlayer() {
3967   ForgetResourceSpecificTracks();
3968
3969   CloseMediaSource();
3970
3971   CancelDeferredLoad();
3972
3973   {
3974     AudioSourceProviderClientLockScope scope(*this);
3975     ClearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
3976   }
3977
3978   StopPeriodicTimers();
3979   load_timer_.Stop();
3980
3981   pending_action_flags_ = 0;
3982   load_state_ = kWaitingForSource;
3983
3984   if (GetLayoutObject())
3985     GetLayoutObject()->SetShouldDoFullPaintInvalidation();
3986 }
3987
3988 void HTMLMediaElement::ContextLifecycleStateChanged(
3989     mojom::FrameLifecycleState state) {
3990   if (state == mojom::FrameLifecycleState::kFrozenAutoResumeMedia && playing_) {
3991     paused_by_context_paused_ = true;
3992     pause();
3993     if (web_media_player_) {
3994       web_media_player_->OnFrozen();
3995     }
3996   } else if (state == mojom::FrameLifecycleState::kFrozen && playing_) {
3997     pause();
3998     if (web_media_player_) {
3999       web_media_player_->OnFrozen();
4000     }
4001   }
4002 #if defined(TIZEN_MULTIMEDIA)
4003   else if (state == mojom::FrameLifecycleState::kPaused) {
4004     // Suspend if a browser tab is switched.
4005     if (GetWebMediaPlayer())
4006       GetWebMediaPlayer()->Suspend();
4007
4008     if (playing_) {
4009       paused_by_context_paused_ = true;
4010       pause();
4011     }
4012   } else if (state == mojom::FrameLifecycleState::kRunning) {
4013     // Do not resume if suspended by player except the resource conflict case.
4014     if (GetWebMediaPlayer() && GetWebMediaPlayer()->SuspendedByPlayer())
4015       return;
4016
4017     if (GetWebMediaPlayer())
4018       GetWebMediaPlayer()->Resume();
4019
4020     if (paused_by_context_paused_) {
4021       paused_by_context_paused_ = false;
4022       Play();
4023     }
4024   }
4025 #else
4026   else if (state == mojom::FrameLifecycleState::kRunning &&
4027            paused_by_context_paused_) {
4028
4029     paused_by_context_paused_ = false;
4030     Play();
4031   }
4032 #endif
4033 }
4034
4035 void HTMLMediaElement::ContextDestroyed() {
4036   DVLOG(3) << "contextDestroyed(" << static_cast<void*>(this) << ")";
4037
4038   // Close the async event queue so that no events are enqueued.
4039   CancelPendingEventsAndCallbacks();
4040
4041   // Clear everything in the Media Element
4042   if (media_source_attachment_)
4043     media_source_attachment_->OnElementContextDestroyed();
4044   ClearMediaPlayer();
4045   ready_state_ = kHaveNothing;
4046   ready_state_maximum_ = kHaveNothing;
4047   SetNetworkState(kNetworkEmpty);
4048   SetShouldDelayLoadEvent(false);
4049   current_source_node_ = nullptr;
4050   official_playback_position_ = 0;
4051   official_playback_position_needs_update_ = true;
4052   playing_ = false;
4053   paused_ = true;
4054   seeking_ = false;
4055   GetCueTimeline().OnReadyStateReset();
4056
4057   UpdateLayoutObject();
4058
4059   StopPeriodicTimers();
4060   removed_from_document_timer_.Stop();
4061 }
4062
4063 #if BUILDFLAG(IS_TIZEN_TV)
4064 WebString HTMLMediaElement::GetContentMIMEType() {
4065   // If the MIME type is missing or is not meaningful, try to figure it out from
4066   // the URL.
4067   if (content_mime_type_.empty() ||
4068       content_mime_type_ == "application/octet-stream" ||
4069       content_mime_type_ == "text/plain") {
4070     if (current_src_.GetSourceIfVisible().ProtocolIsData())
4071       content_mime_type_ =
4072           MimeTypeFromDataURL(current_src_.GetSourceIfVisible().GetString());
4073     else {
4074       String last_path_component =
4075           current_src_.GetSourceIfVisible().LastPathComponent();
4076       size_t pos = last_path_component.ReverseFind('.');
4077       if (pos != kNotFound) {
4078         String extension = last_path_component.Substring(pos + 1);
4079         String media_type =
4080             MIMETypeRegistry::GetMIMETypeForExtension(extension);
4081         if (!media_type.empty())
4082           content_mime_type_ = media_type;
4083       }
4084     }
4085   }
4086   return WebString(content_mime_type_);
4087 }
4088
4089 void HTMLMediaElement::RequestReload(const KURL& new_url) {
4090   DCHECK(GetWebMediaPlayer());
4091   DCHECK(new_url.IsValid());
4092   DCHECK(IsSafeToLoadURL(new_url, kComplain));
4093   ResetMediaPlayerAndMediaSource();
4094   StartPlayerLoad();
4095 }
4096
4097 void HTMLMediaElement::SetTranslatedURL(const String& url) {
4098   LOG(INFO) << "translated url:" << url;
4099   is_translated_url_ = true;
4100   content_mime_type_ = "";
4101   if (src_object_media_source_handle_) {
4102     DCHECK(!KURL(url).IsEmpty());
4103     current_src_.SetSource(KURL(url),
4104                            SourceMetadata::SourceVisibility::kInvisibleToApp);
4105   } else {
4106     current_src_.SetSource(KURL(url),
4107                            SourceMetadata::SourceVisibility::kVisibleToApp);
4108   }
4109   RequestReload(current_src_.GetSource());
4110 }
4111
4112 void HTMLMediaElement::SetParentalRatingResult(bool is_pass) {
4113   LOG(INFO) << "setParentalRatingResult:" << BoolString(is_pass);
4114   if (!GetWebMediaPlayer()) {
4115     LOG(ERROR) << "setParentalRatingResult: mediaplayer not created";
4116     return;
4117   }
4118   GetWebMediaPlayer()->SetParentalRatingResult(is_pass);
4119 }
4120 #endif
4121
4122 bool HTMLMediaElement::HasPendingActivity() const {
4123   const auto result = HasPendingActivityInternal();
4124   // TODO(dalecurtis): Replace c-style casts in followup patch.
4125   DVLOG(3) << "HasPendingActivity(" << *this << ") = " << result;
4126   return result;
4127 }
4128
4129 bool HTMLMediaElement::HasPendingActivityInternal() const {
4130   // The delaying-the-load-event flag is set by resource selection algorithm
4131   // when looking for a resource to load, before networkState has reached to
4132   // kNetworkLoading.
4133   if (should_delay_load_event_)
4134     return true;
4135
4136   // When networkState is kNetworkLoading, progress and stalled events may be
4137   // fired.
4138   //
4139   // When connected to a MediaSource, ignore |network_state_|. The rest
4140   // of this method's logic and the HasPendingActivity() of the various
4141   // MediaSource API objects more precisely indicate whether or not any pending
4142   // activity is expected on the group of connected HTMLMediaElement +
4143   // MediaSource API objects. This lets the group of objects be garbage
4144   // collected if there is no pending activity nor reachability from a GC root,
4145   // even while in kNetworkLoading.
4146   //
4147   // We use the WebMediaPlayer's network state instead of |network_state_| since
4148   // it's value is unreliable prior to ready state kHaveMetadata.
4149   if (!media_source_attachment_) {
4150     if (!web_media_player_) {
4151       if (network_state_ == kNetworkLoading)
4152         return true;
4153     } else if (web_media_player_->GetNetworkState() ==
4154                WebMediaPlayer::kNetworkStateLoading) {
4155       return true;
4156     }
4157   }
4158
4159   {
4160     // Disable potential updating of playback position, as that will
4161     // require v8 allocations; not allowed while GCing
4162     // (hasPendingActivity() is called during a v8 GC.)
4163     base::AutoReset<bool> scope(&official_playback_position_needs_update_,
4164                                 false);
4165
4166     // When playing or if playback may continue, timeupdate events may be fired.
4167     if (CouldPlayIfEnoughData())
4168       return true;
4169   }
4170
4171   // When the seek finishes timeupdate and seeked events will be fired.
4172   if (seeking_)
4173     return true;
4174
4175   // Wait for any pending events to be fired.
4176   if (async_event_queue_->HasPendingEvents())
4177     return true;
4178
4179   return false;
4180 }
4181
4182 bool HTMLMediaElement::IsFullscreen() const {
4183   return Fullscreen::IsFullscreenElement(*this);
4184 }
4185
4186 cc::Layer* HTMLMediaElement::CcLayer() const {
4187   return cc_layer_;
4188 }
4189
4190 bool HTMLMediaElement::HasClosedCaptions() const {
4191   if (!text_tracks_)
4192     return false;
4193
4194   for (unsigned i = 0; i < text_tracks_->length(); ++i) {
4195     if (text_tracks_->AnonymousIndexedGetter(i)->CanBeRendered())
4196       return true;
4197   }
4198
4199   return false;
4200 }
4201
4202 bool HTMLMediaElement::TextTracksVisible() const {
4203   return text_tracks_visible_;
4204 }
4205
4206 // static
4207 void HTMLMediaElement::AssertShadowRootChildren(ShadowRoot& shadow_root) {
4208 #if DCHECK_IS_ON()
4209   // There can be up to three children: an interstitial (media remoting or
4210   // picture in picture), text track container, and media controls. The media
4211   // controls has to be the last child if present, and has to be the next
4212   // sibling of the text track container if both present. When present, media
4213   // remoting interstitial has to be the first child.
4214   unsigned number_of_children = shadow_root.CountChildren();
4215   DCHECK_LE(number_of_children, 3u);
4216   Node* first_child = shadow_root.firstChild();
4217   Node* last_child = shadow_root.lastChild();
4218   if (number_of_children == 1) {
4219     DCHECK(first_child->IsTextTrackContainer() ||
4220            first_child->IsMediaControls() ||
4221            first_child->IsMediaRemotingInterstitial() ||
4222            first_child->IsPictureInPictureInterstitial());
4223   } else if (number_of_children == 2) {
4224     DCHECK(first_child->IsTextTrackContainer() ||
4225            first_child->IsMediaRemotingInterstitial() ||
4226            first_child->IsPictureInPictureInterstitial());
4227     DCHECK(last_child->IsTextTrackContainer() || last_child->IsMediaControls());
4228     if (first_child->IsTextTrackContainer())
4229       DCHECK(last_child->IsMediaControls());
4230   } else if (number_of_children == 3) {
4231     Node* second_child = first_child->nextSibling();
4232     DCHECK(first_child->IsMediaRemotingInterstitial() ||
4233            first_child->IsPictureInPictureInterstitial());
4234     DCHECK(second_child->IsTextTrackContainer());
4235     DCHECK(last_child->IsMediaControls());
4236   }
4237 #endif
4238 }
4239
4240 TextTrackContainer& HTMLMediaElement::EnsureTextTrackContainer() {
4241   UseCounter::Count(GetDocument(), WebFeature::kMediaElementTextTrackContainer);
4242
4243   ShadowRoot& shadow_root = EnsureUserAgentShadowRoot();
4244   AssertShadowRootChildren(shadow_root);
4245
4246   Node* first_child = shadow_root.firstChild();
4247   if (auto* first_child_text_track = DynamicTo<TextTrackContainer>(first_child))
4248     return *first_child_text_track;
4249   Node* to_be_inserted = first_child;
4250
4251   if (first_child && (first_child->IsMediaRemotingInterstitial() ||
4252                       first_child->IsPictureInPictureInterstitial())) {
4253     Node* second_child = first_child->nextSibling();
4254     if (auto* second_child_text_track =
4255             DynamicTo<TextTrackContainer>(second_child))
4256       return *second_child_text_track;
4257     to_be_inserted = second_child;
4258   }
4259
4260   auto* text_track_container = MakeGarbageCollected<TextTrackContainer>(*this);
4261
4262   // The text track container should be inserted before the media controls,
4263   // so that they are rendered behind them.
4264   shadow_root.InsertBefore(text_track_container, to_be_inserted);
4265
4266   AssertShadowRootChildren(shadow_root);
4267
4268   return *text_track_container;
4269 }
4270
4271 void HTMLMediaElement::UpdateTextTrackDisplay() {
4272   DVLOG(3) << "updateTextTrackDisplay(" << *this << ")";
4273
4274   EnsureTextTrackContainer().UpdateDisplay(
4275       *this, TextTrackContainer::kDidNotStartExposingControls);
4276 }
4277
4278 SpeechSynthesisBase* HTMLMediaElement::SpeechSynthesis() {
4279   if (!speech_synthesis_) {
4280     speech_synthesis_ =
4281         SpeechSynthesisBase::Create(*(GetDocument().domWindow()));
4282     speech_synthesis_->SetOnSpeakingCompletedCallback(WTF::BindRepeating(
4283         &HTMLMediaElement::OnSpeakingCompleted, WrapWeakPersistent(this)));
4284   }
4285   return speech_synthesis_.Get();
4286 }
4287
4288 void HTMLMediaElement::MediaControlsDidBecomeVisible() {
4289   DVLOG(3) << "mediaControlsDidBecomeVisible(" << *this << ")";
4290
4291   // When the user agent starts exposing a user interface for a video element,
4292   // the user agent should run the rules for updating the text track rendering
4293   // of each of the text tracks in the video element's list of text tracks ...
4294   if (IsHTMLVideoElement() && TextTracksVisible()) {
4295     EnsureTextTrackContainer().UpdateDisplay(
4296         *this, TextTrackContainer::kDidStartExposingControls);
4297   }
4298 }
4299
4300 void HTMLMediaElement::SetTextTrackKindUserPreferenceForAllMediaElements(
4301     Document* document) {
4302   auto it = DocumentToElementSetMap().find(document);
4303   if (it == DocumentToElementSetMap().end())
4304     return;
4305   DCHECK(it->value);
4306   WeakMediaElementSet& elements = *it->value;
4307   for (const auto& element : elements)
4308     element->AutomaticTrackSelectionForUpdatedUserPreference();
4309 }
4310
4311 void HTMLMediaElement::AutomaticTrackSelectionForUpdatedUserPreference() {
4312   if (!text_tracks_ || !text_tracks_->length())
4313     return;
4314
4315   MarkCaptionAndSubtitleTracksAsUnconfigured();
4316   processing_preference_change_ = true;
4317   text_tracks_visible_ = false;
4318   HonorUserPreferencesForAutomaticTextTrackSelection();
4319   processing_preference_change_ = false;
4320
4321   // If a track is set to 'showing' post performing automatic track selection,
4322   // set text tracks state to visible to update the CC button and display the
4323   // track.
4324   text_tracks_visible_ = text_tracks_->HasShowingTracks();
4325   UpdateTextTrackDisplay();
4326 }
4327
4328 void HTMLMediaElement::MarkCaptionAndSubtitleTracksAsUnconfigured() {
4329   if (!text_tracks_)
4330     return;
4331
4332   // Mark all tracks as not "configured" so that
4333   // honorUserPreferencesForAutomaticTextTrackSelection() will reconsider
4334   // which tracks to display in light of new user preferences (e.g. default
4335   // tracks should not be displayed if the user has turned off captions and
4336   // non-default tracks should be displayed based on language preferences if
4337   // the user has turned captions on).
4338   for (unsigned i = 0; i < text_tracks_->length(); ++i) {
4339     TextTrack* text_track = text_tracks_->AnonymousIndexedGetter(i);
4340     if (text_track->IsVisualKind())
4341       text_track->SetHasBeenConfigured(false);
4342   }
4343 }
4344
4345 uint64_t HTMLMediaElement::webkitAudioDecodedByteCount() const {
4346   if (!web_media_player_)
4347     return 0;
4348   return web_media_player_->AudioDecodedByteCount();
4349 }
4350
4351 uint64_t HTMLMediaElement::webkitVideoDecodedByteCount() const {
4352   if (!web_media_player_)
4353     return 0;
4354   return web_media_player_->VideoDecodedByteCount();
4355 }
4356
4357 bool HTMLMediaElement::IsURLAttribute(const Attribute& attribute) const {
4358   return attribute.GetName() == html_names::kSrcAttr ||
4359          HTMLElement::IsURLAttribute(attribute);
4360 }
4361
4362 void HTMLMediaElement::SetShouldDelayLoadEvent(bool should_delay) {
4363   if (should_delay_load_event_ == should_delay)
4364     return;
4365
4366   DVLOG(3) << "setShouldDelayLoadEvent(" << *this << ", "
4367            << BoolString(should_delay) << ")";
4368
4369   should_delay_load_event_ = should_delay;
4370   if (should_delay)
4371     GetDocument().IncrementLoadEventDelayCount();
4372   else
4373     GetDocument().DecrementLoadEventDelayCount();
4374 }
4375
4376 MediaControls* HTMLMediaElement::GetMediaControls() const {
4377   return media_controls_.Get();
4378 }
4379
4380 void HTMLMediaElement::EnsureMediaControls() {
4381   if (GetMediaControls())
4382     return;
4383
4384   ShadowRoot& shadow_root = EnsureUserAgentShadowRoot();
4385   UseCounterMuteScope scope(*this);
4386   media_controls_ =
4387       CoreInitializer::GetInstance().CreateMediaControls(*this, shadow_root);
4388
4389   // The media controls should be inserted after the text track container,
4390   // so that they are rendered in front of captions and subtitles. This check
4391   // is verifying the contract.
4392   AssertShadowRootChildren(shadow_root);
4393 }
4394
4395 void HTMLMediaElement::UpdateControlsVisibility() {
4396   if (!isConnected())
4397     return;
4398
4399   bool native_controls = ShouldShowControls(RecordMetricsBehavior::kDoRecord);
4400
4401   // When LazyInitializeMediaControls is enabled, initialize the controls only
4402   // if native controls should be used or if using the cast overlay.
4403   if (!RuntimeEnabledFeatures::LazyInitializeMediaControlsEnabled() ||
4404       RuntimeEnabledFeatures::MediaCastOverlayButtonEnabled() ||
4405       native_controls) {
4406     EnsureMediaControls();
4407
4408     // TODO(mlamouri): this doesn't sound needed but the following tests, on
4409     // Android fails when removed:
4410     // fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html
4411     GetMediaControls()->Reset();
4412   }
4413
4414   if (native_controls)
4415     GetMediaControls()->MaybeShow();
4416   else if (GetMediaControls())
4417     GetMediaControls()->Hide();
4418
4419   if (web_media_player_)
4420     web_media_player_->OnHasNativeControlsChanged(native_controls);
4421 }
4422
4423 CueTimeline& HTMLMediaElement::GetCueTimeline() {
4424   if (!cue_timeline_)
4425     cue_timeline_ = MakeGarbageCollected<CueTimeline>(*this);
4426   return *cue_timeline_;
4427 }
4428
4429 void HTMLMediaElement::ConfigureTextTrackDisplay() {
4430   DCHECK(text_tracks_);
4431   DVLOG(3) << "configureTextTrackDisplay(" << *this << ")";
4432
4433   if (processing_preference_change_)
4434     return;
4435
4436   bool have_visible_text_track = text_tracks_->HasShowingTracks();
4437   text_tracks_visible_ = have_visible_text_track;
4438
4439   if (!have_visible_text_track && !GetMediaControls())
4440     return;
4441
4442   // Note: The "time marches on" algorithm |CueTimeline::TimeMarchesOn| runs
4443   // the "rules for updating the text track rendering" (updateTextTrackDisplay)
4444   // only for "affected tracks", i.e. tracks where the the active cues have
4445   // changed. This misses cues in tracks that changed mode between hidden and
4446   // showing. This appears to be a spec bug, which we work around here:
4447   // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28236
4448   UpdateTextTrackDisplay();
4449 }
4450
4451 // TODO(srirama.m): Merge it to resetMediaElement if possible and remove it.
4452 void HTMLMediaElement::ResetMediaPlayerAndMediaSource() {
4453   CloseMediaSource();
4454
4455   {
4456     AudioSourceProviderClientLockScope scope(*this);
4457     ClearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
4458   }
4459
4460   if (audio_source_node_)
4461     GetAudioSourceProvider().SetClient(audio_source_node_);
4462 }
4463
4464 void HTMLMediaElement::SetAudioSourceNode(
4465     AudioSourceProviderClient* source_node) {
4466   DCHECK(IsMainThread());
4467   audio_source_node_ = source_node;
4468
4469   // No need to lock the |audio_source_node| because it locks itself when
4470   // setFormat() is invoked.
4471   GetAudioSourceProvider().SetClient(audio_source_node_);
4472 }
4473
4474 WebMediaPlayer::CorsMode HTMLMediaElement::CorsMode() const {
4475   const AtomicString& cross_origin_mode =
4476       FastGetAttribute(html_names::kCrossoriginAttr);
4477   if (cross_origin_mode.IsNull())
4478     return WebMediaPlayer::kCorsModeUnspecified;
4479   if (EqualIgnoringASCIICase(cross_origin_mode, "use-credentials"))
4480     return WebMediaPlayer::kCorsModeUseCredentials;
4481   return WebMediaPlayer::kCorsModeAnonymous;
4482 }
4483
4484 void HTMLMediaElement::SetCcLayer(cc::Layer* cc_layer) {
4485   if (cc_layer == cc_layer_)
4486     return;
4487
4488   SetNeedsCompositingUpdate();
4489   cc_layer_ = cc_layer;
4490 }
4491
4492 void HTMLMediaElement::MediaSourceOpened(WebMediaSource* web_media_source) {
4493   SetShouldDelayLoadEvent(false);
4494   media_source_attachment_->CompleteAttachingToMediaElement(
4495       media_source_tracer_, base::WrapUnique(web_media_source));
4496 }
4497
4498 bool HTMLMediaElement::IsInteractiveContent() const {
4499   return FastHasAttribute(html_names::kControlsAttr);
4500 }
4501
4502 void HTMLMediaElement::BindMediaPlayerReceiver(
4503     mojo::PendingAssociatedReceiver<media::mojom::blink::MediaPlayer>
4504         receiver) {
4505   media_player_receiver_set_->Value().Add(
4506       std::move(receiver),
4507       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
4508 }
4509
4510 void HTMLMediaElement::OnSpeakingCompleted() {
4511   if (paused())
4512     Play();
4513 }
4514
4515 void HTMLMediaElement::Trace(Visitor* visitor) const {
4516   visitor->Trace(audio_source_node_);
4517   visitor->Trace(speech_synthesis_);
4518   visitor->Trace(load_timer_);
4519   visitor->Trace(audio_tracks_timer_);
4520   visitor->Trace(removed_from_document_timer_);
4521   visitor->Trace(played_time_ranges_);
4522   visitor->Trace(async_event_queue_);
4523   visitor->Trace(error_);
4524   visitor->Trace(current_source_node_);
4525   visitor->Trace(next_child_node_to_consider_);
4526   visitor->Trace(deferred_load_timer_);
4527   visitor->Trace(media_source_tracer_);
4528   visitor->Trace(audio_tracks_);
4529   visitor->Trace(video_tracks_);
4530   visitor->Trace(cue_timeline_);
4531   visitor->Trace(text_tracks_);
4532   visitor->Trace(text_tracks_when_resource_selection_began_);
4533   visitor->Trace(play_promise_resolvers_);
4534   visitor->Trace(play_promise_resolve_list_);
4535   visitor->Trace(play_promise_reject_list_);
4536   visitor->Trace(audio_source_provider_);
4537   visitor->Trace(src_object_stream_descriptor_);
4538   visitor->Trace(src_object_media_source_handle_);
4539   visitor->Trace(autoplay_policy_);
4540   visitor->Trace(media_controls_);
4541   visitor->Trace(controls_list_);
4542   visitor->Trace(lazy_load_intersection_observer_);
4543   visitor->Trace(media_player_host_remote_);
4544   visitor->Trace(media_player_observer_remote_set_);
4545   visitor->Trace(media_player_receiver_set_);
4546   visitor->Trace(opener_document_);
4547   visitor->Trace(opener_context_observer_);
4548   Supplementable<HTMLMediaElement>::Trace(visitor);
4549   HTMLElement::Trace(visitor);
4550   ExecutionContextLifecycleStateObserver::Trace(visitor);
4551 }
4552
4553 void HTMLMediaElement::CreatePlaceholderTracksIfNecessary() {
4554   // Create a placeholder audio track if the player says it has audio but it
4555   // didn't explicitly announce the tracks.
4556   if (HasAudio() && !audioTracks().length()) {
4557     AddAudioTrack("audio", WebMediaPlayerClient::kAudioTrackKindMain,
4558                   "Audio Track", "", true);
4559   }
4560
4561   // Create a placeholder video track if the player says it has video but it
4562   // didn't explicitly announce the tracks.
4563   if (HasVideo() && !videoTracks().length()) {
4564     AddVideoTrack("video", WebMediaPlayerClient::kVideoTrackKindMain,
4565                   "Video Track", "", true);
4566   }
4567 }
4568
4569 void HTMLMediaElement::SetNetworkState(NetworkState state,
4570                                        bool update_media_controls) {
4571   if (network_state_ == state)
4572     return;
4573
4574   network_state_ = state;
4575   if (update_media_controls && GetMediaControls())
4576     GetMediaControls()->NetworkStateChanged();
4577 }
4578
4579 void HTMLMediaElement::VideoWillBeDrawnToCanvas() const {
4580   DCHECK(IsHTMLVideoElement());
4581   UseCounter::Count(GetDocument(), WebFeature::kVideoInCanvas);
4582   autoplay_policy_->VideoWillBeDrawnToCanvas();
4583 }
4584
4585 void HTMLMediaElement::ScheduleResolvePlayPromises() {
4586   // TODO(mlamouri): per spec, we should create a new task but we can't create
4587   // a new cancellable task without cancelling the previous one. There are two
4588   // approaches then: cancel the previous task and create a new one with the
4589   // appended promise list or append the new promise to the current list. The
4590   // latter approach is preferred because it might be the less observable
4591   // change.
4592   DCHECK(play_promise_resolve_list_.empty() ||
4593          play_promise_resolve_task_handle_.IsActive());
4594   if (play_promise_resolvers_.empty())
4595     return;
4596
4597   play_promise_resolve_list_.AppendVector(play_promise_resolvers_);
4598   play_promise_resolvers_.clear();
4599
4600   if (play_promise_resolve_task_handle_.IsActive())
4601     return;
4602
4603   play_promise_resolve_task_handle_ = PostCancellableTask(
4604       *GetDocument().GetTaskRunner(TaskType::kMediaElementEvent), FROM_HERE,
4605       WTF::BindOnce(&HTMLMediaElement::ResolveScheduledPlayPromises,
4606                     WrapWeakPersistent(this)));
4607 }
4608
4609 void HTMLMediaElement::ScheduleRejectPlayPromises(PlayPromiseError code) {
4610   // TODO(mlamouri): per spec, we should create a new task but we can't create
4611   // a new cancellable task without cancelling the previous one. There are two
4612   // approaches then: cancel the previous task and create a new one with the
4613   // appended promise list or append the new promise to the current list. The
4614   // latter approach is preferred because it might be the less observable
4615   // change.
4616   DCHECK(play_promise_reject_list_.empty() ||
4617          play_promise_reject_task_handle_.IsActive());
4618   if (play_promise_resolvers_.empty())
4619     return;
4620
4621   play_promise_reject_list_.AppendVector(play_promise_resolvers_);
4622   play_promise_resolvers_.clear();
4623
4624   if (play_promise_reject_task_handle_.IsActive())
4625     return;
4626
4627   // TODO(nhiroki): Bind this error code to a cancellable task instead of a
4628   // member field.
4629   play_promise_error_code_ = code;
4630   play_promise_reject_task_handle_ = PostCancellableTask(
4631       *GetDocument().GetTaskRunner(TaskType::kMediaElementEvent), FROM_HERE,
4632       WTF::BindOnce(&HTMLMediaElement::RejectScheduledPlayPromises,
4633                     WrapWeakPersistent(this)));
4634 }
4635
4636 void HTMLMediaElement::ScheduleNotifyPlaying() {
4637   ScheduleEvent(event_type_names::kPlaying);
4638   ScheduleResolvePlayPromises();
4639 }
4640
4641 void HTMLMediaElement::ResolveScheduledPlayPromises() {
4642   for (auto& resolver : play_promise_resolve_list_)
4643     resolver->Resolve();
4644
4645   play_promise_resolve_list_.clear();
4646 }
4647
4648 void HTMLMediaElement::RejectScheduledPlayPromises() {
4649   if (play_promise_error_code_ == PlayPromiseError::kNotSupported) {
4650     RejectPlayPromisesInternal(
4651         DOMExceptionCode::kNotSupportedError,
4652         "Failed to load because no supported source was found.");
4653     return;
4654   }
4655
4656   const char* reason = "";
4657   switch (play_promise_error_code_) {
4658     case PlayPromiseError::kPaused_Unknown:
4659       reason = " because the media paused";
4660       break;
4661     case PlayPromiseError::kPaused_PauseCalled:
4662       reason = " by a call to pause()";
4663       break;
4664     case PlayPromiseError::kPaused_EndOfPlayback:
4665       reason = " by end of playback";
4666       break;
4667     case PlayPromiseError::kPaused_RemovedFromDocument:
4668       reason = " because the media was removed from the document";
4669       break;
4670     case PlayPromiseError::kPaused_AutoplayAutoPause:
4671       reason = " because autoplaying background media was paused to save power";
4672       break;
4673     case PlayPromiseError::kPaused_BackgroundVideoOptimization:
4674       reason = " because video-only background media was paused to save power";
4675       break;
4676     case PlayPromiseError::kPaused_SuspendedPlayerIdleTimeout:
4677       reason = " because the player was been suspended and became idle";
4678       break;
4679     case PlayPromiseError::kPaused_RemotePlayStateChange:
4680       reason = " by a pause request from a remote media player";
4681       break;
4682     case PlayPromiseError::kPaused_PauseRequestedByUser:
4683       reason = " because a pause was requested by the user";
4684       break;
4685     case PlayPromiseError::kPaused_PauseRequestedInternally:
4686       reason = " because a pause was requested by the browser";
4687       break;
4688     case PlayPromiseError::kNotSupported:
4689       NOTREACHED();
4690   }
4691   RejectPlayPromisesInternal(
4692       DOMExceptionCode::kAbortError,
4693       String::Format(
4694           "The play() request was interrupted%s. https://goo.gl/LdLk22",
4695           reason));
4696 }
4697
4698 void HTMLMediaElement::RejectPlayPromises(DOMExceptionCode code,
4699                                           const String& message) {
4700   play_promise_reject_list_.AppendVector(play_promise_resolvers_);
4701   play_promise_resolvers_.clear();
4702   RejectPlayPromisesInternal(code, message);
4703 }
4704
4705 void HTMLMediaElement::RejectPlayPromisesInternal(DOMExceptionCode code,
4706                                                   const String& message) {
4707   DCHECK(code == DOMExceptionCode::kAbortError ||
4708          code == DOMExceptionCode::kNotSupportedError);
4709   for (auto& resolver : play_promise_reject_list_)
4710     resolver->Reject(MakeGarbageCollected<DOMException>(code, message));
4711
4712   play_promise_reject_list_.clear();
4713 }
4714
4715 void HTMLMediaElement::OnRemovedFromDocumentTimerFired(TimerBase*) {
4716   if (InActiveDocument())
4717     return;
4718
4719   // Video should not pause when playing in Picture-in-Picture and subsequently
4720   // removed from the Document.
4721   if (!PictureInPictureController::IsElementInPictureInPicture(this))
4722     PauseInternal(PlayPromiseError::kPaused_RemovedFromDocument);
4723 #if BUILDFLAG(IS_TIZEN_TV)
4724   if (!media_source_attachment_) {
4725     LOG(INFO) << "(" << (void*)this << ")"
4726               << "HTMLMediaElement::removedFrom(clear)";
4727     ClearMediaPlayer();
4728     network_state_ = kNetworkEmpty;
4729     ready_state_ = kHaveNothing;
4730     ready_state_maximum_ = kHaveNothing;
4731     seeking_ = false;
4732     // Clear any pending events
4733     SetShouldDelayLoadEvent(false);
4734     async_event_queue_->CancelAllEvents();
4735   }
4736 #endif
4737 }
4738
4739 void HTMLMediaElement::AudioSourceProviderImpl::Wrap(
4740     scoped_refptr<WebAudioSourceProviderImpl> provider) {
4741   base::AutoLock locker(provide_input_lock);
4742
4743   if (web_audio_source_provider_ && provider != web_audio_source_provider_)
4744     web_audio_source_provider_->SetClient(nullptr);
4745
4746   web_audio_source_provider_ = std::move(provider);
4747   if (web_audio_source_provider_)
4748     web_audio_source_provider_->SetClient(client_.Get());
4749 }
4750
4751 void HTMLMediaElement::AudioSourceProviderImpl::SetClient(
4752     AudioSourceProviderClient* client) {
4753   base::AutoLock locker(provide_input_lock);
4754
4755   if (client)
4756     client_ = MakeGarbageCollected<HTMLMediaElement::AudioClientImpl>(client);
4757   else
4758     client_.Clear();
4759
4760   if (web_audio_source_provider_)
4761     web_audio_source_provider_->SetClient(client_.Get());
4762 }
4763
4764 void HTMLMediaElement::AudioSourceProviderImpl::ProvideInput(
4765     AudioBus* bus,
4766     int frames_to_process) {
4767   DCHECK(bus);
4768
4769   base::AutoTryLock try_locker(provide_input_lock);
4770   if (!try_locker.is_acquired() || !web_audio_source_provider_ ||
4771       !client_.Get()) {
4772     bus->Zero();
4773     return;
4774   }
4775
4776   // Wrap the AudioBus channel data using WebVector.
4777   unsigned n = bus->NumberOfChannels();
4778   WebVector<float*> web_audio_data(n);
4779   for (unsigned i = 0; i < n; ++i)
4780     web_audio_data[i] = bus->Channel(i)->MutableData();
4781
4782   web_audio_source_provider_->ProvideInput(web_audio_data, frames_to_process);
4783 }
4784
4785 void HTMLMediaElement::AudioClientImpl::SetFormat(uint32_t number_of_channels,
4786                                                   float sample_rate) {
4787   if (client_)
4788     client_->SetFormat(number_of_channels, sample_rate);
4789 }
4790
4791 void HTMLMediaElement::AudioClientImpl::Trace(Visitor* visitor) const {
4792   visitor->Trace(client_);
4793 }
4794
4795 void HTMLMediaElement::AudioSourceProviderImpl::Trace(Visitor* visitor) const {
4796   visitor->Trace(client_);
4797 }
4798
4799 bool HTMLMediaElement::HasNativeControls() {
4800   return ShouldShowControls(RecordMetricsBehavior::kDoRecord);
4801 }
4802
4803 bool HTMLMediaElement::IsAudioElement() {
4804   return IsHTMLAudioElement();
4805 }
4806
4807 DisplayType HTMLMediaElement::GetDisplayType() const {
4808   return IsFullscreen() ? DisplayType::kFullscreen : DisplayType::kInline;
4809 }
4810
4811 gfx::ColorSpace HTMLMediaElement::TargetColorSpace() {
4812   LocalFrame* frame = GetDocument().GetFrame();
4813   if (!frame)
4814     return gfx::ColorSpace();
4815   return frame->GetPage()
4816       ->GetChromeClient()
4817       .GetScreenInfo(*frame)
4818       .display_color_spaces.GetScreenInfoColorSpace();
4819 }
4820
4821 bool HTMLMediaElement::WasAutoplayInitiated() {
4822   return autoplay_policy_->WasAutoplayInitiated();
4823 }
4824
4825 void HTMLMediaElement::ResumePlayback() {
4826   autoplay_policy_->EnsureAutoplayInitiatedSet();
4827   PlayInternal();
4828 }
4829
4830 void HTMLMediaElement::PausePlayback(PauseReason pause_reason) {
4831   switch (pause_reason) {
4832     case PauseReason::kUnknown:
4833       return PauseInternal(PlayPromiseError::kPaused_Unknown);
4834     case PauseReason::kBackgroundVideoOptimization:
4835       return PauseInternal(
4836           PlayPromiseError::kPaused_BackgroundVideoOptimization);
4837     case PauseReason::kSuspendedPlayerIdleTimeout:
4838       return PauseInternal(
4839           PlayPromiseError::kPaused_SuspendedPlayerIdleTimeout);
4840     case PauseReason::kRemotePlayStateChange:
4841       return PauseInternal(PlayPromiseError::kPaused_RemotePlayStateChange);
4842   }
4843   NOTREACHED();
4844 }
4845
4846 void HTMLMediaElement::DidPlayerStartPlaying() {
4847   for (auto& observer : media_player_observer_remote_set_->Value())
4848     observer->OnMediaPlaying();
4849 }
4850
4851 void HTMLMediaElement::DidPlayerPaused(bool stream_ended) {
4852   for (auto& observer : media_player_observer_remote_set_->Value())
4853     observer->OnMediaPaused(stream_ended);
4854 }
4855
4856 void HTMLMediaElement::DidPlayerMutedStatusChange(bool muted) {
4857   for (auto& observer : media_player_observer_remote_set_->Value())
4858     observer->OnMutedStatusChanged(muted);
4859 }
4860
4861 void HTMLMediaElement::DidMediaMetadataChange(
4862     bool has_audio,
4863     bool has_video,
4864     media::AudioCodec audio_codec,
4865     media::VideoCodec video_codec,
4866     media::MediaContentType media_content_type,
4867     bool is_encrypted_media) {
4868   for (auto& observer : media_player_observer_remote_set_->Value()) {
4869     observer->OnMediaMetadataChanged(has_audio, has_video, media_content_type);
4870   }
4871
4872   if (video_codec == media::VideoCodec::kUnknown &&
4873       audio_codec == media::AudioCodec::kUnknown) {
4874     return;
4875   }
4876   video_codec_ = video_codec;
4877   audio_codec_ = audio_codec;
4878   is_encrypted_media_ = is_encrypted_media;
4879   OnRemotePlaybackMetadataChange();
4880 }
4881
4882 void HTMLMediaElement::DidPlayerMediaPositionStateChange(
4883     double playback_rate,
4884     base::TimeDelta duration,
4885     base::TimeDelta position,
4886     bool end_of_media) {
4887   for (auto& observer : media_player_observer_remote_set_->Value()) {
4888     observer->OnMediaPositionStateChanged(
4889         media_session::mojom::blink::MediaPosition::New(
4890             playback_rate, duration, position, base::TimeTicks::Now(),
4891             end_of_media));
4892   }
4893 }
4894
4895 void HTMLMediaElement::DidDisableAudioOutputSinkChanges() {
4896   for (auto& observer : media_player_observer_remote_set_->Value())
4897     observer->OnAudioOutputSinkChangingDisabled();
4898 }
4899
4900 void HTMLMediaElement::DidUseAudioServiceChange(bool uses_audio_service) {
4901   for (auto& observer : media_player_observer_remote_set_->Value()) {
4902     observer->OnUseAudioServiceChanged(uses_audio_service);
4903   }
4904 }
4905
4906 void HTMLMediaElement::DidPlayerSizeChange(const gfx::Size& size) {
4907   for (auto& observer : media_player_observer_remote_set_->Value())
4908     observer->OnMediaSizeChanged(size);
4909 }
4910
4911 void HTMLMediaElement::OnRemotePlaybackDisabled(bool disabled) {
4912   if (is_remote_playback_disabled_ == disabled)
4913     return;
4914   is_remote_playback_disabled_ = disabled;
4915   OnRemotePlaybackMetadataChange();
4916 }
4917
4918 #if defined(TIZEN_MULTIMEDIA)
4919 void HTMLMediaElement::SuspendPlayer() {
4920   progress_event_timer_.Stop();
4921   ScheduleEvent(event_type_names::kSuspend);
4922   SetShouldDelayLoadEvent(false);
4923   SetNetworkState(kNetworkIdle);
4924 }
4925
4926 void HTMLMediaElement::OnLivePlaybackComplete() {
4927   live_playback_complete_ = true;
4928 }
4929 #endif
4930
4931 media::mojom::blink::MediaPlayerHost&
4932 HTMLMediaElement::GetMediaPlayerHostRemote() {
4933   // It is an error to call this before having access to the document's frame.
4934   DCHECK(GetDocument().GetFrame());
4935   if (!media_player_host_remote_->Value().is_bound()) {
4936     GetDocument()
4937         .GetFrame()
4938         ->GetRemoteNavigationAssociatedInterfaces()
4939         ->GetInterface(
4940             media_player_host_remote_->Value().BindNewEndpointAndPassReceiver(
4941                 GetDocument().GetTaskRunner(TaskType::kInternalMedia)));
4942   }
4943   return *media_player_host_remote_->Value().get();
4944 }
4945
4946 mojo::PendingAssociatedReceiver<media::mojom::blink::MediaPlayerObserver>
4947 HTMLMediaElement::AddMediaPlayerObserverAndPassReceiver() {
4948   mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayerObserver>
4949       observer;
4950   auto observer_receiver = observer.InitWithNewEndpointAndPassReceiver();
4951   media_player_observer_remote_set_->Value().Add(
4952       std::move(observer),
4953       GetDocument().GetTaskRunner(TaskType::kInternalMedia));
4954   return observer_receiver;
4955 }
4956
4957 void HTMLMediaElement::RequestPlay() {
4958   LocalFrame* frame = GetDocument().GetFrame();
4959   if (frame) {
4960     LocalFrame::NotifyUserActivation(
4961         frame, mojom::blink::UserActivationNotificationType::kInteraction);
4962   }
4963   autoplay_policy_->EnsureAutoplayInitiatedSet();
4964   PlayInternal();
4965 }
4966
4967 void HTMLMediaElement::RequestPause(bool triggered_by_user) {
4968   if (triggered_by_user) {
4969     LocalFrame* frame = GetDocument().GetFrame();
4970     if (frame) {
4971       LocalFrame::NotifyUserActivation(
4972           frame, mojom::blink::UserActivationNotificationType::kInteraction);
4973     }
4974   }
4975   PauseInternal(triggered_by_user
4976                     ? PlayPromiseError::kPaused_PauseRequestedByUser
4977                     : PlayPromiseError::kPaused_PauseRequestedInternally);
4978 }
4979
4980 void HTMLMediaElement::RequestSeekForward(base::TimeDelta seek_time) {
4981   double seconds = seek_time.InSecondsF();
4982   DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
4983   setCurrentTime(currentTime() + seconds);
4984 }
4985
4986 void HTMLMediaElement::RequestSeekBackward(base::TimeDelta seek_time) {
4987   double seconds = seek_time.InSecondsF();
4988   DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
4989   setCurrentTime(currentTime() - seconds);
4990 }
4991
4992 void HTMLMediaElement::RequestSeekTo(base::TimeDelta seek_time) {
4993   setCurrentTime(seek_time.InSecondsF());
4994 }
4995
4996 void HTMLMediaElement::RequestMute(bool mute) {
4997   setMuted(mute);
4998 }
4999
5000 void HTMLMediaElement::SetVolumeMultiplier(double multiplier) {
5001   if (web_media_player_)
5002     web_media_player_->SetVolumeMultiplier(multiplier);
5003 }
5004
5005 void HTMLMediaElement::SetPowerExperimentState(bool enabled) {
5006   if (web_media_player_)
5007     web_media_player_->SetPowerExperimentState(enabled);
5008 }
5009
5010 void HTMLMediaElement::SetAudioSinkId(const String& sink_id) {
5011   auto* audio_output_controller = AudioOutputDeviceController::From(*this);
5012   DCHECK(audio_output_controller);
5013
5014   audio_output_controller->SetSinkId(sink_id);
5015 }
5016
5017 void HTMLMediaElement::SuspendForFrameClosed() {
5018   if (web_media_player_)
5019     web_media_player_->SuspendForFrameClosed();
5020 }
5021
5022 bool HTMLMediaElement::MediaShouldBeOpaque() const {
5023   return !IsMediaDataCorsSameOrigin() && ready_state_ < kHaveMetadata &&
5024          EffectivePreloadType() != WebMediaPlayer::kPreloadNone;
5025 }
5026
5027 void HTMLMediaElement::SetError(MediaError* error) {
5028   error_ = error;
5029
5030   if (error) {
5031     DLOG(ERROR) << __func__ << ": {code=" << error->code()
5032                 << ", message=" << error->message() << "}";
5033     if (media_source_attachment_)
5034       media_source_attachment_->OnElementError();
5035   }
5036 }
5037
5038 void HTMLMediaElement::ReportCurrentTimeToMediaSource() {
5039   if (!media_source_attachment_)
5040     return;
5041
5042   // See MediaSourceAttachment::OnElementTimeUpdate() for why the attachment
5043   // needs our currentTime.
5044   media_source_attachment_->OnElementTimeUpdate(currentTime());
5045 }
5046
5047 void HTMLMediaElement::OnRemotePlaybackMetadataChange() {
5048   if (remote_playback_client_) {
5049     remote_playback_client_->MediaMetadataChanged(video_codec_, audio_codec_);
5050   }
5051   for (auto& observer : media_player_observer_remote_set_->Value()) {
5052     observer->OnRemotePlaybackMetadataChange(
5053         media_session::mojom::blink::RemotePlaybackMetadata::New(
5054             WTF::String(media::GetCodecName(video_codec_)),
5055             WTF::String(media::GetCodecName(audio_codec_)),
5056             is_remote_playback_disabled_, is_remote_rendering_,
5057             WTF::String(remote_device_friendly_name_), is_encrypted_media_));
5058   }
5059 }
5060
5061 HTMLMediaElement::OpenerContextObserver::OpenerContextObserver(
5062     HTMLMediaElement* element)
5063     : element_(element) {}
5064
5065 HTMLMediaElement::OpenerContextObserver::~OpenerContextObserver() = default;
5066
5067 void HTMLMediaElement::OpenerContextObserver::Trace(Visitor* visitor) const {
5068   ContextLifecycleObserver::Trace(visitor);
5069   visitor->Trace(element_);
5070 }
5071
5072 void HTMLMediaElement::OpenerContextObserver::ContextDestroyed() {
5073   element_->AttachToNewFrame();
5074 }
5075
5076 #if defined(TIZEN_MULTIMEDIA_SUPPORT)
5077 void HTMLMediaElement::MediaPlayerHidden() {
5078   LOG(INFO) << "Media player hidden: " << this;
5079   // TODO(m.debski): It should store periodic timers and restore on shown.
5080   // Currently they will still fire, but will return immediately.
5081   suppress_events_ = true;
5082 }
5083
5084 void HTMLMediaElement::MediaPlayerShown() {
5085   LOG(INFO) << "Media player shown: " << this;
5086   suppress_events_ = false;
5087 }
5088
5089 void HTMLMediaElement::Suspend() {
5090   LOG(INFO) << "Suspend(" << (void*)this << ")";
5091   if (!GetWebMediaPlayer())
5092     return;
5093
5094 #if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
5095   if (media_source_attachment_) {
5096     // Send suspend event to the source before WebMediaPlayer suspends backend.
5097     media_source_attachment_->OnSuspend(media_source_tracer_);
5098   }
5099 #endif  // SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE
5100
5101   GetWebMediaPlayer()->Suspend();
5102 }
5103
5104 void HTMLMediaElement::Resume() {
5105   LOG(INFO) << "Resume(" << (void*)this << ")";
5106   if (!GetWebMediaPlayer())
5107     return;
5108
5109 #if BUILDFLAG(IS_TIZEN_TV)
5110   // IsViewResumedByTabSwitching, return true on the tab which has no
5111   // floatwindow, otherwise it is false
5112   if (GetDocument().GetPage() &&
5113       GetDocument().GetPage()->IsViewResumedByTabSwitching()) {
5114     GetWebMediaPlayer()->Deactivate();
5115     LOG(INFO) << "is_deactivate_ TRUE";
5116     is_deactivate_ = true;
5117   } else if (is_deactivate_) {
5118     GetWebMediaPlayer()->Activate();
5119     LOG(INFO) << "is_deactivate_ FALSE";
5120     is_deactivate_ = false;
5121   }
5122 #endif
5123
5124   GetWebMediaPlayer()->Resume();
5125
5126 #if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
5127   if (media_source_attachment_) {
5128     // Send suspend event to the source after WebMediaPlayer resumes backend.
5129     media_source_attachment_->OnResume(media_source_tracer_);
5130   }
5131 #endif  // SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE
5132 }
5133
5134 void HTMLMediaElement::ActivatePlayer() {
5135   if (!GetWebMediaPlayer())
5136     return;
5137
5138   GetWebMediaPlayer()->Activate();
5139 }
5140 #endif
5141
5142 STATIC_ASSERT_ENUM(WebMediaPlayer::kReadyStateHaveNothing,
5143                    HTMLMediaElement::kHaveNothing);
5144 STATIC_ASSERT_ENUM(WebMediaPlayer::kReadyStateHaveMetadata,
5145                    HTMLMediaElement::kHaveMetadata);
5146 STATIC_ASSERT_ENUM(WebMediaPlayer::kReadyStateHaveCurrentData,
5147                    HTMLMediaElement::kHaveCurrentData);
5148 STATIC_ASSERT_ENUM(WebMediaPlayer::kReadyStateHaveFutureData,
5149                    HTMLMediaElement::kHaveFutureData);
5150 STATIC_ASSERT_ENUM(WebMediaPlayer::kReadyStateHaveEnoughData,
5151                    HTMLMediaElement::kHaveEnoughData);
5152
5153 }  // namespace blink