Media elements are allowed to continue to load media data after navigation
[WebKit-https.git] / Source / WebCore / html / HTMLMediaElement.h
1 /*
2  * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #if ENABLE(VIDEO)
29
30 #include "ActiveDOMObject.h"
31 #include "AutoplayEvent.h"
32 #include "GenericEventQueue.h"
33 #include "GenericTaskQueue.h"
34 #include "HTMLElement.h"
35 #include "HTMLMediaElementEnums.h"
36 #include "MediaCanStartListener.h"
37 #include "MediaControllerInterface.h"
38 #include "MediaElementSession.h"
39 #include "MediaProducer.h"
40 #include "UserInterfaceLayoutDirection.h"
41 #include "VisibilityChangeClient.h"
42 #include <wtf/WeakPtr.h>
43
44 #if ENABLE(VIDEO_TRACK)
45 #include "AudioTrack.h"
46 #include "CaptionUserPreferences.h"
47 #include "PODIntervalTree.h"
48 #include "TextTrack.h"
49 #include "TextTrackCue.h"
50 #include "VTTCue.h"
51 #include "VideoTrack.h"
52 #endif
53
54 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
55 #include "AudioSession.h"
56 #endif
57
58 #ifndef NDEBUG
59 #include <wtf/StringPrintStream.h>
60 #endif
61
62 namespace WebCore {
63
64 class AudioSourceProvider;
65 class AudioTrackList;
66 class AudioTrackPrivate;
67 class Blob;
68 class DOMError;
69 class DeferredPromise;
70 class SleepDisabler;
71 class Event;
72 class HTMLSourceElement;
73 class HTMLTrackElement;
74 class InbandTextTrackPrivate;
75 class MediaController;
76 class MediaControls;
77 class MediaControlsHost;
78 class MediaElementAudioSourceNode;
79 class MediaError;
80 class MediaKeys;
81 class MediaPlayer;
82 class MediaResourceLoader;
83 class MediaSession;
84 class MediaSource;
85 class MediaStream;
86 class RenderMedia;
87 class ScriptExecutionContext;
88 class SourceBuffer;
89 class TextTrackList;
90 class TimeRanges;
91 class VideoPlaybackQuality;
92 class VideoTrackList;
93 class VideoTrackPrivate;
94 class WebKitMediaKeys;
95
96 template<typename> class DOMPromiseDeferred;
97
98 #if ENABLE(VIDEO_TRACK)
99 using CueIntervalTree = PODIntervalTree<MediaTime, TextTrackCue*>;
100 using CueInterval = CueIntervalTree::IntervalType;
101 using CueList = Vector<CueInterval>;
102 #endif
103
104 using MediaProvider = std::optional<Variant<
105 #if ENABLE(MEDIA_STREAM)
106     RefPtr<MediaStream>,
107 #endif
108 #if ENABLE(MEDIA_SOURCE)
109     RefPtr<MediaSource>,
110 #endif
111     RefPtr<Blob>>>;
112
113 class HTMLMediaElement
114     : public HTMLElement
115     , public ActiveDOMObject
116     , public MediaControllerInterface
117     , public MediaPlayerSupportsTypeClient
118     , public PlatformMediaSessionClient
119     , private MediaCanStartListener
120     , private MediaPlayerClient
121     , private MediaProducer
122     , private VisibilityChangeClient
123 #if ENABLE(VIDEO_TRACK)
124     , private AudioTrackClient
125     , private TextTrackClient
126     , private VideoTrackClient
127 #endif
128 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
129     , private AudioSession::MutedStateObserver
130 #endif
131 {
132 public:
133     WeakPtr<HTMLMediaElement> createWeakPtr() { return m_weakFactory.createWeakPtr(); }
134     MediaPlayer* player() const { return m_player.get(); }
135
136     virtual bool isVideo() const { return false; }
137     bool hasVideo() const override { return false; }
138     bool hasAudio() const override;
139
140     static HashSet<HTMLMediaElement*>& allMediaElements();
141
142     static HTMLMediaElement* bestMediaElementForShowingPlaybackControlsManager(MediaElementSession::PlaybackControlsPurpose);
143
144     void rewind(double timeDelta);
145     WEBCORE_EXPORT void returnToRealtime() override;
146
147     // Eventually overloaded in HTMLVideoElement
148     bool supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenMode) const override { return false; };
149
150     bool supportsScanning() const override;
151
152     bool canSaveMediaData() const;
153
154     bool doesHaveAttribute(const AtomicString&, AtomicString* value = nullptr) const override;
155
156     WEBCORE_EXPORT PlatformMedia platformMedia() const;
157     PlatformLayer* platformLayer() const;
158     bool isVideoLayerInline();
159     void setPreparedToReturnVideoLayerToInline(bool);
160     void waitForPreparedForInlineThen(std::function<void()> completionHandler = [] { });
161 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
162     void setVideoFullscreenLayer(PlatformLayer*, std::function<void()> completionHandler = [] { });
163     PlatformLayer* videoFullscreenLayer() const { return m_videoFullscreenLayer.get(); }
164     void setVideoFullscreenFrame(FloatRect);
165     void setVideoFullscreenGravity(MediaPlayerEnums::VideoGravity);
166     MediaPlayerEnums::VideoGravity videoFullscreenGravity() const { return m_videoFullscreenGravity; }
167 #endif
168
169     using HTMLMediaElementEnums::DelayedActionType;
170     void scheduleDelayedAction(DelayedActionType);
171     void scheduleResolvePendingPlayPromises();
172     void rejectPendingPlayPromises(DOMError&);
173     void resolvePendingPlayPromises();
174     void scheduleNotifyAboutPlaying();
175     void notifyAboutPlaying();
176     
177     MediaPlayerEnums::MovieLoadType movieLoadType() const;
178     
179     bool inActiveDocument() const { return m_inActiveDocument; }
180
181     const Document* hostingDocument() const override { return &document(); }
182
183 // DOM API
184 // error state
185     WEBCORE_EXPORT MediaError* error() const;
186
187     const URL& currentSrc() const { return m_currentSrc; }
188
189     const MediaProvider& srcObject() const { return m_mediaProvider; }
190     void setSrcObject(MediaProvider&&);
191
192     WEBCORE_EXPORT void setCrossOrigin(const AtomicString&);
193     WEBCORE_EXPORT String crossOrigin() const;
194
195 // network state
196     using HTMLMediaElementEnums::NetworkState;
197     WEBCORE_EXPORT NetworkState networkState() const;
198
199     WEBCORE_EXPORT String preload() const;
200     WEBCORE_EXPORT void setPreload(const String&);
201
202     Ref<TimeRanges> buffered() const override;
203     WEBCORE_EXPORT void load();
204     WEBCORE_EXPORT String canPlayType(const String& mimeType) const;
205
206 // ready state
207     using HTMLMediaElementEnums::ReadyState;
208     ReadyState readyState() const override;
209     WEBCORE_EXPORT bool seeking() const;
210
211 // playback state
212     WEBCORE_EXPORT double currentTime() const override;
213     void setCurrentTime(double) override;
214     double currentTimeForBindings() const { return currentTime(); }
215     WEBCORE_EXPORT ExceptionOr<void> setCurrentTimeForBindings(double);
216     WEBCORE_EXPORT double getStartDate() const;
217     WEBCORE_EXPORT double duration() const override;
218     WEBCORE_EXPORT bool paused() const override;
219     double defaultPlaybackRate() const override;
220     void setDefaultPlaybackRate(double) override;
221     WEBCORE_EXPORT double playbackRate() const override;
222     void setPlaybackRate(double) override;
223
224 // MediaTime versions of playback state
225     MediaTime currentMediaTime() const;
226     void setCurrentTime(const MediaTime&);
227     MediaTime durationMediaTime() const;
228     WEBCORE_EXPORT void fastSeek(const MediaTime&);
229
230     void updatePlaybackRate();
231     WEBCORE_EXPORT bool webkitPreservesPitch() const;
232     WEBCORE_EXPORT void setWebkitPreservesPitch(bool);
233     Ref<TimeRanges> played() override;
234     Ref<TimeRanges> seekable() const override;
235     double seekableTimeRangesLastModifiedTime() const;
236     double liveUpdateInterval() const;
237     WEBCORE_EXPORT bool ended() const;
238     bool autoplay() const;
239     bool isAutoplaying() const { return m_autoplaying; }
240     bool loop() const;
241     void setLoop(bool b);
242
243     void play(DOMPromiseDeferred<void>&&);
244
245     WEBCORE_EXPORT void play() override;
246     WEBCORE_EXPORT void pause() override;
247     void setShouldBufferData(bool) override;
248     WEBCORE_EXPORT void fastSeek(double);
249     double minFastReverseRate() const;
250     double maxFastForwardRate() const;
251
252     void purgeBufferedDataIfPossible();
253
254 // captions
255     WEBCORE_EXPORT bool webkitHasClosedCaptions() const;
256     WEBCORE_EXPORT bool webkitClosedCaptionsVisible() const;
257     WEBCORE_EXPORT void setWebkitClosedCaptionsVisible(bool);
258
259     bool elementIsHidden() const override { return m_elementIsHidden; }
260
261 #if ENABLE(MEDIA_STATISTICS)
262 // Statistics
263     unsigned webkitAudioDecodedByteCount() const;
264     unsigned webkitVideoDecodedByteCount() const;
265 #endif
266
267 #if ENABLE(MEDIA_SOURCE)
268 //  Media Source.
269     void detachMediaSource();
270     void incrementDroppedFrameCount() { ++m_droppedVideoFrames; }
271     size_t maximumSourceBufferSize(const SourceBuffer&) const;
272 #endif
273
274 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
275     WebKitMediaKeys* webkitKeys() const { return m_webKitMediaKeys.get(); }
276     void webkitSetMediaKeys(WebKitMediaKeys*);
277
278     void keyAdded();
279 #endif
280
281 #if ENABLE(ENCRYPTED_MEDIA)
282     MediaKeys* mediaKeys() const;
283
284     void setMediaKeys(MediaKeys*, Ref<DeferredPromise>&&);
285 #endif
286
287 // controls
288     WEBCORE_EXPORT bool controls() const;
289     WEBCORE_EXPORT void setControls(bool);
290     WEBCORE_EXPORT double volume() const override;
291     ExceptionOr<void> setVolume(double) override;
292     WEBCORE_EXPORT bool muted() const override;
293     WEBCORE_EXPORT void setMuted(bool) override;
294
295     WEBCORE_EXPORT void togglePlayState();
296     WEBCORE_EXPORT void beginScrubbing() override;
297     WEBCORE_EXPORT void endScrubbing() override;
298
299     void beginScanning(ScanDirection) override;
300     void endScanning() override;
301     double nextScanRate();
302
303     WEBCORE_EXPORT bool canPlay() const override;
304
305     double percentLoaded() const;
306
307     bool shouldForceControlsDisplay() const;
308
309 #if ENABLE(VIDEO_TRACK)
310     ExceptionOr<TextTrack&> addTextTrack(const String& kind, const String& label, const String& language);
311
312     AudioTrackList& audioTracks();
313     TextTrackList& textTracks();
314     VideoTrackList& videoTracks();
315
316     CueList currentlyActiveCues() const { return m_currentlyActiveCues; }
317
318     void addAudioTrack(Ref<AudioTrack>&&);
319     void addTextTrack(Ref<TextTrack>&&);
320     void addVideoTrack(Ref<VideoTrack>&&);
321     void removeAudioTrack(AudioTrack&);
322     void removeTextTrack(TextTrack&, bool scheduleEvent = true);
323     void removeVideoTrack(VideoTrack&);
324     void forgetResourceSpecificTracks();
325     void closeCaptionTracksChanged();
326     void notifyMediaPlayerOfTextTrackChanges();
327
328     virtual void didAddTextTrack(HTMLTrackElement&);
329     virtual void didRemoveTextTrack(HTMLTrackElement&);
330
331     void mediaPlayerDidAddAudioTrack(AudioTrackPrivate&) final;
332     void mediaPlayerDidAddTextTrack(InbandTextTrackPrivate&) final;
333     void mediaPlayerDidAddVideoTrack(VideoTrackPrivate&) final;
334     void mediaPlayerDidRemoveAudioTrack(AudioTrackPrivate&) final;
335     void mediaPlayerDidRemoveTextTrack(InbandTextTrackPrivate&) final;
336     void mediaPlayerDidRemoveVideoTrack(VideoTrackPrivate&) final;
337
338 #if ENABLE(AVF_CAPTIONS)
339     Vector<RefPtr<PlatformTextTrack>> outOfBandTrackSources() final;
340 #endif
341
342     struct TrackGroup;
343     void configureTextTrackGroupForLanguage(const TrackGroup&) const;
344     void configureTextTracks();
345     void configureTextTrackGroup(const TrackGroup&);
346
347     void setSelectedTextTrack(TextTrack*);
348
349     bool textTracksAreReady() const;
350     using HTMLMediaElementEnums::TextTrackVisibilityCheckType;
351     void configureTextTrackDisplay(TextTrackVisibilityCheckType checkType = CheckTextTrackVisibility);
352     void updateTextTrackDisplay();
353
354     // AudioTrackClient
355     void audioTrackEnabledChanged(AudioTrack&) final;
356
357     void textTrackReadyStateChanged(TextTrack*);
358
359     // TextTrackClient
360     void textTrackKindChanged(TextTrack&) override;
361     void textTrackModeChanged(TextTrack&) override;
362     void textTrackAddCues(TextTrack&, const TextTrackCueList&) override;
363     void textTrackRemoveCues(TextTrack&, const TextTrackCueList&) override;
364     void textTrackAddCue(TextTrack&, TextTrackCue&) override;
365     void textTrackRemoveCue(TextTrack&, TextTrackCue&) override;
366
367     // VideoTrackClient
368     void videoTrackSelectedChanged(VideoTrack&) final;
369
370     bool requiresTextTrackRepresentation() const;
371     void setTextTrackRepresentation(TextTrackRepresentation*);
372     void syncTextTrackBounds();
373 #endif
374
375 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
376     void webkitShowPlaybackTargetPicker();
377     bool addEventListener(const AtomicString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) override;
378     bool removeEventListener(const AtomicString& eventType, EventListener&, const ListenerOptions&) override;
379
380     void wirelessRoutesAvailableDidChange() override;
381     bool canPlayToWirelessPlaybackTarget() const override;
382     bool isPlayingToWirelessPlaybackTarget() const override;
383     void setWirelessPlaybackTarget(Ref<MediaPlaybackTarget>&&) override;
384     void setShouldPlayToPlaybackTarget(bool) override;
385 #endif
386     bool webkitCurrentPlaybackTargetIsWireless() const;
387
388     // EventTarget function.
389     // Both Node (via HTMLElement) and ActiveDOMObject define this method, which
390     // causes an ambiguity error at compile time. This class's constructor
391     // ensures that both implementations return document, so return the result
392     // of one of them here.
393     using HTMLElement::scriptExecutionContext;
394
395     bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); }
396     
397     WEBCORE_EXPORT bool isFullscreen() const override;
398     bool isStandardFullscreen() const;
399     void toggleStandardFullscreenState();
400
401     using MediaPlayerEnums::VideoFullscreenMode;
402     VideoFullscreenMode fullscreenMode() const { return m_videoFullscreenMode; }
403     virtual void fullscreenModeChanged(VideoFullscreenMode);
404
405     void enterFullscreen(VideoFullscreenMode);
406     void enterFullscreen() override;
407     WEBCORE_EXPORT void exitFullscreen();
408
409     bool hasClosedCaptions() const override;
410     bool closedCaptionsVisible() const override;
411     void setClosedCaptionsVisible(bool) override;
412
413     MediaControls* mediaControls() const;
414
415     void sourceWasRemoved(HTMLSourceElement&);
416     void sourceWasAdded(HTMLSourceElement&);
417
418     void privateBrowsingStateDidChange() override;
419
420     // Media cache management.
421     WEBCORE_EXPORT static void setMediaCacheDirectory(const String&);
422     WEBCORE_EXPORT static const String& mediaCacheDirectory();
423     WEBCORE_EXPORT static HashSet<RefPtr<SecurityOrigin>> originsInMediaCache(const String&);
424     WEBCORE_EXPORT static void clearMediaCache(const String&, std::chrono::system_clock::time_point modifiedSince = { });
425     WEBCORE_EXPORT static void clearMediaCacheForOrigins(const String&, const HashSet<RefPtr<SecurityOrigin>>&);
426     static void resetMediaEngines();
427
428     bool isPlaying() const { return m_playing; }
429
430     bool hasPendingActivity() const override;
431
432 #if ENABLE(WEB_AUDIO)
433     MediaElementAudioSourceNode* audioSourceNode() { return m_audioSourceNode; }
434     void setAudioSourceNode(MediaElementAudioSourceNode*);
435
436     AudioSourceProvider* audioSourceProvider();
437 #endif
438
439     using HTMLMediaElementEnums::InvalidURLAction;
440     bool isSafeToLoadURL(const URL&, InvalidURLAction);
441
442     const String& mediaGroup() const;
443     void setMediaGroup(const String&);
444
445     MediaController* controller() const;
446     void setController(RefPtr<MediaController>&&);
447
448     MediaController* controllerForBindings() const { return controller(); }
449     void setControllerForBindings(MediaController*);
450
451     void enteredOrExitedFullscreen() { configureMediaControls(); }
452
453     unsigned long long fileSize() const;
454
455     void mediaLoadingFailed(MediaPlayerEnums::NetworkState);
456     void mediaLoadingFailedFatally(MediaPlayerEnums::NetworkState);
457
458 #if ENABLE(MEDIA_SESSION)
459     WEBCORE_EXPORT double playerVolume() const;
460
461     const String& kind() const { return m_kind; }
462     void setKind(const String& kind) { m_kind = kind; }
463
464     MediaSession* session() const;
465     void setSession(MediaSession*);
466
467     void setShouldDuck(bool);
468
469     static HTMLMediaElement* elementWithID(uint64_t);
470     uint64_t elementID() const { return m_elementID; }
471 #endif
472
473 #if ENABLE(MEDIA_SOURCE)
474     RefPtr<VideoPlaybackQuality> getVideoPlaybackQuality();
475 #endif
476
477     MediaPlayerEnums::Preload preloadValue() const { return m_preload; }
478     MediaElementSession& mediaSession() const { return *m_mediaSession; }
479
480 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
481     void pageScaleFactorChanged();
482     void userInterfaceLayoutDirectionChanged();
483     WEBCORE_EXPORT String getCurrentMediaControlsStatus();
484
485     MediaControlsHost* mediaControlsHost() { return m_mediaControlsHost.get(); }
486 #endif
487
488     bool isDisablingSleep() const { return m_sleepDisabler.get(); }
489
490     double maxBufferedTime() const;
491
492     MediaProducer::MediaStateFlags mediaState() const override;
493
494     void layoutSizeChanged();
495     void visibilityDidChange();
496
497     void allowsMediaDocumentInlinePlaybackChanged();
498     void updateShouldPlay();
499
500     RenderMedia* renderer() const;
501
502     void resetPlaybackSessionState();
503     bool isVisibleInViewport() const;
504     bool hasEverNotifiedAboutPlaying() const;
505     void setShouldDelayLoadEvent(bool);
506
507     bool hasEverHadAudio() const { return m_hasEverHadAudio; }
508     bool hasEverHadVideo() const { return m_hasEverHadVideo; }
509
510     double playbackStartedTime() const { return m_playbackStartedTime; }
511
512     bool isTemporarilyAllowingInlinePlaybackAfterFullscreen() const {return m_temporarilyAllowingInlinePlaybackAfterFullscreen; }
513
514     void isVisibleInViewportChanged();
515
516     WEBCORE_EXPORT const MediaResourceLoader* lastMediaResourceLoaderForTesting() const;
517
518 #if ENABLE(MEDIA_STREAM)
519     void mediaStreamCaptureStarted() { resumeAutoplaying(); }
520     bool hasMediaStreamSrcObject() const { return !!m_mediaStreamSrcObject; }
521 #endif
522
523     bool supportsSeeking() const override;
524
525 protected:
526     HTMLMediaElement(const QualifiedName&, Document&, bool createdByParser);
527     virtual ~HTMLMediaElement();
528
529     void parseAttribute(const QualifiedName&, const AtomicString&) override;
530     void finishParsingChildren() override;
531     bool isURLAttribute(const Attribute&) const override;
532     void willAttachRenderers() override;
533     void didAttachRenderers() override;
534     void willDetachRenderers() override;
535     void didDetachRenderers() override;
536
537     void didMoveToNewDocument(Document& oldDocument, Document& newDocument) override;
538
539     enum DisplayMode { Unknown, None, Poster, PosterWaitingForVideo, Video };
540     DisplayMode displayMode() const { return m_displayMode; }
541     virtual void setDisplayMode(DisplayMode mode) { m_displayMode = mode; }
542     
543     bool isMediaElement() const final { return true; }
544
545 #if ENABLE(VIDEO_TRACK)
546     bool ignoreTrackDisplayUpdateRequests() const { return m_ignoreTrackDisplayUpdate > 0 || !m_textTracks || !m_cueTree.size(); }
547     void beginIgnoringTrackDisplayUpdateRequests();
548     void endIgnoringTrackDisplayUpdateRequests();
549 #endif
550
551     RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
552
553 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
554     bool mediaControlsDependOnPageScaleFactor() const { return m_mediaControlsDependOnPageScaleFactor; }
555     void setMediaControlsDependOnPageScaleFactor(bool);
556     void updateMediaControlsAfterPresentationModeChange();
557 #endif
558
559     void scheduleEvent(const AtomicString& eventName);
560
561 private:
562     void createMediaPlayer();
563
564     bool alwaysCreateUserAgentShadowRoot() const override { return true; }
565
566     bool supportsFocus() const override;
567     bool isMouseFocusable() const override;
568     bool rendererIsNeeded(const RenderStyle&) override;
569     bool childShouldCreateRenderer(const Node&) const override;
570     InsertionNotificationRequest insertedInto(ContainerNode&) override;
571     void finishedInsertingSubtree() override;
572     void removedFrom(ContainerNode&) override;
573     void didRecalcStyle(Style::Change) override;
574
575     void willBecomeFullscreenElement() override;
576     void didBecomeFullscreenElement() override;
577     void willStopBeingFullscreenElement() override;
578
579     // ActiveDOMObject API.
580     const char* activeDOMObjectName() const override;
581     bool canSuspendForDocumentSuspension() const override;
582     void suspend(ReasonForSuspension) override;
583     void resume() override;
584     void stop() override;
585     void stopWithoutDestroyingMediaPlayer();
586     void contextDestroyed() override;
587     
588     void mediaVolumeDidChange() override;
589
590     void visibilityStateChanged() override;
591
592     virtual void updateDisplayState() { }
593     
594     void setReadyState(MediaPlayerEnums::ReadyState);
595     void setNetworkState(MediaPlayerEnums::NetworkState);
596
597     double effectivePlaybackRate() const;
598     double requestedPlaybackRate() const;
599
600     void mediaPlayerNetworkStateChanged(MediaPlayer*) override;
601     void mediaPlayerReadyStateChanged(MediaPlayer*) override;
602     void mediaPlayerTimeChanged(MediaPlayer*) override;
603     void mediaPlayerVolumeChanged(MediaPlayer*) override;
604     void mediaPlayerMuteChanged(MediaPlayer*) override;
605     void mediaPlayerDurationChanged(MediaPlayer*) override;
606     void mediaPlayerRateChanged(MediaPlayer*) override;
607     void mediaPlayerPlaybackStateChanged(MediaPlayer*) override;
608     void mediaPlayerSawUnsupportedTracks(MediaPlayer*) override;
609     void mediaPlayerResourceNotSupported(MediaPlayer*) override;
610     void mediaPlayerRepaint(MediaPlayer*) override;
611     void mediaPlayerSizeChanged(MediaPlayer*) override;
612     bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) override;
613     void mediaPlayerRenderingModeChanged(MediaPlayer*) override;
614     bool mediaPlayerAcceleratedCompositingEnabled() override;
615     void mediaPlayerEngineUpdated(MediaPlayer*) override;
616     void mediaEngineWasUpdated();
617
618     void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*) override;
619     void mediaPlayerCharacteristicChanged(MediaPlayer*) override;
620
621 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
622     RefPtr<ArrayBuffer> mediaPlayerCachedKeyForKeyId(const String& keyId) const override;
623     bool mediaPlayerKeyNeeded(MediaPlayer*, Uint8Array*) override;
624     String mediaPlayerMediaKeysStorageDirectory() const override;
625 #endif
626     
627 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
628     void mediaPlayerCurrentPlaybackTargetIsWirelessChanged(MediaPlayer*) override;
629     void enqueuePlaybackTargetAvailabilityChangedEvent();
630
631     using EventTarget::dispatchEvent;
632     bool dispatchEvent(Event&) override;
633 #endif
634
635 #if ENABLE(MEDIA_SESSION)
636     void setSessionInternal(MediaSession&);
637 #endif
638
639     String mediaPlayerReferrer() const override;
640     String mediaPlayerUserAgent() const override;
641
642     bool mediaPlayerNeedsSiteSpecificHacks() const override;
643     String mediaPlayerDocumentHost() const override;
644
645     void mediaPlayerEnterFullscreen() override;
646     void mediaPlayerExitFullscreen() override;
647     bool mediaPlayerIsFullscreen() const override;
648     bool mediaPlayerIsFullscreenPermitted() const override;
649     bool mediaPlayerIsVideo() const override;
650     LayoutRect mediaPlayerContentBoxRect() const override;
651     float mediaPlayerContentsScale() const override;
652     void mediaPlayerSetSize(const IntSize&) override;
653     void mediaPlayerPause() override;
654     void mediaPlayerPlay() override;
655     bool mediaPlayerPlatformVolumeConfigurationRequired() const override;
656     bool mediaPlayerIsPaused() const override;
657     bool mediaPlayerIsLooping() const override;
658     CachedResourceLoader* mediaPlayerCachedResourceLoader() override;
659     RefPtr<PlatformMediaResourceLoader> mediaPlayerCreateResourceLoader() override;
660     bool mediaPlayerShouldUsePersistentCache() const override;
661     const String& mediaPlayerMediaCacheDirectory() const override;
662
663 #if PLATFORM(WIN) && USE(AVFOUNDATION)
664     GraphicsDeviceAdapter* mediaPlayerGraphicsDeviceAdapter(const MediaPlayer*) const override;
665 #endif
666
667     void mediaPlayerActiveSourceBuffersChanged(const MediaPlayer*) override;
668
669     bool mediaPlayerShouldWaitForResponseToAuthenticationChallenge(const AuthenticationChallenge&) override;
670     void mediaPlayerHandlePlaybackCommand(PlatformMediaSession::RemoteControlCommandType command) override { didReceiveRemoteControlCommand(command, nullptr); }
671     String sourceApplicationIdentifier() const override;
672     String mediaPlayerSourceApplicationIdentifier() const override { return sourceApplicationIdentifier(); }
673     Vector<String> mediaPlayerPreferredAudioCharacteristics() const override;
674
675 #if PLATFORM(IOS)
676     String mediaPlayerNetworkInterfaceName() const override;
677     bool mediaPlayerGetRawCookies(const URL&, Vector<Cookie>&) const override;
678 #endif
679
680     bool mediaPlayerIsInMediaDocument() const final;
681     void mediaPlayerEngineFailedToLoad() const final;
682
683     double mediaPlayerRequestedPlaybackRate() const final;
684     VideoFullscreenMode mediaPlayerFullscreenMode() const final { return fullscreenMode(); }
685     bool mediaPlayerShouldDisableSleep() const final { return shouldDisableSleep() == SleepType::Display; }
686     const Vector<ContentType>& mediaContentTypesRequiringHardwareSupport() const final;
687
688 #if USE(GSTREAMER)
689     void requestInstallMissingPlugins(const String& details, const String& description, MediaPlayerRequestInstallMissingPluginsCallback&) final;
690 #endif
691
692     void pendingActionTimerFired();
693     void progressEventTimerFired();
694     void playbackProgressTimerFired();
695     void scanTimerFired();
696     void seekTask();
697     void startPlaybackProgressTimer();
698     void startProgressEventTimer();
699     void stopPeriodicTimers();
700
701     void seek(const MediaTime&);
702     void seekInternal(const MediaTime&);
703     void seekWithTolerance(const MediaTime&, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance, bool fromDOM);
704     void finishSeek();
705     void clearSeeking();
706     void addPlayedRange(const MediaTime& start, const MediaTime& end);
707     
708     void scheduleTimeupdateEvent(bool periodicEvent);
709     virtual void scheduleResizeEvent() { }
710     virtual void scheduleResizeEventIfSizeChanged() { }
711
712     void selectMediaResource();
713     void loadResource(const URL&, ContentType&, const String& keySystem);
714     void scheduleNextSourceChild();
715     void loadNextSourceChild();
716     void userCancelledLoad();
717     void clearMediaPlayer(DelayedActionType flags);
718     bool havePotentialSourceChild();
719     void noneSupported();
720     void cancelPendingEventsAndCallbacks();
721     void waitForSourceChange();
722     void prepareToPlay();
723
724     URL selectNextSourceChild(ContentType*, String* keySystem, InvalidURLAction);
725
726 #if ENABLE(VIDEO_TRACK)
727     void updateActiveTextTrackCues(const MediaTime&);
728     HTMLTrackElement* showingTrackWithSameKind(HTMLTrackElement*) const;
729
730     enum ReconfigureMode {
731         Immediately,
732         AfterDelay,
733     };
734     void markCaptionAndSubtitleTracksAsUnconfigured(ReconfigureMode);
735     void captionPreferencesChanged() override;
736 #endif
737
738     // These "internal" functions do not check user gesture restrictions.
739     bool playInternal();
740     void pauseInternal();
741
742     void prepareForLoad();
743     void allowVideoRendering();
744
745     bool processingMediaPlayerCallback() const { return m_processingMediaPlayerCallback > 0; }
746     void beginProcessingMediaPlayerCallback() { ++m_processingMediaPlayerCallback; }
747     void endProcessingMediaPlayerCallback() { ASSERT(m_processingMediaPlayerCallback); --m_processingMediaPlayerCallback; }
748
749     enum class UpdateState { Asynchronously, Synchronously };
750
751     void updatePlayState(UpdateState updateState = UpdateState::Synchronously);
752     void updateVolume();
753     void setPlaying(bool);
754     bool potentiallyPlaying() const;
755     bool endedPlayback() const;
756     bool stoppedDueToErrors() const;
757     bool pausedForUserInteraction() const;
758     bool couldPlayIfEnoughData() const;
759     void dispatchPlayPauseEventsIfNeedsQuirks();
760     SuccessOr<MediaPlaybackDenialReason> canTransitionFromAutoplayToPlay() const;
761
762     enum class PlaybackWithoutUserGesture { None, Started, Prevented };
763     void setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture);
764     void userDidInterfereWithAutoplay();
765     void handleAutoplayEvent(AutoplayEvent);
766
767     MediaTime minTimeSeekable() const;
768     MediaTime maxTimeSeekable() const;
769
770     // Pauses playback without changing any states or generating events
771     void setPausedInternal(bool);
772
773     void setPlaybackRateInternal(double);
774
775     void mediaCanStart(Document&) final;
776
777     void invalidateCachedTime() const;
778     void refreshCachedTime() const;
779
780     bool hasMediaControls() const;
781     bool createMediaControls();
782     void configureMediaControls();
783
784     void prepareMediaFragmentURI();
785     void applyMediaFragmentURI();
786
787     void changeNetworkStateFromLoadingToIdle();
788
789     void removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::BehaviorRestrictions mask = MediaElementSession::AllRestrictions);
790
791     void updateMediaController();
792     bool isBlocked() const;
793     bool isBlockedOnMediaController() const;
794     bool hasCurrentSrc() const override { return !m_currentSrc.isEmpty(); }
795     bool isLiveStream() const override { return movieLoadType() == MediaPlayerEnums::LiveStream; }
796
797     void updateSleepDisabling();
798     enum class SleepType {
799         None,
800         Display,
801         System,
802     };
803     SleepType shouldDisableSleep() const;
804
805 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
806     void didAddUserAgentShadowRoot(ShadowRoot*) override;
807     DOMWrapperWorld& ensureIsolatedWorld();
808     bool ensureMediaControlsInjectedScript();
809 #endif
810
811     PlatformMediaSession::MediaType mediaType() const override;
812     PlatformMediaSession::MediaType presentationType() const override;
813     PlatformMediaSession::DisplayType displayType() const override;
814     PlatformMediaSession::CharacteristicsFlags characteristics() const final;
815
816     void suspendPlayback() override;
817     void resumeAutoplaying() override;
818     void mayResumePlayback(bool shouldResume) override;
819     String mediaSessionTitle() const override;
820     double mediaSessionDuration() const override { return duration(); }
821     double mediaSessionCurrentTime() const override { return currentTime(); }
822     bool canReceiveRemoteControlCommands() const override { return true; }
823     void didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType, const PlatformMediaSession::RemoteCommandArgument*) override;
824     bool shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType) const override;
825     bool shouldOverrideBackgroundLoadingRestriction() const override;
826     bool canProduceAudio() const final;
827     bool processingUserGestureForMedia() const final;
828     bool isSuspended() const final;
829
830     void pageMutedStateDidChange() override;
831
832 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
833     void hardwareMutedStateDidChange(AudioSession*) final;
834 #endif
835
836     bool effectiveMuted() const;
837
838     void registerWithDocument(Document&);
839     void unregisterWithDocument(Document&);
840
841     void updateCaptionContainer();
842     void ensureMediaControlsShadowRoot();
843
844 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
845     void prepareForDocumentSuspension() final;
846     void resumeFromDocumentSuspension() final;
847
848     void updateMediaState(UpdateState updateState = UpdateState::Synchronously);
849     bool hasPlaybackTargetAvailabilityListeners() const { return m_hasPlaybackTargetAvailabilityListeners; }
850 #endif
851
852     bool isVideoTooSmallForInlinePlayback();
853     void updateShouldAutoplay();
854
855     void pauseAfterDetachedTask();
856     void updatePlaybackControlsManager();
857     void scheduleUpdatePlaybackControlsManager();
858     void playbackControlsManagerBehaviorRestrictionsTimerFired();
859
860     void updateRenderer();
861
862     void updatePageScaleFactorJSProperty();
863     void updateUsesLTRUserInterfaceLayoutDirectionJSProperty();
864     void setControllerJSProperty(const char*, JSC::JSValue);
865
866     void addBehaviorRestrictionsOnEndIfNecessary();
867     void handleSeekToPlaybackPosition(double);
868     void seekToPlaybackPositionEndedTimerFired();
869
870     WeakPtrFactory<HTMLMediaElement> m_weakFactory;
871     Timer m_pendingActionTimer;
872     Timer m_progressEventTimer;
873     Timer m_playbackProgressTimer;
874     Timer m_scanTimer;
875     Timer m_playbackControlsManagerBehaviorRestrictionsTimer;
876     Timer m_seekToPlaybackPositionEndedTimer;
877     GenericTaskQueue<Timer> m_seekTaskQueue;
878     GenericTaskQueue<Timer> m_shadowDOMTaskQueue;
879     GenericTaskQueue<Timer> m_promiseTaskQueue;
880     GenericTaskQueue<Timer> m_pauseAfterDetachedTaskQueue;
881     GenericTaskQueue<Timer> m_updatePlaybackControlsManagerQueue;
882     GenericTaskQueue<Timer> m_playbackControlsManagerBehaviorRestrictionsQueue;
883     GenericTaskQueue<Timer> m_resourceSelectionTaskQueue;
884     RefPtr<TimeRanges> m_playedTimeRanges;
885     GenericEventQueue m_asyncEventQueue;
886
887     Vector<DOMPromiseDeferred<void>> m_pendingPlayPromises;
888
889     double m_requestedPlaybackRate { 1 };
890     double m_reportedPlaybackRate { 1 };
891     double m_defaultPlaybackRate { 1 };
892     bool m_webkitPreservesPitch { true };
893     NetworkState m_networkState { NETWORK_EMPTY };
894     ReadyState m_readyState { HAVE_NOTHING };
895     ReadyState m_readyStateMaximum { HAVE_NOTHING };
896     URL m_currentSrc;
897
898     RefPtr<MediaError> m_error;
899
900     struct PendingSeek {
901         PendingSeek(const MediaTime& now, const MediaTime& targetTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance)
902             : now(now)
903             , targetTime(targetTime)
904             , negativeTolerance(negativeTolerance)
905             , positiveTolerance(positiveTolerance)
906         {
907         }
908         MediaTime now;
909         MediaTime targetTime;
910         MediaTime negativeTolerance;
911         MediaTime positiveTolerance;
912     };
913     std::unique_ptr<PendingSeek> m_pendingSeek;
914     SeekType m_pendingSeekType { NoSeek };
915
916     double m_volume { 1 };
917     bool m_volumeInitialized { false };
918     MediaTime m_lastSeekTime;
919     
920     double m_previousProgressTime { std::numeric_limits<double>::max() };
921     double m_playbackStartedTime { 0 };
922
923     // The last time a timeupdate event was sent (based on monotonic clock).
924     MonotonicTime m_clockTimeAtLastUpdateEvent;
925
926     // The last time a timeupdate event was sent in movie time.
927     MediaTime m_lastTimeUpdateEventMovieTime;
928     
929     // Loading state.
930     enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement };
931     LoadState m_loadState { WaitingForSource };
932     RefPtr<HTMLSourceElement> m_currentSourceNode;
933     RefPtr<Node> m_nextChildNodeToConsider;
934
935     VideoFullscreenMode m_videoFullscreenMode { VideoFullscreenModeNone };
936     bool m_preparedForInline;
937     std::function<void()> m_preparedForInlineCompletionHandler;
938
939     bool m_temporarilyAllowingInlinePlaybackAfterFullscreen { false };
940
941 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
942     RetainPtr<PlatformLayer> m_videoFullscreenLayer;
943     FloatRect m_videoFullscreenFrame;
944     MediaPlayerEnums::VideoGravity m_videoFullscreenGravity { MediaPlayer::VideoGravityResizeAspect };
945 #endif
946
947     RefPtr<MediaPlayer> m_player;
948
949     MediaPlayerEnums::Preload m_preload { MediaPlayer::Auto };
950
951     DisplayMode m_displayMode { Unknown };
952
953     // Counter incremented while processing a callback from the media player, so we can avoid
954     // calling the media engine recursively.
955     int m_processingMediaPlayerCallback { 0 };
956
957 #if ENABLE(MEDIA_SESSION)
958     String m_kind;
959     RefPtr<MediaSession> m_session;
960     bool m_shouldDuck { false };
961     uint64_t m_elementID;
962 #endif
963
964 #if ENABLE(MEDIA_SOURCE)
965     RefPtr<MediaSource> m_mediaSource;
966     unsigned m_droppedVideoFrames { 0 };
967 #endif
968
969     mutable MediaTime m_cachedTime;
970     mutable double m_clockTimeAtLastCachedTimeUpdate { 0 };
971     mutable double m_minimumClockTimeToUpdateCachedTime { 0 };
972
973     MediaTime m_fragmentStartTime;
974     MediaTime m_fragmentEndTime;
975
976     using PendingActionFlags = unsigned;
977     PendingActionFlags m_pendingActionFlags { 0 };
978
979     enum ActionAfterScanType { Nothing, Play, Pause };
980     ActionAfterScanType m_actionAfterScan { Nothing };
981
982     enum ScanType { Seek, Scan };
983     ScanType m_scanType { Scan };
984     ScanDirection m_scanDirection { Forward };
985
986     bool m_firstTimePlaying : 1;
987     bool m_playing : 1;
988     bool m_isWaitingUntilMediaCanStart : 1;
989     bool m_shouldDelayLoadEvent : 1;
990     bool m_haveFiredLoadedData : 1;
991     bool m_inActiveDocument : 1;
992     bool m_autoplaying : 1;
993     bool m_muted : 1;
994     bool m_explicitlyMuted : 1;
995     bool m_initiallyMuted : 1;
996     bool m_paused : 1;
997     bool m_seeking : 1;
998
999     // data has not been loaded since sending a "stalled" event
1000     bool m_sentStalledEvent : 1;
1001
1002     // time has not changed since sending an "ended" event
1003     bool m_sentEndEvent : 1;
1004
1005     bool m_pausedInternal : 1;
1006
1007     bool m_closedCaptionsVisible : 1;
1008     bool m_webkitLegacyClosedCaptionOverride : 1;
1009     bool m_completelyLoaded : 1;
1010     bool m_havePreparedToPlay : 1;
1011     bool m_parsingInProgress : 1;
1012     bool m_elementIsHidden : 1;
1013     bool m_creatingControls : 1;
1014     bool m_receivedLayoutSizeChanged : 1;
1015     bool m_hasEverNotifiedAboutPlaying : 1;
1016
1017     bool m_hasEverHadAudio : 1;
1018     bool m_hasEverHadVideo : 1;
1019
1020 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1021     bool m_mediaControlsDependOnPageScaleFactor : 1;
1022     bool m_haveSetUpCaptionContainer : 1;
1023 #endif
1024
1025     bool m_isScrubbingRemotely : 1;
1026
1027 #if ENABLE(VIDEO_TRACK)
1028     bool m_tracksAreReady : 1;
1029     bool m_haveVisibleTextTrack : 1;
1030     bool m_processingPreferenceChange : 1;
1031
1032     PlaybackWithoutUserGesture m_playbackWithoutUserGesture { PlaybackWithoutUserGesture::None };
1033     std::optional<MediaTime> m_playbackWithoutUserGestureStartedTime;
1034
1035     String m_subtitleTrackLanguage;
1036     MediaTime m_lastTextTrackUpdateTime { -1, 1 };
1037
1038     CaptionUserPreferences::CaptionDisplayMode m_captionDisplayMode { CaptionUserPreferences::Automatic };
1039
1040     RefPtr<AudioTrackList> m_audioTracks;
1041     RefPtr<TextTrackList> m_textTracks;
1042     RefPtr<VideoTrackList> m_videoTracks;
1043     Vector<RefPtr<TextTrack>> m_textTracksWhenResourceSelectionBegan;
1044
1045     CueIntervalTree m_cueTree;
1046
1047     CueList m_currentlyActiveCues;
1048     int m_ignoreTrackDisplayUpdate { 0 };
1049
1050     bool m_requireCaptionPreferencesChangedCallbacks { false };
1051 #endif
1052
1053 #if ENABLE(WEB_AUDIO)
1054     // This is a weak reference, since m_audioSourceNode holds a reference to us.
1055     // The value is set just after the MediaElementAudioSourceNode is created.
1056     // The value is cleared in MediaElementAudioSourceNode::~MediaElementAudioSourceNode().
1057     MediaElementAudioSourceNode* m_audioSourceNode { nullptr };
1058 #endif
1059
1060     String m_mediaGroup;
1061     friend class MediaController;
1062     RefPtr<MediaController> m_mediaController;
1063
1064     std::unique_ptr<SleepDisabler> m_sleepDisabler;
1065
1066     WeakPtr<const MediaResourceLoader> m_lastMediaResourceLoaderForTesting;
1067
1068     friend class TrackDisplayUpdateScope;
1069
1070     RefPtr<Blob> m_blob;
1071     MediaProvider m_mediaProvider;
1072
1073 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
1074     RefPtr<WebKitMediaKeys> m_webKitMediaKeys;
1075 #endif
1076
1077     std::unique_ptr<MediaElementSession> m_mediaSession;
1078     size_t m_reportedExtraMemoryCost { 0 };
1079
1080 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1081     friend class MediaControlsHost;
1082     RefPtr<MediaControlsHost> m_mediaControlsHost;
1083     RefPtr<DOMWrapperWorld> m_isolatedWorld;
1084 #endif
1085
1086 #if ENABLE(MEDIA_STREAM)
1087     RefPtr<MediaStream> m_mediaStreamSrcObject;
1088     bool m_settingMediaStreamSrcObject { false };
1089 #endif
1090
1091 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1092     MediaProducer::MediaStateFlags m_mediaState { MediaProducer::IsNotPlaying };
1093     bool m_hasPlaybackTargetAvailabilityListeners { false };
1094     bool m_failedToPlayToWirelessTarget { false };
1095     bool m_isPlayingToWirelessTarget { false };
1096 #endif
1097 };
1098
1099 #if ENABLE(VIDEO_TRACK) && !defined(NDEBUG)
1100
1101 // Template specialization required by PodIntervalTree in debug mode.
1102 template <> struct ValueToString<TextTrackCue*> {
1103     static String string(TextTrackCue* const& cue)
1104     {
1105         String text;
1106         if (cue->isRenderable())
1107             text = toVTTCue(cue)->text();
1108         return String::format("%p id=%s interval=%s-->%s cue=%s)", cue, cue->id().utf8().data(), toString(cue->startTime()).utf8().data(), toString(cue->endTime()).utf8().data(), text.utf8().data());
1109     }
1110 };
1111
1112 #endif
1113
1114 #ifndef NDEBUG
1115
1116 template<> struct ValueToString<MediaTime> {
1117     static String string(const MediaTime& time)
1118     {
1119         return toString(time);
1120     }
1121 };
1122
1123 #endif
1124
1125 } // namespace WebCore
1126
1127 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::HTMLMediaElement)
1128     static bool isType(const WebCore::Element& element) { return element.isMediaElement(); }
1129     static bool isType(const WebCore::Node& node) { return is<WebCore::Element>(node) && isType(downcast<WebCore::Element>(node)); }
1130 SPECIALIZE_TYPE_TRAITS_END()
1131
1132 #endif