diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/HTMLVideoElement.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/html/HTMLVideoElement.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLVideoElement.cpp | 282 |
1 files changed, 200 insertions, 82 deletions
diff --git a/Source/WebCore/html/HTMLVideoElement.cpp b/Source/WebCore/html/HTMLVideoElement.cpp index 69237e435..7533c85d6 100644 --- a/Source/WebCore/html/HTMLVideoElement.cpp +++ b/Source/WebCore/html/HTMLVideoElement.cpp @@ -10,10 +10,10 @@ * 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 + * THIS SOFTWARE IS PROVIDED BY APPLE 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 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE 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 @@ -24,23 +24,32 @@ */ #include "config.h" -#if ENABLE(VIDEO) #include "HTMLVideoElement.h" -#include "Attribute.h" +#if ENABLE(VIDEO) + #include "CSSPropertyNames.h" #include "Chrome.h" #include "ChromeClient.h" #include "Document.h" +#include "EventNames.h" +#include "ExceptionCode.h" #include "Frame.h" #include "HTMLImageLoader.h" #include "HTMLNames.h" #include "HTMLParserIdioms.h" +#include "Logging.h" #include "Page.h" #include "RenderImage.h" #include "RenderVideo.h" #include "ScriptController.h" #include "Settings.h" +#include "TextStream.h" +#include <wtf/NeverDestroyed.h> + +#if ENABLE(VIDEO_PRESENTATION_MODE) +#include "WebVideoFullscreenInterface.h" +#endif namespace WebCore { @@ -51,49 +60,43 @@ inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document { ASSERT(hasTagName(videoTag)); setHasCustomStyleResolveCallbacks(); - if (document.settings()) - m_defaultPosterURL = document.settings()->defaultVideoPosterURL(); + m_defaultPosterURL = document.settings().defaultVideoPosterURL(); } -PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document& document, bool createdByParser) +Ref<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document& document, bool createdByParser) { - RefPtr<HTMLVideoElement> videoElement(adoptRef(new HTMLVideoElement(tagName, document, createdByParser))); + auto videoElement = adoptRef(*new HTMLVideoElement(tagName, document, createdByParser)); videoElement->suspendIfNeeded(); - return videoElement.release(); + return videoElement; } -bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style) +Ref<HTMLVideoElement> HTMLVideoElement::create(Document& document) +{ + return create(videoTag, document, false); +} + +bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style) { return HTMLElement::rendererIsNeeded(style); } -RenderPtr<RenderElement> HTMLVideoElement::createElementRenderer(PassRef<RenderStyle> style) +RenderPtr<RenderElement> HTMLVideoElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&) { -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - if (shouldUseVideoPluginProxy()) - return HTMLMediaElement::createElementRenderer(std::move(style)); -#endif - return createRenderer<RenderVideo>(*this, std::move(style)); + return createRenderer<RenderVideo>(*this, WTFMove(style)); } void HTMLVideoElement::didAttachRenderers() { HTMLMediaElement::didAttachRenderers(); -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - if (!shouldUseVideoPluginProxy()) { -#endif - updateDisplayState(); - if (shouldDisplayPosterImage()) { - if (!m_imageLoader) - m_imageLoader = adoptPtr(new HTMLImageLoader(this)); - m_imageLoader->updateFromElement(); - if (renderer()) - toRenderImage(renderer())->imageResource().setCachedImage(m_imageLoader->image()); - } -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + updateDisplayState(); + if (shouldDisplayPosterImage()) { + if (!m_imageLoader) + m_imageLoader = std::make_unique<HTMLImageLoader>(*this); + m_imageLoader->updateFromElement(); + if (auto* renderer = this->renderer()) + renderer->imageResource().setCachedImage(m_imageLoader->image()); } -#endif } void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style) @@ -119,39 +122,40 @@ void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicStr // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState. HTMLMediaElement::setDisplayMode(Unknown); updateDisplayState(); -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - if (shouldUseVideoPluginProxy()) - return; -#endif + if (shouldDisplayPosterImage()) { if (!m_imageLoader) - m_imageLoader = adoptPtr(new HTMLImageLoader(this)); + m_imageLoader = std::make_unique<HTMLImageLoader>(*this); m_imageLoader->updateFromElementIgnoringPreviousError(); } else { - if (renderer()) - toRenderImage(renderer())->imageResource().setCachedImage(0); + if (auto* renderer = this->renderer()) + renderer->imageResource().setCachedImage(nullptr); } } -#if ENABLE(IOS_AIRPLAY) - else if (name == webkitwirelessvideoplaybackdisabledAttr) { - if (player()) - player()->setWirelessVideoPlaybackDisabled(webkitWirelessVideoPlaybackDisabled()); - } else { - HTMLMediaElement::parseAttribute(name, value); +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + else if (name == webkitwirelessvideoplaybackdisabledAttr) + mediaSession().setWirelessVideoPlaybackDisabled(*this, true); +#endif + else { + HTMLMediaElement::parseAttribute(name, value); +#if PLATFORM(IOS) && ENABLE(WIRELESS_PLAYBACK_TARGET) if (name == webkitairplayAttr) { - if (player()) - player()->setWirelessVideoPlaybackDisabled(webkitWirelessVideoPlaybackDisabled()); + bool disabled = false; + if (equalLettersIgnoringASCIICase(attributeWithoutSynchronization(HTMLNames::webkitairplayAttr), "deny")) + disabled = true; + mediaSession().setWirelessVideoPlaybackDisabled(*this, disabled); } - } -#else - else - HTMLMediaElement::parseAttribute(name, value); #endif + } + } -bool HTMLVideoElement::supportsFullscreen() const +bool HTMLVideoElement::supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode) const { + if (videoFullscreenMode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture && !mediaSession().allowsPictureInPicture(*this)) + return false; + Page* page = document().page(); if (!page) return false; @@ -160,20 +164,21 @@ bool HTMLVideoElement::supportsFullscreen() const return false; #if PLATFORM(IOS) + UNUSED_PARAM(videoFullscreenMode); // Fullscreen implemented by player. return true; #else #if ENABLE(FULLSCREEN_API) // If the full screen API is enabled and is supported for the current element // do not require that the player has a video track to enter full screen. - if (page->chrome().client().supportsFullScreenForElement(this, false)) + if (videoFullscreenMode == HTMLMediaElementEnums::VideoFullscreenModeStandard && page->chrome().client().supportsFullScreenForElement(*this, false)) return true; #endif if (!player()->hasVideo()) return false; - return page->chrome().client().supportsFullscreenForNode(this); + return page->chrome().client().supportsVideoFullscreen(videoFullscreenMode); #endif // PLATFORM(IOS) } @@ -181,14 +186,28 @@ unsigned HTMLVideoElement::videoWidth() const { if (!player()) return 0; - return player()->naturalSize().width(); + return clampToUnsigned(player()->naturalSize().width()); } unsigned HTMLVideoElement::videoHeight() const { if (!player()) return 0; - return player()->naturalSize().height(); + return clampToUnsigned(player()->naturalSize().height()); +} + +void HTMLVideoElement::scheduleResizeEvent() +{ + m_lastReportedVideoWidth = videoWidth(); + m_lastReportedVideoHeight = videoHeight(); + scheduleEvent(eventNames().resizeEvent); +} + +void HTMLVideoElement::scheduleResizeEventIfSizeChanged() +{ + if (m_lastReportedVideoWidth == videoWidth() && m_lastReportedVideoHeight == videoHeight()) + return; + scheduleResizeEvent(); } bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const @@ -198,7 +217,7 @@ bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const const AtomicString& HTMLVideoElement::imageSourceURL() const { - const AtomicString& url = getAttribute(posterAttr); + const AtomicString& url = attributeWithoutSynchronization(posterAttr); if (!stripLeadingAndTrailingHTMLSpaces(url).isEmpty()) return url; return m_defaultPosterURL; @@ -233,12 +252,10 @@ void HTMLVideoElement::setDisplayMode(DisplayMode mode) player()->setPoster(poster); } -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - if (shouldUseVideoPluginProxy()) - return; -#endif - if (renderer() && displayMode() != oldMode) - renderer()->updateFromElement(); + if (auto* renderer = this->renderer()) { + if (displayMode() != oldMode) + renderer->updateFromElement(); + } } void HTMLVideoElement::updateDisplayState() @@ -249,7 +266,7 @@ void HTMLVideoElement::updateDisplayState() setDisplayMode(Poster); } -void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect) +void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext& context, const FloatRect& destRect) { MediaPlayer* player = HTMLMediaElement::player(); if (!player) @@ -259,11 +276,11 @@ void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, cons player->paintCurrentFrameInContext(context, destRect); } -bool HTMLVideoElement::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject texture, GC3Dint level, GC3Denum type, GC3Denum internalFormat, bool premultiplyAlpha, bool flipY) +bool HTMLVideoElement::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject texture, GC3Denum target, GC3Dint level, GC3Denum internalFormat, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool flipY) { if (!player()) return false; - return player()->copyVideoTextureToPlatformTexture(context, texture, level, type, internalFormat, premultiplyAlpha, flipY); + return player()->copyVideoTextureToPlatformTexture(context, texture, target, level, internalFormat, format, type, premultiplyAlpha, flipY); } bool HTMLVideoElement::hasAvailableVideoFrame() const @@ -274,27 +291,26 @@ bool HTMLVideoElement::hasAvailableVideoFrame() const return player()->hasVideo() && player()->hasAvailableVideoFrame(); } -PassNativeImagePtr HTMLVideoElement::nativeImageForCurrentTime() +NativeImagePtr HTMLVideoElement::nativeImageForCurrentTime() { if (!player()) - return 0; + return nullptr; return player()->nativeImageForCurrentTime(); } -void HTMLVideoElement::webkitEnterFullscreen(ExceptionCode& ec) +ExceptionOr<void> HTMLVideoElement::webkitEnterFullscreen() { if (isFullscreen()) - return; + return { }; // Generate an exception if this isn't called in response to a user gesture, or if the // element does not support fullscreen. - if (!mediaSession().fullscreenPermitted(*this) || !supportsFullscreen()) { - ec = INVALID_STATE_ERR; - return; - } + if (!mediaSession().fullscreenPermitted(*this) || !supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard)) + return Exception { INVALID_STATE_ERR }; enterFullscreen(); + return { }; } void HTMLVideoElement::webkitExitFullscreen() @@ -305,7 +321,7 @@ void HTMLVideoElement::webkitExitFullscreen() bool HTMLVideoElement::webkitSupportsFullscreen() { - return supportsFullscreen(); + return supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard); } bool HTMLVideoElement::webkitDisplayingFullscreen() @@ -313,17 +329,22 @@ bool HTMLVideoElement::webkitDisplayingFullscreen() return isFullscreen(); } -#if ENABLE(IOS_AIRPLAY) -bool HTMLVideoElement::webkitWirelessVideoPlaybackDisabled() const +void HTMLVideoElement::ancestorWillEnterFullscreen() { - Settings* settings = document().settings(); - if (!settings || !settings->mediaPlaybackAllowsAirPlay()) - return true; +#if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE) + if (fullscreenMode() == VideoFullscreenModeNone) + return; - String legacyAirplayAttributeValue = fastGetAttribute(webkitairplayAttr); - if (equalIgnoringCase(legacyAirplayAttributeValue, "deny")) - return true; - return fastHasAttribute(webkitwirelessvideoplaybackdisabledAttr); + // If this video element's presentation mode is not inline, but its ancestor + // is entering fullscreen, exit its current fullscreen mode. + exitToFullscreenModeWithoutAnimationIfPossible(fullscreenMode(), VideoFullscreenModeNone); +#endif +} + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) +bool HTMLVideoElement::webkitWirelessVideoPlaybackDisabled() const +{ + return mediaSession().wirelessVideoPlaybackDisabled(*this); } void HTMLVideoElement::setWebkitWirelessVideoPlaybackDisabled(bool disabled) @@ -332,7 +353,7 @@ void HTMLVideoElement::setWebkitWirelessVideoPlaybackDisabled(bool disabled) } #endif -void HTMLVideoElement::didMoveToNewDocument(Document* oldDocument) +void HTMLVideoElement::didMoveToNewDocument(Document& oldDocument) { if (m_imageLoader) m_imageLoader->elementDidMoveToNewDocument(); @@ -365,6 +386,103 @@ URL HTMLVideoElement::posterImageURL() const return document().completeURL(url); } +#if ENABLE(VIDEO_PRESENTATION_MODE) + +bool HTMLVideoElement::webkitSupportsPresentationMode(VideoPresentationMode mode) const +{ + if (mode == VideoPresentationMode::Fullscreen) + return mediaSession().fullscreenPermitted(*this) && supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard); + + if (mode == VideoPresentationMode::PictureInPicture) { +#if PLATFORM(COCOA) + if (!supportsPictureInPicture()) + return false; +#endif + + return mediaSession().allowsPictureInPicture(*this) && supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); + } + + if (mode == VideoPresentationMode::Inline) + return !mediaSession().requiresFullscreenForVideoPlayback(*this); + + return false; +} + +static inline HTMLMediaElementEnums::VideoFullscreenMode toFullscreenMode(HTMLVideoElement::VideoPresentationMode mode) +{ + switch (mode) { + case HTMLVideoElement::VideoPresentationMode::Fullscreen: + return HTMLMediaElementEnums::VideoFullscreenModeStandard; + case HTMLVideoElement::VideoPresentationMode::PictureInPicture: + return HTMLMediaElementEnums::VideoFullscreenModePictureInPicture; + case HTMLVideoElement::VideoPresentationMode::Inline: + return HTMLMediaElementEnums::VideoFullscreenModeNone; + } + ASSERT_NOT_REACHED(); + return HTMLMediaElementEnums::VideoFullscreenModeNone; +} + +void HTMLVideoElement::webkitSetPresentationMode(VideoPresentationMode mode) +{ + setFullscreenMode(toFullscreenMode(mode)); +} + +void HTMLVideoElement::setFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode) +{ + if (mode == VideoFullscreenModeNone && isFullscreen()) { + exitFullscreen(); + return; + } + + if (!mediaSession().fullscreenPermitted(*this) || !supportsFullscreen(mode)) + return; + + enterFullscreen(mode); +} + +static HTMLVideoElement::VideoPresentationMode toPresentationMode(HTMLMediaElementEnums::VideoFullscreenMode mode) +{ + if (mode == HTMLMediaElementEnums::VideoFullscreenModeStandard) + return HTMLVideoElement::VideoPresentationMode::Fullscreen; + + if (mode & HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) + return HTMLVideoElement::VideoPresentationMode::PictureInPicture; + + if (mode == HTMLMediaElementEnums::VideoFullscreenModeNone) + return HTMLVideoElement::VideoPresentationMode::Inline; + + ASSERT_NOT_REACHED(); + return HTMLVideoElement::VideoPresentationMode::Inline; +} + +auto HTMLVideoElement::webkitPresentationMode() const -> VideoPresentationMode +{ + return toPresentationMode(fullscreenMode()); +} + +void HTMLVideoElement::fullscreenModeChanged(VideoFullscreenMode mode) +{ + if (mode != fullscreenMode()) { + LOG(Media, "HTMLVideoElement::fullscreenModeChanged(%p) - mode changed from %i to %i", this, fullscreenMode(), mode); + scheduleEvent(eventNames().webkitpresentationmodechangedEvent); + } + + if (player()) + player()->setVideoFullscreenMode(mode); + + HTMLMediaElement::fullscreenModeChanged(mode); +} + +#endif + +#if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE) +void HTMLVideoElement::exitToFullscreenModeWithoutAnimationIfPossible(HTMLMediaElementEnums::VideoFullscreenMode fromMode, HTMLMediaElementEnums::VideoFullscreenMode toMode) +{ + if (document().page()->chrome().client().supportsVideoFullscreen(fromMode)) + document().page()->chrome().client().exitVideoFullscreenToModeWithoutAnimation(*this, toMode); +} +#endif + } #endif |