/* * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HTMLMediaElement_h #define HTMLMediaElement_h #if ENABLE(VIDEO) #include "HTMLElement.h" #include "ActiveDOMObject.h" #include "MediaCanStartListener.h" #include "MediaPlayer.h" #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) #include "MediaPlayerProxy.h" #endif namespace WebCore { class Event; class HTMLSourceElement; class MediaControls; class MediaError; class KURL; class TimeRanges; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) class Widget; #endif // FIXME: The inheritance from MediaPlayerClient here should be private inheritance. // But it can't be until the Chromium WebMediaPlayerClientImpl class is fixed so it // no longer depends on typecasting a MediaPlayerClient to an HTMLMediaElement. class HTMLMediaElement : public HTMLElement, public MediaPlayerClient, private MediaCanStartListener, private ActiveDOMObject { public: MediaPlayer* player() const { return m_player.get(); } virtual bool isVideo() const = 0; virtual bool hasVideo() const { return false; } virtual bool hasAudio() const; void rewind(float timeDelta); void returnToRealtime(); // Eventually overloaded in HTMLVideoElement virtual bool supportsFullscreen() const { return false; }; virtual bool supportsSave() const; PlatformMedia platformMedia() const; #if USE(ACCELERATED_COMPOSITING) PlatformLayer* platformLayer() const; #endif void scheduleLoad(); MediaPlayer::MovieLoadType movieLoadType() const; bool inActiveDocument() const { return m_inActiveDocument; } // DOM API // error state PassRefPtr<MediaError> error() const; // network state void setSrc(const String&); String currentSrc() const; enum NetworkState { NETWORK_EMPTY, NETWORK_IDLE, NETWORK_LOADING, NETWORK_NO_SOURCE }; NetworkState networkState() const; String preload() const; void setPreload(const String&); PassRefPtr<TimeRanges> buffered() const; void load(bool isUserGesture, ExceptionCode&); String canPlayType(const String& mimeType) const; // ready state enum ReadyState { HAVE_NOTHING, HAVE_METADATA, HAVE_CURRENT_DATA, HAVE_FUTURE_DATA, HAVE_ENOUGH_DATA }; ReadyState readyState() const; bool seeking() const; // playback state float currentTime() const; void setCurrentTime(float, ExceptionCode&); float startTime() const; float duration() const; bool paused() const; float defaultPlaybackRate() const; void setDefaultPlaybackRate(float); float playbackRate() const; void setPlaybackRate(float); bool webkitPreservesPitch() const; void setWebkitPreservesPitch(bool); PassRefPtr<TimeRanges> played(); PassRefPtr<TimeRanges> seekable() const; bool ended() const; bool autoplay() const; void setAutoplay(bool b); bool loop() const; void setLoop(bool b); void play(bool isUserGesture); void pause(bool isUserGesture); // captions bool webkitHasClosedCaptions() const; bool webkitClosedCaptionsVisible() const; void setWebkitClosedCaptionsVisible(bool); #if ENABLE(MEDIA_STATISTICS) // Statistics unsigned webkitAudioDecodedByteCount() const; unsigned webkitVideoDecodedByteCount() const; #endif // controls bool controls() const; void setControls(bool); float volume() const; void setVolume(float, ExceptionCode&); bool muted() const; void setMuted(bool); void togglePlayState(); void beginScrubbing(); void endScrubbing(); bool canPlay() const; float percentLoaded() const; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) void allocateMediaPlayerIfNecessary(); void setNeedWidgetUpdate(bool needWidgetUpdate) { m_needWidgetUpdate = needWidgetUpdate; } void deliverNotification(MediaPlayerProxyNotificationType notification); void setMediaPlayerProxy(WebMediaPlayerProxy* proxy); void getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values); virtual void finishParsingChildren(); void createMediaPlayerProxy(); void updateWidget(PluginCreationOption); #endif bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); } bool isFullscreen() const; void enterFullscreen(); void exitFullscreen(); bool hasClosedCaptions() const; bool closedCaptionsVisible() const; void setClosedCaptionsVisible(bool); MediaControls* mediaControls(); bool processingUserGesture() const; void sourceWillBeRemoved(HTMLSourceElement*); void sourceWasAdded(HTMLSourceElement*); void privateBrowsingStateDidChange(); // Restrictions to change default behaviors. enum BehaviorRestrictionFlags { NoRestrictions = 0, RequireUserGestureForLoadRestriction = 1 << 0, RequireUserGestureForRateChangeRestriction = 1 << 1, RequireUserGestureForFullScreenRestriction = 1 << 2 }; typedef unsigned BehaviorRestrictions; bool requireUserGestureForLoad() const { return m_restrictions & RequireUserGestureForLoadRestriction; } bool requireUserGestureForRateChange() const { return m_restrictions & RequireUserGestureForRateChangeRestriction; } bool requireUserGestureForFullScreen() const { return m_restrictions & RequireUserGestureForFullScreenRestriction; } void setBehaviorRestrictions(BehaviorRestrictions restrictions) { m_restrictions = restrictions; } // Media cache management. static void getSitesInMediaCache(Vector<String>&); static void clearMediaCache(); static void clearMediaCacheForSite(const String&); protected: HTMLMediaElement(const QualifiedName&, Document*); virtual ~HTMLMediaElement(); virtual void parseMappedAttribute(Attribute*); virtual bool isURLAttribute(Attribute*) const; virtual void attach(); virtual void willMoveToNewOwnerDocument(); virtual void didMoveToNewOwnerDocument(); enum DisplayMode { Unknown, None, Poster, PosterWaitingForVideo, Video }; DisplayMode displayMode() const { return m_displayMode; } virtual void setDisplayMode(DisplayMode mode) { m_displayMode = mode; } private: virtual void attributeChanged(Attribute*, bool preserveDecls); virtual bool rendererIsNeeded(RenderStyle*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual void insertedIntoDocument(); virtual void removedFromDocument(); virtual void recalcStyle(StyleChange); virtual void defaultEventHandler(Event*); // ActiveDOMObject functions. virtual bool canSuspend() const; virtual void suspend(ReasonForSuspension); virtual void resume(); virtual void stop(); virtual bool hasPendingActivity() const; virtual void mediaVolumeDidChange(); virtual void updateDisplayState() { } void setReadyState(MediaPlayer::ReadyState); void setNetworkState(MediaPlayer::NetworkState); virtual Document* mediaPlayerOwningDocument(); virtual void mediaPlayerNetworkStateChanged(MediaPlayer*); virtual void mediaPlayerReadyStateChanged(MediaPlayer*); virtual void mediaPlayerTimeChanged(MediaPlayer*); virtual void mediaPlayerVolumeChanged(MediaPlayer*); virtual void mediaPlayerMuteChanged(MediaPlayer*); virtual void mediaPlayerDurationChanged(MediaPlayer*); virtual void mediaPlayerRateChanged(MediaPlayer*); virtual void mediaPlayerPlaybackStateChanged(MediaPlayer*); virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*); virtual void mediaPlayerRepaint(MediaPlayer*); virtual void mediaPlayerSizeChanged(MediaPlayer*); #if USE(ACCELERATED_COMPOSITING) virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*); virtual void mediaPlayerRenderingModeChanged(MediaPlayer*); #endif virtual void mediaPlayerEngineUpdated(MediaPlayer*); virtual void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*); void loadTimerFired(Timer<HTMLMediaElement>*); void asyncEventTimerFired(Timer<HTMLMediaElement>*); void progressEventTimerFired(Timer<HTMLMediaElement>*); void playbackProgressTimerFired(Timer<HTMLMediaElement>*); void startPlaybackProgressTimer(); void startProgressEventTimer(); void stopPeriodicTimers(); void seek(float time, ExceptionCode&); void finishSeek(); void checkIfSeekNeeded(); void addPlayedRange(float start, float end); void scheduleTimeupdateEvent(bool periodicEvent); void scheduleEvent(const AtomicString& eventName); // loading void selectMediaResource(); void loadResource(const KURL&, ContentType&); void scheduleNextSourceChild(); void loadNextSourceChild(); void userCancelledLoad(); bool havePotentialSourceChild(); void noneSupported(); void mediaEngineError(PassRefPtr<MediaError> err); void cancelPendingEventsAndCallbacks(); void waitForSourceChange(); enum InvalidSourceAction { DoNothing, Complain }; bool isSafeToLoadURL(const KURL&, InvalidSourceAction); KURL selectNextSourceChild(ContentType*, InvalidSourceAction); // These "internal" functions do not check user gesture restrictions. void loadInternal(); void playInternal(); void pauseInternal(); void prepareForLoad(); void allowVideoRendering(); bool processingMediaPlayerCallback() const { return m_processingMediaPlayerCallback > 0; } void beginProcessingMediaPlayerCallback() { ++m_processingMediaPlayerCallback; } void endProcessingMediaPlayerCallback() { ASSERT(m_processingMediaPlayerCallback); --m_processingMediaPlayerCallback; } void updateVolume(); void updatePlayState(); bool potentiallyPlaying() const; bool endedPlayback() const; bool stoppedDueToErrors() const; bool pausedForUserInteraction() const; bool couldPlayIfEnoughData() const; float minTimeSeekable() const; float maxTimeSeekable() const; // Pauses playback without changing any states or generating events void setPausedInternal(bool); virtual void mediaCanStart(); void setShouldDelayLoadEvent(bool); void invalidateCachedTime(); void refreshCachedTime() const; bool hasMediaControls(); bool createMediaControls(); virtual void* preDispatchEventHandler(Event*); Timer<HTMLMediaElement> m_loadTimer; Timer<HTMLMediaElement> m_asyncEventTimer; Timer<HTMLMediaElement> m_progressEventTimer; Timer<HTMLMediaElement> m_playbackProgressTimer; Vector<RefPtr<Event> > m_pendingEvents; RefPtr<TimeRanges> m_playedTimeRanges; float m_playbackRate; float m_defaultPlaybackRate; bool m_webkitPreservesPitch; NetworkState m_networkState; ReadyState m_readyState; ReadyState m_readyStateMaximum; String m_currentSrc; RefPtr<MediaError> m_error; float m_volume; float m_lastSeekTime; unsigned m_previousProgress; double m_previousProgressTime; // the last time a timeupdate event was sent (wall clock) double m_lastTimeUpdateEventWallTime; // the last time a timeupdate event was sent in movie time float m_lastTimeUpdateEventMovieTime; // loading state enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement }; LoadState m_loadState; HTMLSourceElement* m_currentSourceNode; Node* m_nextChildNodeToConsider; Node* sourceChildEndOfListValue() { return static_cast<Node*>(this); } OwnPtr<MediaPlayer> m_player; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) RefPtr<Widget> m_proxyWidget; #endif BehaviorRestrictions m_restrictions; MediaPlayer::Preload m_preload; DisplayMode m_displayMode; // Counter incremented while processing a callback from the media player, so we can avoid // calling the media engine recursively. int m_processingMediaPlayerCallback; mutable float m_cachedTime; mutable double m_cachedTimeWallClockUpdateTime; mutable double m_minimumWallClockTimeToCacheMediaTime; bool m_playing : 1; bool m_isWaitingUntilMediaCanStart : 1; bool m_shouldDelayLoadEvent : 1; bool m_haveFiredLoadedData : 1; bool m_inActiveDocument : 1; bool m_autoplaying : 1; bool m_muted : 1; bool m_paused : 1; bool m_seeking : 1; // data has not been loaded since sending a "stalled" event bool m_sentStalledEvent : 1; // time has not changed since sending an "ended" event bool m_sentEndEvent : 1; bool m_pausedInternal : 1; // Not all media engines provide enough information about a file to be able to // support progress events so setting m_sendProgressEvents disables them bool m_sendProgressEvents : 1; bool m_isFullscreen : 1; bool m_closedCaptionsVisible : 1; bool m_mouseOver : 1; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) bool m_needWidgetUpdate : 1; #endif bool m_dispatchingCanPlayEvent : 1; bool m_loadInitiatedByUserGesture : 1; bool m_completelyLoaded : 1; #if PLATFORM(ANDROID) double m_lastTouch; // When user gesture invoke load, play or pause, this turns to be true. // After this becomes true, we ignore the user gesture requirement for play // and pause. bool m_userGestureInitiated; #endif }; } //namespace #endif #endif