blob: bd8354717e6b003939c40abcc23b4a499f655c8e [file] [log] [blame]
/*
* Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2011, 2012 Google 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 MediaControlsImpl_h
#define MediaControlsImpl_h
#include "core/geometry/DOMRectReadOnly.h"
#include "core/html/HTMLDivElement.h"
#include "core/html/media/MediaControls.h"
#include "modules/ModulesExport.h"
#include "platform/Timer.h"
namespace blink {
class Event;
class HTMLVideoElement;
class MediaControlsMediaEventListener;
class MediaControlsOrientationLockDelegate;
class MediaControlsRotateToFullscreenDelegate;
class MediaControlsWindowEventListener;
class MediaControlButtonPanelElement;
class MediaControlCastButtonElement;
class MediaControlCurrentTimeDisplayElement;
class MediaControlDownloadButtonElement;
class MediaControlFullscreenButtonElement;
class MediaControlLoadingPanelElement;
class MediaControlMuteButtonElement;
class MediaControlOverflowMenuButtonElement;
class MediaControlOverflowMenuListElement;
class MediaControlOverlayEnclosureElement;
class MediaControlOverlayPlayButtonElement;
class MediaControlPanelElement;
class MediaControlPanelEnclosureElement;
class MediaControlPictureInPictureButtonElement;
class MediaControlPlayButtonElement;
class MediaControlRemainingTimeDisplayElement;
class MediaControlTextTrackListElement;
class MediaControlTimelineElement;
class MediaControlToggleClosedCaptionsButtonElement;
class MediaControlVolumeSliderElement;
class MediaDownloadInProductHelpManager;
class ShadowRoot;
class TextTrack;
// Default implementation of the core/ MediaControls interface used by
// HTMLMediaElement.
class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
public MediaControls {
USING_GARBAGE_COLLECTED_MIXIN(MediaControlsImpl);
WTF_MAKE_NONCOPYABLE(MediaControlsImpl);
public:
static MediaControlsImpl* Create(HTMLMediaElement&, ShadowRoot&);
~MediaControlsImpl() = default;
// Returns whether the ModernMediaControlsEnabled runtime flag is on.
static bool IsModern();
// Node override.
Node::InsertionNotificationRequest InsertedInto(ContainerNode*) override;
void RemovedFrom(ContainerNode*) override;
// MediaControls implementation.
void MaybeShow() override;
void Hide() override;
void Reset() override;
void OnControlsListUpdated() override;
// TODO(mlamouri): this is temporary to notify the controls that an
// HTMLTrackElement failed to load because there is no web exposed way to
// be notified on the TextTrack object. See https://crbug.com/669977
void OnTrackElementFailedToLoad() override { OnTextTracksAddedOrRemoved(); }
// Notify us that the media element's network state has changed.
void NetworkStateChanged() override;
LayoutObject* PanelLayoutObject() override;
LayoutObject* ContainerLayoutObject() override;
// Return the internal elements, which is used by registering clicking
// EventHandlers from MediaControlsWindowEventListener.
HTMLDivElement* PanelElement() override;
// TODO(mlamouri): this method is needed in order to notify the controls that
// the `MediaControlsEnabled` setting has changed.
void OnMediaControlsEnabledChange() override {
// There is no update because only the overlay is expected to change.
RefreshCastButtonVisibilityWithoutUpdate();
}
// Called by the fullscreen buttons to toggle fulllscreen on/off.
void EnterFullscreen();
void ExitFullscreen();
// Text track related methods exposed to components handling closed captions.
void ToggleTextTrackList();
void ShowTextTrackAtIndex(unsigned);
void DisableShowingTextTracks();
// Returns the label for the track when a valid track is passed in and "Off"
// when the parameter is null.
String GetTextTrackLabel(TextTrack*) const;
// Methods related to the overflow menu.
void ToggleOverflowMenu();
bool OverflowMenuVisible();
void ShowOverlayCastButtonIfNeeded();
// Methods call by the scrubber.
void BeginScrubbing();
void EndScrubbing();
void UpdateCurrentTimeDisplay();
// Methods used for Download In-product help.
const MediaControlDownloadButtonElement& DownloadButton() const;
void DidDismissDownloadInProductHelp();
MediaDownloadInProductHelpManager* DownloadInProductHelp();
void MaybeRecordOverflowTimeToAction();
virtual void Trace(blink::Visitor*);
// Track the state of the controls.
enum ControlsState {
// There is no video source.
kNoSource,
// Metadata has not been loaded.
kNotLoaded,
// Metadata is being loaded.
kLoadingMetadata,
// Metadata is loaded and the media is ready to play. This can be when the
// media is paused, when it has ended or before the media has started
// playing.
kStopped,
// The media is playing.
kPlaying,
// Playback has stopped to buffer.
kBuffering,
// The media is being scrubbed.
kScrubbing,
};
ControlsState State() const;
void MaybeToggleControlsFromTap();
private:
// MediaControlsMediaEventListener is a component that is listening to events
// and calling the appropriate callback on MediaControlsImpl. The object is
// split from MedaiControlsImpl to reduce boilerplate and ease reading. In
// order to not expose accessors only for this component, a friendship is
// declared.
friend class MediaControlsMediaEventListener;
// Same as above but handles the menus hiding when the window is interacted
// with, allowing MediaControlsImpl to not have the boilerplate.
friend class MediaControlsWindowEventListener;
// For tests.
friend class MediaControlsOrientationLockDelegateTest;
friend class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest;
friend class MediaControlsRotateToFullscreenDelegateTest;
friend class MediaControlsImplTest;
friend class MediaControlsImplInProductHelpTest;
friend class MediaControlTimelineElementTest;
// Need to be members of MediaControls for private member access.
class BatchedControlUpdate;
class MediaControlsResizeObserverDelegate;
class MediaElementMutationCallback;
void Invalidate(Element*);
// Notify us that our controls enclosure has changed size.
void NotifyElementSizeChanged(DOMRectReadOnly* new_size);
// Update the CSS class when we think the state has updated.
void UpdateCSSClassFromState();
// Get the HTMLVideoElement that the controls are attached to. The caller must
// check that the element is a video element first.
HTMLVideoElement& VideoElement();
explicit MediaControlsImpl(HTMLMediaElement&);
void InitializeControls();
void MakeOpaque();
void MakeOpaqueFromPointerEvent();
void MakeTransparent();
bool IsVisible() const;
void UpdatePlayState();
enum HideBehaviorFlags {
kIgnoreNone = 0,
kIgnoreVideoHover = 1 << 0,
kIgnoreFocus = 1 << 1,
kIgnoreControlsHover = 1 << 2,
kIgnoreWaitForTimer = 1 << 3,
};
bool ShouldHideMediaControls(unsigned behavior_flags = 0) const;
void HideMediaControlsTimerFired(TimerBase*);
void StartHideMediaControlsIfNecessary();
void StartHideMediaControlsTimer();
void StopHideMediaControlsTimer();
void ResetHideMediaControlsTimer();
void HideCursor();
void ShowCursor();
void ElementSizeChangedTimerFired(TimerBase*);
void HideAllMenus();
// Hide elements that don't fit, and show those things that we want which
// do fit. This requires that m_effectiveWidth and m_effectiveHeight are
// current.
void ComputeWhichControlsFit();
void UpdateOverflowMenuWanted() const;
void MaybeRecordElementsDisplayed() const;
// Takes a popup menu (caption, overflow) and position on the screen. This is
// used because these menus use a fixed position in order to appear over all
// content.
void PositionPopupMenu(Element*);
// Node
bool IsMediaControls() const override { return true; }
bool WillRespondToMouseMoveEvents() override { return true; }
void DefaultEventHandler(Event*) override;
bool ContainsRelatedTarget(Event*);
// Internal cast related methods.
void RemotePlaybackStateChanged();
void RefreshCastButtonVisibility();
void RefreshCastButtonVisibilityWithoutUpdate();
// Methods called by MediaControlsMediaEventListener.
void OnVolumeChange();
void OnFocusIn();
void OnTimeUpdate();
void OnDurationChange();
void OnPlay();
void OnPlaying();
void OnPause();
void OnTextTracksAddedOrRemoved();
void OnTextTracksChanged();
void OnError();
void OnLoadedMetadata();
void OnEnteredFullscreen();
void OnExitedFullscreen();
void OnPanelKeypress();
void OnMediaKeyboardEvent(Event* event) { DefaultEventHandler(event); }
void OnWaiting();
void OnLoadingProgress();
void OnLoadedData();
// Media control elements.
Member<MediaControlOverlayEnclosureElement> overlay_enclosure_;
Member<MediaControlOverlayPlayButtonElement> overlay_play_button_;
Member<MediaControlCastButtonElement> overlay_cast_button_;
Member<MediaControlPanelEnclosureElement> enclosure_;
Member<MediaControlPanelElement> panel_;
Member<MediaControlPlayButtonElement> play_button_;
Member<MediaControlTimelineElement> timeline_;
Member<MediaControlCurrentTimeDisplayElement> current_time_display_;
Member<MediaControlRemainingTimeDisplayElement> duration_display_;
Member<MediaControlMuteButtonElement> mute_button_;
Member<MediaControlVolumeSliderElement> volume_slider_;
Member<MediaControlToggleClosedCaptionsButtonElement>
toggle_closed_captions_button_;
Member<MediaControlTextTrackListElement> text_track_list_;
Member<MediaControlOverflowMenuButtonElement> overflow_menu_;
Member<MediaControlOverflowMenuListElement> overflow_list_;
Member<MediaControlButtonPanelElement> media_button_panel_;
Member<MediaControlLoadingPanelElement> loading_panel_;
Member<MediaControlPictureInPictureButtonElement> picture_in_picture_button_;
Member<MediaControlCastButtonElement> cast_button_;
Member<MediaControlFullscreenButtonElement> fullscreen_button_;
Member<MediaControlDownloadButtonElement> download_button_;
Member<MediaControlsMediaEventListener> media_event_listener_;
Member<MediaControlsWindowEventListener> window_event_listener_;
Member<MediaControlsOrientationLockDelegate> orientation_lock_delegate_;
Member<MediaControlsRotateToFullscreenDelegate>
rotate_to_fullscreen_delegate_;
TaskRunnerTimer<MediaControlsImpl> hide_media_controls_timer_;
unsigned hide_timer_behavior_flags_;
bool is_mouse_over_controls_ : 1;
bool is_paused_for_scrubbing_ : 1;
bool is_scrubbing_ = false;
// Watches the video element for resize and updates media controls as
// necessary.
Member<ResizeObserver> resize_observer_;
// Watches the media element for attribute changes and updates media controls
// as necessary.
Member<MediaElementMutationCallback> element_mutation_callback_;
TaskRunnerTimer<MediaControlsImpl> element_size_changed_timer_;
IntSize size_;
bool keep_showing_until_timer_fires_ : 1;
bool pointer_event_did_show_controls_ = false;
Member<MediaDownloadInProductHelpManager> download_iph_manager_;
};
DEFINE_ELEMENT_TYPE_CASTS(MediaControlsImpl, IsMediaControls());
} // namespace blink
#endif