Esempio n. 1
0
void TextTrack::setLanguage(const AtomicString& language)
{
    // 11.1 language, on setting:
    // 1. If the value being assigned to this attribute is not an empty string or a BCP 47 language
    // tag[BCP47], then abort these steps.
    // FIXME(123926): Validate the BCP47-ness of langague.

    // 2. Update this attribute to the new value.
    TrackBase::setLanguage(language);

    // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
    // event named change at sourceBuffer.textTracks.
    if (m_sourceBuffer)
        m_sourceBuffer->textTracks()->scheduleChangeEvent();

    // 4. Queue a task to fire a simple event named change at the TextTrackList object referenced by
    // the textTracks attribute on the HTMLMediaElement.
    if (mediaElement())
        mediaElement()->textTracks()->scheduleChangeEvent();
}
Esempio n. 2
0
void MediaControls::playbackStarted()
{
    m_currentTimeDisplay->show();
    m_durationDisplay->hide();

    updatePlayState();
    m_timeline->setPosition(mediaElement().currentTime());
    updateCurrentTimeDisplay();

    startHideMediaControlsTimer();
}
Esempio n. 3
0
bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const
{
    // Never hide for a media element without visual representation.
    if (!mediaElement().hasVideo() || mediaElement().isPlayingRemotely())
        return false;
    // Don't hide if the mouse is over the controls.
    const bool ignoreControlsHover = behaviorFlags & IgnoreControlsHover;
    if (!ignoreControlsHover && m_panel->hovered())
        return false;
    // Don't hide if the mouse is over the video area.
    const bool ignoreVideoHover = behaviorFlags & IgnoreVideoHover;
    if (!ignoreVideoHover && m_isMouseOverControls)
        return false;
    // Don't hide if focus is on the HTMLMediaElement or within the
    // controls/shadow tree. (Perform the checks separately to avoid going
    // through all the potential ancestor hosts for the focused element.)
    const bool ignoreFocus = behaviorFlags & IgnoreFocus;
    if (!ignoreFocus && (mediaElement().focused() || contains(document().focusedElement())))
        return false;
    return true;
}
Esempio n. 4
0
void MediaControls::refreshCastButtonVisibilityWithoutUpdate() {
  if (!shouldShowCastButton(mediaElement())) {
    m_castButton->setIsWanted(false);
    m_overlayCastButton->setIsWanted(false);
    return;
  }

  // The reason for the autoplay test is that some pages (e.g. vimeo.com) have
  // an autoplay background video, which doesn't autoplay on Chrome for Android
  // (we prevent it) so starts paused. In such cases we don't want to
  // automatically show the cast button, since it looks strange and is unlikely
  // to correspond with anything the user wants to do.  If a user does want to
  // cast a paused autoplay video then they can still do so by touching or
  // clicking on the video, which will cause the cast button to appear.
  if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() &&
      mediaElement().paused()) {
    // Note that this is a case where we add the overlay cast button
    // without wanting the panel cast button.  We depend on the fact
    // that computeWhichControlsFit() won't change overlay cast button
    // visibility in the case where the cast button isn't wanted.
    // We don't call compute...() here, but it will be called as
    // non-cast changes (e.g., resize) occur.  If the panel button
    // is shown, however, compute...() will take control of the
    // overlay cast button if it needs to hide it from the panel.
    m_overlayCastButton->tryShowOverlay();
    m_castButton->setIsWanted(false);
  } else if (mediaElement().shouldShowControls()) {
    m_overlayCastButton->setIsWanted(false);
    m_castButton->setIsWanted(true);
    // Check that the cast button actually fits on the bar.  For the
    // newMediaPlaybackUiEnabled case, we let computeWhichControlsFit()
    // handle this.
    if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() &&
        m_fullscreenButton->getBoundingClientRect()->right() >
            m_panel->getBoundingClientRect()->right()) {
      m_castButton->setIsWanted(false);
      m_overlayCastButton->tryShowOverlay();
    }
  }
}
Esempio n. 5
0
void MediaControls::updateVolume()
{
    m_muteButton->updateDisplayType();
    // Invalidate the mute button because it paints differently according to volume.
    if (LayoutObject* layoutObject = m_muteButton->layoutObject())
        layoutObject->setShouldDoFullPaintInvalidation();

    if (mediaElement().muted())
        m_volumeSlider->setVolume(0);
    else
        m_volumeSlider->setVolume(mediaElement().volume());

    // Update the visibility of our audio elements.
    // We never want the volume slider if there's no audio.
    // If there is audio, then we want it unless hiding audio is enabled and
    // we prefer to hide it.
    BatchedControlUpdate batch(this);
    m_volumeSlider->setIsWanted(mediaElement().hasAudio()
        && !(m_allowHiddenVolumeControls && preferHiddenVolumeControls(document())));

    // The mute button is a little more complicated.  If enableNewMediaPlaybackUi
    // is true, then we choose to hide or show the mute button to save space.
    // If enableNew* is not set, then we never touch the mute button, and
    // instead leave it to the CSS.
    // Note that this is why m_allowHiddenVolumeControls isn't rolled into prefer...().
    if (m_allowHiddenVolumeControls) {
        // If there is no audio track, then hide the mute button.  If there
        // is an audio track, then we always show the mute button unless
        // we prefer to hide it and the media isn't muted.  If it's muted,
        // then we show it to let the user unmute it.  In this case, we don't
        // want to re-hide the mute button later.
        m_keepMuteButton |= mediaElement().muted();
        m_muteButton->setIsWanted(mediaElement().hasAudio()
            && (!preferHiddenVolumeControls(document()) || m_keepMuteButton));
    }

    // Invalidate the volume slider because it paints differently according to volume.
    if (LayoutObject* layoutObject = m_volumeSlider->layoutObject())
        layoutObject->setShouldDoFullPaintInvalidation();
}
// MediaPlayer -------------------------------------------------
void WebMediaPlayerClientImpl::load(WebMediaPlayer::LoadType loadType, const WTF::String& url, WebMediaPlayer::CORSMode corsMode)
{
    ASSERT(!m_webMediaPlayer);

    // FIXME: Remove this cast
    LocalFrame* frame = mediaElement().document().frame();

    WebURL poster = m_client->mediaPlayerPosterURL();

    KURL kurl(ParsedURLString, url);
    m_webMediaPlayer = createWebMediaPlayer(this, kurl, frame, HTMLMediaElementEncryptedMedia::contentDecryptionModule(mediaElement()));
    if (!m_webMediaPlayer)
        return;

    if (mediaElement().layoutObject())
        mediaElement().layoutObject()->setShouldDoFullPaintInvalidation();

#if ENABLE(WEB_AUDIO)
    // Make sure if we create/re-create the WebMediaPlayer that we update our wrapper.
    m_audioSourceProvider.wrap(m_webMediaPlayer->audioSourceProvider());
#endif

    m_webMediaPlayer->setVolume(mediaElement().effectiveMediaVolume());

    m_webMediaPlayer->setPoster(poster);

    setPreload(mediaElement().effectivePreloadType());

    m_webMediaPlayer->load(loadType, kurl, corsMode);

    if (mediaElement().isFullscreen())
        m_webMediaPlayer->enterFullscreen();
}
Esempio n. 7
0
void MediaControls::hideMediaControlsTimerFired(Timer<MediaControls>*)
{
    unsigned behaviorFlags = m_hideTimerBehaviorFlags | IgnoreFocus | IgnoreVideoHover;
    m_hideTimerBehaviorFlags = IgnoreNone;

    if (mediaElement().togglePlayStateWillPlay())
        return;

    if (!shouldHideMediaControls(behaviorFlags))
        return;

    makeTransparent();
}
void InbandGenericTextTrack::updateCueFromCueData(TextTrackCueGeneric* cue, GenericCueData* cueData)
{
    cue->willChange();

    cue->setStartTime(cueData->startTime(), IGNORE_EXCEPTION);
    double endTime = cueData->endTime();
    if (std::isinf(endTime) && mediaElement())
        endTime = mediaElement()->duration();
    cue->setEndTime(endTime, IGNORE_EXCEPTION);
    cue->setText(cueData->content());
    cue->setId(cueData->id());
    cue->setBaseFontSizeRelativeToVideoHeight(cueData->baseFontSize());
    cue->setFontSizeMultiplier(cueData->relativeFontSize());
    cue->setFontName(cueData->fontName());

    if (cueData->position() > 0)
        cue->setPosition(lround(cueData->position()), IGNORE_EXCEPTION);
    if (cueData->line() > 0)
        cue->setLine(lround(cueData->line()), IGNORE_EXCEPTION);
    if (cueData->size() > 0)
        cue->setSize(lround(cueData->size()), IGNORE_EXCEPTION);
    if (cueData->backgroundColor().isValid())
        cue->setBackgroundColor(cueData->backgroundColor().rgb());
    if (cueData->foregroundColor().isValid())
        cue->setForegroundColor(cueData->foregroundColor().rgb());
    if (cueData->highlightColor().isValid())
        cue->setHighlightColor(cueData->highlightColor().rgb());

    if (cueData->align() == GenericCueData::Start)
        cue->setAlign(ASCIILiteral("start"), IGNORE_EXCEPTION);
    else if (cueData->align() == GenericCueData::Middle)
        cue->setAlign(ASCIILiteral("middle"), IGNORE_EXCEPTION);
    else if (cueData->align() == GenericCueData::End)
        cue->setAlign(ASCIILiteral("end"), IGNORE_EXCEPTION);
    cue->setSnapToLines(false);

    cue->didChange();
}
Esempio n. 9
0
void MediaControls::reset() {
  EventDispatchForbiddenScope::AllowUserAgentEvents allowEventsInShadow;
  BatchedControlUpdate batch(this);

  const double duration = mediaElement().duration();
  m_durationDisplay->setTextContent(
      LayoutTheme::theme().formatMediaControlsTime(duration));
  m_durationDisplay->setCurrentValue(duration);

  // Show everything that we might hide.
  // If we don't have a duration, then mark it to be hidden.  For the
  // old UI case, want / don't want is the same as show / hide since
  // it is never marked as not fitting.
  m_durationDisplay->setIsWanted(std::isfinite(duration));
  m_currentTimeDisplay->setIsWanted(true);
  m_timeline->setIsWanted(true);

  // If the player has entered an error state, force it into the paused state.
  if (mediaElement().error())
    mediaElement().pause();

  updatePlayState();

  updateCurrentTimeDisplay();

  m_timeline->setDuration(duration);
  m_timeline->setPosition(mediaElement().currentTime());

  onVolumeChange();
  onTextTracksAddedOrRemoved();

  m_fullscreenButton->setIsWanted(shouldShowFullscreenButton(mediaElement()));

  refreshCastButtonVisibilityWithoutUpdate();

  m_downloadButton->setIsWanted(
      m_downloadButton->shouldDisplayDownloadButton());
}
void MediaControls::hideMediaControlsTimerFired(Timer<MediaControls>*)
{
    unsigned behaviorFlags = m_hideTimerBehaviorFlags | IgnoreFocus | IgnoreVideoHover;
    m_hideTimerBehaviorFlags = IgnoreNone;

    if (mediaElement().paused())
        return;

    if (!shouldHideMediaControls(behaviorFlags))
        return;

    makeTransparent();
    m_overlayCastButton->setIsWanted(false);
}
Esempio n. 11
0
void TextTrack::setMode(const AtomicString& mode)
{
    ASSERT(mode == disabledKeyword() || mode == hiddenKeyword() || mode == showingKeyword());

    // On setting, if the new value isn't equal to what the attribute would currently
    // return, the new value must be processed as follows ...
    if (m_mode == mode)
        return;

    // If mode changes to disabled, remove this track's cues from the client
    // because they will no longer be accessible from the cues() function.
    if (mode == disabledKeyword() && mediaElement() && m_cues)
        mediaElement()->textTrackRemoveCues(this, m_cues.get());

    if (mode != showingKeyword() && m_cues)
        for (size_t i = 0; i < m_cues->length(); ++i)
            m_cues->item(i)->removeDisplayTree();

    m_mode = mode;

    if (mediaElement())
        mediaElement()->textTrackModeChanged(this);
}
Esempio n. 12
0
void MediaControls::playbackStarted() {
  BatchedControlUpdate batch(this);

  if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
    m_currentTimeDisplay->setIsWanted(true);
    m_durationDisplay->setIsWanted(false);
  }

  updatePlayState();
  m_timeline->setPosition(mediaElement().currentTime());
  updateCurrentTimeDisplay();

  startHideMediaControlsTimer();
}
Esempio n. 13
0
bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const {
  // Never hide for a media element without visual representation.
  if (!mediaElement().isHTMLVideoElement() || !mediaElement().hasVideo() ||
      mediaElement().isPlayingRemotely()) {
    return false;
  }

  // Keep the controls visible as long as the timer is running.
  const bool ignoreWaitForTimer = behaviorFlags & IgnoreWaitForTimer;
  if (!ignoreWaitForTimer && m_keepShowingUntilTimerFires)
    return false;

  // Don't hide if the mouse is over the controls.
  const bool ignoreControlsHover = behaviorFlags & IgnoreControlsHover;
  if (!ignoreControlsHover && m_panel->isHovered())
    return false;

  // Don't hide if the mouse is over the video area.
  const bool ignoreVideoHover = behaviorFlags & IgnoreVideoHover;
  if (!ignoreVideoHover && m_isMouseOverControls)
    return false;

  // Don't hide if focus is on the HTMLMediaElement or within the
  // controls/shadow tree. (Perform the checks separately to avoid going
  // through all the potential ancestor hosts for the focused element.)
  const bool ignoreFocus = behaviorFlags & IgnoreFocus;
  if (!ignoreFocus &&
      (mediaElement().isFocused() || contains(document().focusedElement()))) {
    return false;
  }

  // Don't hide the media controls when a panel is showing.
  if (m_textTrackList->isWanted() || m_overflowList->isWanted())
    return false;

  return true;
}
void MediaControls::hideMediaControlsTimerFired(Timer<MediaControls>*)
{
    if (mediaElement().togglePlayStateWillPlay())
        return;

    unsigned behaviorFlags = IgnoreFocus | IgnoreVideoHover;
    // FIXME: improve this check, see http://www.crbug.com/401177.
    if (!deviceSupportsMouse(document())) {
        behaviorFlags |= IgnoreControlsHover;
    }
    if (!shouldHideMediaControls(behaviorFlags))
        return;

    makeTransparent();
}
Esempio n. 15
0
void MediaControls::refreshCastButtonVisibility()
{
    if (mediaElement().hasRemoteRoutes()) {
        // The reason for the autoplay test is that some pages (e.g. vimeo.com) have an autoplay background video, which
        // doesn't autoplay on Chrome for Android (we prevent it) so starts paused. In such cases we don't want to automatically
        // show the cast button, since it looks strange and is unlikely to correspond with anything the user wants to do.
        // If a user does want to cast a paused autoplay video then they can still do so by touching or clicking on the
        // video, which will cause the cast button to appear.
        if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() && mediaElement().paused()) {
            showOverlayCastButton();
        } else if (mediaElement().shouldShowControls()) {
            m_overlayCastButton->hide();
            m_castButton->show();
            // Check that the cast button actually fits on the bar.
            if (m_fullScreenButton->getBoundingClientRect()->right() > m_panel->getBoundingClientRect()->right()) {
                m_castButton->hide();
                tryShowOverlayCastButton();
            }
        }
    } else {
        m_castButton->hide();
        m_overlayCastButton->hide();
    }
}
void MediaControls::reset()
{
    const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled();
    BatchedControlUpdate batch(this);

    m_allowHiddenVolumeControls = useNewUi;

    const double duration = mediaElement().duration();
    m_durationDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsTime(duration), ASSERT_NO_EXCEPTION);
    m_durationDisplay->setCurrentValue(duration);

    if (useNewUi) {
        // Show everything that we might hide.
        // If we don't have a duration, then mark it to be hidden.  For the
        // old UI case, want / don't want is the same as show / hide since
        // it is never marked as not fitting.
        m_durationDisplay->setIsWanted(std::isfinite(duration));
        m_currentTimeDisplay->setIsWanted(true);
        m_timeline->setIsWanted(true);
    }

    updatePlayState();

    updateCurrentTimeDisplay();

    m_timeline->setDuration(duration);
    m_timeline->setPosition(mediaElement().currentTime());

    updateVolume();

    refreshClosedCaptionsButtonVisibility();

    m_fullScreenButton->setIsWanted(shouldShowFullscreenButton(mediaElement()));

    refreshCastButtonVisibilityWithoutUpdate();
}
Esempio n. 17
0
bool HTMLTrackElement::canLoadUrl(const KURL& url)
{
    HTMLMediaElement* parent = mediaElement();
    if (!parent)
        return false;

    if (url.isEmpty())
        return false;

    if (!document().contentSecurityPolicy()->allowMediaFromSource(url)) {
        WTF_LOG(Media, "HTMLTrackElement::canLoadUrl(%s) -> rejected by Content Security Policy", urlForLoggingTrack(url).utf8().data());
        return false;
    }

    return true;
}
Esempio n. 18
0
bool HTMLTrackElement::canLoadUrl(const KURL& url) {
  HTMLMediaElement* parent = mediaElement();
  if (!parent)
    return false;

  if (url.isEmpty())
    return false;

  if (!document().contentSecurityPolicy()->allowMediaFromSource(url)) {
    DVLOG(TRACK_LOG_LEVEL) << "canLoadUrl(" << urlForLoggingTrack(url)
                           << ") -> rejected by Content Security Policy";
    return false;
  }

  return true;
}
Esempio n. 19
0
void MediaControls::defaultEventHandler(Event* event)
{
    HTMLDivElement::defaultEventHandler(event);

    // Add IgnoreControlsHover to m_hideTimerBehaviorFlags when we see a touch event,
    // to allow the hide-timer to do the right thing when it fires.
    // FIXME: Preferably we would only do this when we're actually handling the event
    // here ourselves.
    bool wasLastEventTouch = event->isTouchEvent() || event->isGestureEvent()
        || (event->isMouseEvent() && toMouseEvent(event)->fromTouch());
    m_hideTimerBehaviorFlags |= wasLastEventTouch ? IgnoreControlsHover : IgnoreNone;

    if (event->type() == EventTypeNames::mouseover) {
        if (!containsRelatedTarget(event)) {
            m_isMouseOverControls = true;
            if (!mediaElement().togglePlayStateWillPlay()) {
                makeOpaque();
                if (shouldHideMediaControls())
                    startHideMediaControlsTimer();
            }
        }
        return;
    }

    if (event->type() == EventTypeNames::mouseout) {
        if (!containsRelatedTarget(event)) {
            m_isMouseOverControls = false;
            stopHideMediaControlsTimer();
        }
        return;
    }

    if (event->type() == EventTypeNames::mousemove) {
        // When we get a mouse move, show the media controls, and start a timer
        // that will hide the media controls after a 3 seconds without a mouse move.
        makeOpaque();
        refreshCastButtonVisibility();
        if (shouldHideMediaControls(IgnoreVideoHover))
            startHideMediaControlsTimer();
        return;
    }
}
void HTMLTrackElement::scheduleLoad()
{
    WTF_LOG(Media, "HTMLTrackElement::scheduleLoad");

    // 1. If another occurrence of this algorithm is already running for this text track and its track element,
    // abort these steps, letting that other algorithm take care of this element.
    if (m_loadTimer.isActive())
        return;

    // 2. If the text track's text track mode is not set to one of hidden or showing, abort these steps.
    if (ensureTrack()->mode() != TextTrack::hiddenKeyword() && ensureTrack()->mode() != TextTrack::showingKeyword())
        return;

    // 3. If the text track's track element does not have a media element as a parent, abort these steps.
    if (!mediaElement())
        return;

    // 4. Run the remainder of these steps asynchronously, allowing whatever caused these steps to run to continue.
    m_loadTimer.startOneShot(0, FROM_HERE);
}
bool HTMLTrackElement::canLoadUrl(const KURL& url)
{
    HTMLMediaElement* parent = mediaElement();
    if (!parent)
        return false;

    // 4.8.10.12.3 Sourcing out-of-band text tracks

    // 4. Download: If URL is not the empty string, perform a potentially CORS-enabled fetch of URL, with the
    // mode being the state of the media element's crossorigin content attribute, the origin being the
    // origin of the media element's Document, and the default origin behaviour set to fail.
    if (url.isEmpty())
        return false;

    if (!document().contentSecurityPolicy()->allowMediaFromSource(url)) {
        WTF_LOG(Media, "HTMLTrackElement::canLoadUrl(%s) -> rejected by Content Security Policy", urlForLoggingTrack(url).utf8().data());
        return false;
    }

    return true;
}
Esempio n. 22
0
LayoutSize RenderVideo::calculateIntrinsicSize()
{
    HTMLVideoElement* video = videoElement();
    
    // Spec text from 4.8.6
    //
    // The intrinsic width of a video element's playback area is the intrinsic width 
    // of the video resource, if that is available; otherwise it is the intrinsic 
    // width of the poster frame, if that is available; otherwise it is 300 CSS pixels.
    //
    // The intrinsic height of a video element's playback area is the intrinsic height 
    // of the video resource, if that is available; otherwise it is the intrinsic 
    // height of the poster frame, if that is available; otherwise it is 150 CSS pixels.
    MediaPlayer* player = mediaElement()->player();
    if (player && video->readyState() >= HTMLVideoElement::HAVE_METADATA) {
        LayoutSize size = player->naturalSize();
        if (!size.isEmpty())
            return size;
    }

    if (video->shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred())
        return m_cachedImageSize;

    // When the natural size of the video is unavailable, we use the provided
    // width and height attributes of the video element as the intrinsic size until
    // better values become available. 
    if (video->hasAttribute(widthAttr) && video->hasAttribute(heightAttr))
        return LayoutSize(video->width(), video->height());

    // <video> in standalone media documents should not use the default 300x150
    // size since they also have audio-only files. By setting the intrinsic
    // size to 300x1 the video will resize itself in these cases, and audio will
    // have the correct height (it needs to be > 0 for controls to render properly).
    if (video->ownerDocument() && video->ownerDocument()->isMediaDocument())
        return LayoutSize(defaultSize().width(), 1);

    return defaultSize();
}
Esempio n. 23
0
void HTMLTrackElement::scheduleLoad()
{
    WTF_LOG(Media, "HTMLTrackElement::scheduleLoad");

    // 1. If another occurrence of this algorithm is already running for this text track and its track element,
    // abort these steps, letting that other algorithm take care of this element.
    if (m_loadTimer.isActive())
        return;

    // 2. If the text track's text track mode is not set to one of hidden or showing, abort these steps.
    if (ensureTrack()->mode() != TextTrack::hiddenKeyword() && ensureTrack()->mode() != TextTrack::showingKeyword())
        return;

    // 3. If the text track's track element does not have a media element as a parent, abort these steps.
    if (!mediaElement())
        return;

    // 4. Run the remainder of these steps in parallel, allowing whatever caused these steps to run to continue.
    m_loadTimer.startOneShot(0, BLINK_FROM_HERE);

    // 5. Top: Await a stable state. The synchronous section consists of the following steps. (The steps in the
    // synchronous section are marked with [X])
    // FIXME: We use a timer to approximate a "stable state" - i.e. this is not 100% per spec.
}
Esempio n. 24
0
void LayoutMedia::layout() {
  LayoutSize oldSize = contentBoxRect().size();

  LayoutImage::layout();

  LayoutRect newRect = contentBoxRect();

  LayoutState state(*this);

  Optional<LayoutUnit> newPanelWidth;

// Iterate the children in reverse order so that the media controls are laid
// out before the text track container. This is to ensure that the text
// track rendering has an up-to-date position of the media controls for
// overlap checking, see LayoutVTTCue.
#if ENABLE(ASSERT)
  bool seenTextTrackContainer = false;
#endif
  for (LayoutObject* child = m_children.lastChild(); child;
       child = child->previousSibling()) {
#if ENABLE(ASSERT)
    if (child->node()->isMediaControls())
      ASSERT(!seenTextTrackContainer);
    else if (child->node()->isTextTrackContainer())
      seenTextTrackContainer = true;
    else
      ASSERT_NOT_REACHED();
#endif

    // TODO(mlamouri): we miss some layouts because needsLayout returns false in
    // some cases where we want to change the width of the controls because the
    // visible viewport has changed for example.
    if (newRect.size() == oldSize && !child->needsLayout())
      continue;

    LayoutUnit width = newRect.width();
    if (child->node()->isMediaControls()) {
      width = computePanelWidth(newRect);
      if (width != oldSize.width())
        newPanelWidth = width;
    }

    LayoutBox* layoutBox = toLayoutBox(child);
    layoutBox->setLocation(newRect.location());
    // TODO(foolip): Remove the mutableStyleRef() and depend on CSS
    // width/height: inherit to match the media element size.
    layoutBox->mutableStyleRef().setHeight(Length(newRect.height(), Fixed));
    layoutBox->mutableStyleRef().setWidth(Length(width, Fixed));

    layoutBox->forceLayout();
  }

  clearNeedsLayout();

  // Notify our MediaControls that a layout has happened.
  if (mediaElement() && mediaElement()->mediaControls() &&
      newPanelWidth.has_value()) {
    mediaElement()->mediaControls()->notifyPanelWidthChanged(
        newPanelWidth.value());
  }
}
Esempio n. 25
0
void LayoutMedia::notifyPositionMayHaveChanged(const IntRect& visibleRect) {
  // Tell our element about it.
  if (HTMLMediaElement* element = mediaElement())
    element->notifyPositionMayHaveChanged(visibleRect);
}
Esempio n. 26
0
void MediaSource::removeSourceBuffer(SourceBuffer& buffer, ExceptionCode& ec)
{
    LOG(MediaSource, "MediaSource::removeSourceBuffer() %p", this);
    Ref<SourceBuffer> protect(buffer);

    // 2. If sourceBuffer specifies an object that is not in sourceBuffers then
    // throw a NOT_FOUND_ERR exception and abort these steps.
    if (!m_sourceBuffers->length() || !m_sourceBuffers->contains(buffer)) {
        ec = NOT_FOUND_ERR;
        return;
    }

    // 3. If the sourceBuffer.updating attribute equals true, then run the following steps: ...
    buffer.abortIfUpdating();

    // 4. Let SourceBuffer audioTracks list equal the AudioTrackList object returned by sourceBuffer.audioTracks.
    RefPtr<AudioTrackList> audioTracks = buffer.audioTracks();

    // 5. If the SourceBuffer audioTracks list is not empty, then run the following steps:
    if (audioTracks->length()) {
        // 5.1 Let HTMLMediaElement audioTracks list equal the AudioTrackList object returned by the audioTracks
        // attribute on the HTMLMediaElement.
        // 5.2 Let the removed enabled audio track flag equal false.
        bool removedEnabledAudioTrack = false;

        // 5.3 For each AudioTrack object in the SourceBuffer audioTracks list, run the following steps:
        while (audioTracks->length()) {
            auto& track = *audioTracks->lastItem();

            // 5.3.1 Set the sourceBuffer attribute on the AudioTrack object to null.
            track.setSourceBuffer(nullptr);

            // 5.3.2 If the enabled attribute on the AudioTrack object is true, then set the removed enabled
            // audio track flag to true.
            if (track.enabled())
                removedEnabledAudioTrack = true;

            // 5.3.3 Remove the AudioTrack object from the HTMLMediaElement audioTracks list.
            // 5.3.4 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
            // cancelable, and that uses the TrackEvent interface, at the HTMLMediaElement audioTracks list.
            if (mediaElement())
                mediaElement()->removeAudioTrack(track);

            // 5.3.5 Remove the AudioTrack object from the SourceBuffer audioTracks list.
            // 5.3.6 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
            // cancelable, and that uses the TrackEvent interface, at the SourceBuffer audioTracks list.
            audioTracks->remove(track);
        }

        // 5.4 If the removed enabled audio track flag equals true, then queue a task to fire a simple event
        // named change at the HTMLMediaElement audioTracks list.
        if (removedEnabledAudioTrack)
            mediaElement()->audioTracks().scheduleChangeEvent();
    }

    // 6. Let SourceBuffer videoTracks list equal the VideoTrackList object returned by sourceBuffer.videoTracks.
    RefPtr<VideoTrackList> videoTracks = buffer.videoTracks();

    // 7. If the SourceBuffer videoTracks list is not empty, then run the following steps:
    if (videoTracks->length()) {
        // 7.1 Let HTMLMediaElement videoTracks list equal the VideoTrackList object returned by the videoTracks
        // attribute on the HTMLMediaElement.
        // 7.2 Let the removed selected video track flag equal false.
        bool removedSelectedVideoTrack = false;

        // 7.3 For each VideoTrack object in the SourceBuffer videoTracks list, run the following steps:
        while (videoTracks->length()) {
            auto& track = *videoTracks->lastItem();

            // 7.3.1 Set the sourceBuffer attribute on the VideoTrack object to null.
            track.setSourceBuffer(nullptr);

            // 7.3.2 If the selected attribute on the VideoTrack object is true, then set the removed selected
            // video track flag to true.
            if (track.selected())
                removedSelectedVideoTrack = true;

            // 7.3.3 Remove the VideoTrack object from the HTMLMediaElement videoTracks list.
            // 7.3.4 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
            // cancelable, and that uses the TrackEvent interface, at the HTMLMediaElement videoTracks list.
            if (mediaElement())
                mediaElement()->removeVideoTrack(track);

            // 7.3.5 Remove the VideoTrack object from the SourceBuffer videoTracks list.
            // 7.3.6 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
            // cancelable, and that uses the TrackEvent interface, at the SourceBuffer videoTracks list.
            videoTracks->remove(track);
        }

        // 7.4 If the removed selected video track flag equals true, then queue a task to fire a simple event
        // named change at the HTMLMediaElement videoTracks list.
        if (removedSelectedVideoTrack)
            mediaElement()->videoTracks().scheduleChangeEvent();
    }

    // 8. Let SourceBuffer textTracks list equal the TextTrackList object returned by sourceBuffer.textTracks.
    RefPtr<TextTrackList> textTracks = buffer.textTracks();

    // 9. If the SourceBuffer textTracks list is not empty, then run the following steps:
    if (textTracks->length()) {
        // 9.1 Let HTMLMediaElement textTracks list equal the TextTrackList object returned by the textTracks
        // attribute on the HTMLMediaElement.
        // 9.2 Let the removed enabled text track flag equal false.
        bool removedEnabledTextTrack = false;

        // 9.3 For each TextTrack object in the SourceBuffer textTracks list, run the following steps:
        while (textTracks->length()) {
            auto& track = *textTracks->lastItem();

            // 9.3.1 Set the sourceBuffer attribute on the TextTrack object to null.
            track.setSourceBuffer(nullptr);

            // 9.3.2 If the mode attribute on the TextTrack object is set to "showing" or "hidden", then
            // set the removed enabled text track flag to true.
            if (track.mode() == TextTrack::Mode::Showing || track.mode() == TextTrack::Mode::Hidden)
                removedEnabledTextTrack = true;

            // 9.3.3 Remove the TextTrack object from the HTMLMediaElement textTracks list.
            // 9.3.4 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
            // cancelable, and that uses the TrackEvent interface, at the HTMLMediaElement textTracks list.
            if (mediaElement())
                mediaElement()->removeTextTrack(track);

            // 9.3.5 Remove the TextTrack object from the SourceBuffer textTracks list.
            // 9.3.6 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
            // cancelable, and that uses the TrackEvent interface, at the SourceBuffer textTracks list.
            textTracks->remove(track);
        }
        
        // 9.4 If the removed enabled text track flag equals true, then queue a task to fire a simple event
        // named change at the HTMLMediaElement textTracks list.
        if (removedEnabledTextTrack)
            mediaElement()->textTracks().scheduleChangeEvent();
    }
    
    
    // 10. If sourceBuffer is in activeSourceBuffers, then remove sourceBuffer from activeSourceBuffers ...
    m_activeSourceBuffers->remove(buffer);
    
    // 11. Remove sourceBuffer from sourceBuffers and fire a removesourcebuffer event
    // on that object.
    m_sourceBuffers->remove(buffer);
    
    // 12. Destroy all resources for sourceBuffer.
    buffer.removedFromMediaSource();
}
Esempio n. 27
0
void MediaSource::monitorSourceBuffers()
{
    // 2.4.4 SourceBuffer Monitoring
    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#buffer-monitoring

    // Note, the behavior if activeSourceBuffers is empty is undefined.
    if (!m_activeSourceBuffers) {
        m_private->setReadyState(MediaPlayer::HaveNothing);
        return;
    }

    // http://w3c.github.io/media-source/#buffer-monitoring, change from 11 December 2014
    // ↳ If the the HTMLMediaElement.readyState attribute equals HAVE_NOTHING:
    if (mediaElement()->readyState() == HTMLMediaElement::HAVE_NOTHING) {
        // 1. Abort these steps.
        return;
    }

    // ↳ If buffered for all objects in activeSourceBuffers do not contain TimeRanges for the current
    // playback position:
    auto begin = m_activeSourceBuffers->begin();
    auto end = m_activeSourceBuffers->end();
    if (std::all_of(begin, end, [](RefPtr<SourceBuffer>& sourceBuffer) {
        return !sourceBuffer->hasCurrentTime();
    })) {
        // 1. Set the HTMLMediaElement.readyState attribute to HAVE_METADATA.
        // 2. If this is the first transition to HAVE_METADATA, then queue a task to fire a simple event
        // named loadedmetadata at the media element.
        m_private->setReadyState(MediaPlayer::HaveMetadata);

        // 3. Abort these steps.
        return;
    }

    // ↳ If buffered for all objects in activeSourceBuffers contain TimeRanges that include the current
    // playback position and enough data to ensure uninterrupted playback:
    if (std::all_of(begin, end, [](RefPtr<SourceBuffer>& sourceBuffer) {
        return sourceBuffer->hasFutureTime() && sourceBuffer->canPlayThrough();
    })) {
        // 1. Set the HTMLMediaElement.readyState attribute to HAVE_ENOUGH_DATA.
        // 2. Queue a task to fire a simple event named canplaythrough at the media element.
        // 3. Playback may resume at this point if it was previously suspended by a transition to HAVE_CURRENT_DATA.
        m_private->setReadyState(MediaPlayer::HaveEnoughData);

        if (m_pendingSeekTime.isValid())
            completeSeek();

        // 4. Abort these steps.
        return;
    }

    // ↳ If buffered for all objects in activeSourceBuffers contain a TimeRange that includes
    // the current playback position and some time beyond the current playback position, then run the following steps:
    if (std::all_of(begin, end, [](RefPtr<SourceBuffer>& sourceBuffer) {
        return sourceBuffer->hasFutureTime();
    })) {
        // 1. Set the HTMLMediaElement.readyState attribute to HAVE_FUTURE_DATA.
        // 2. If the previous value of HTMLMediaElement.readyState was less than HAVE_FUTURE_DATA, then queue a task to fire a simple event named canplay at the media element.
        // 3. Playback may resume at this point if it was previously suspended by a transition to HAVE_CURRENT_DATA.
        m_private->setReadyState(MediaPlayer::HaveFutureData);

        if (m_pendingSeekTime.isValid())
            completeSeek();

        // 4. Abort these steps.
        return;
    }

    // ↳ If buffered for at least one object in activeSourceBuffers contains a TimeRange that ends
    // at the current playback position and does not have a range covering the time immediately
    // after the current position:
    // NOTE: Logically, !(all objects do not contain currentTime) == (some objects contain current time)

    // 1. Set the HTMLMediaElement.readyState attribute to HAVE_CURRENT_DATA.
    // 2. If this is the first transition to HAVE_CURRENT_DATA, then queue a task to fire a simple
    // event named loadeddata at the media element.
    // 3. Playback is suspended at this point since the media element doesn't have enough data to
    // advance the media timeline.
    m_private->setReadyState(MediaPlayer::HaveCurrentData);

    if (m_pendingSeekTime.isValid())
        completeSeek();

    // 4. Abort these steps.
}
Esempio n. 28
0
void HTMLTrackElement::setReadyState(ReadyState state)
{
    ensureTrack()->setReadinessState(static_cast<TextTrack::ReadinessState>(state));
    if (HTMLMediaElement* parent = mediaElement())
        return parent->textTrackReadyStateChanged(m_track.get());
}
Esempio n. 29
0
void AudioTrack::willRemove(TrackPrivateBase* trackPrivate)
{
    ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
    mediaElement()->removeAudioTrack(this);
}
Esempio n. 30
0
void MediaControls::resetHideMediaControlsTimer()
{
    stopHideMediaControlsTimer();
    if (!mediaElement().paused())
        startHideMediaControlsTimer();
}