Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2007, 2008, 2009, 2010 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 COMPUTER, 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 COMPUTER, 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 #include "config.h"
     27 #include "core/html/HTMLVideoElement.h"
     28 
     29 #include "bindings/v8/ExceptionState.h"
     30 #include "core/CSSPropertyNames.h"
     31 #include "core/HTMLNames.h"
     32 #include "core/dom/Attribute.h"
     33 #include "core/dom/Document.h"
     34 #include "core/dom/ExceptionCode.h"
     35 #include "core/dom/shadow/ShadowRoot.h"
     36 #include "core/frame/Settings.h"
     37 #include "core/html/HTMLImageLoader.h"
     38 #include "core/html/canvas/CanvasRenderingContext.h"
     39 #include "core/html/parser/HTMLParserIdioms.h"
     40 #include "core/rendering/RenderImage.h"
     41 #include "core/rendering/RenderVideo.h"
     42 #include "platform/UserGestureIndicator.h"
     43 
     44 namespace WebCore {
     45 
     46 using namespace HTMLNames;
     47 
     48 inline HTMLVideoElement::HTMLVideoElement(Document& document)
     49     : HTMLMediaElement(videoTag, document)
     50 {
     51     ScriptWrappable::init(this);
     52     if (document.settings())
     53         m_defaultPosterURL = AtomicString(document.settings()->defaultVideoPosterURL());
     54 }
     55 
     56 PassRefPtrWillBeRawPtr<HTMLVideoElement> HTMLVideoElement::create(Document& document)
     57 {
     58     RefPtrWillBeRawPtr<HTMLVideoElement> video = adoptRefWillBeNoop(new HTMLVideoElement(document));
     59     video->ensureUserAgentShadowRoot();
     60     video->suspendIfNeeded();
     61     return video.release();
     62 }
     63 
     64 void HTMLVideoElement::trace(Visitor* visitor)
     65 {
     66     visitor->trace(m_imageLoader);
     67     HTMLMediaElement::trace(visitor);
     68 }
     69 
     70 bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style)
     71 {
     72     return HTMLElement::rendererIsNeeded(style);
     73 }
     74 
     75 RenderObject* HTMLVideoElement::createRenderer(RenderStyle*)
     76 {
     77     return new RenderVideo(this);
     78 }
     79 
     80 void HTMLVideoElement::attach(const AttachContext& context)
     81 {
     82     HTMLMediaElement::attach(context);
     83 
     84     updateDisplayState();
     85     if (shouldDisplayPosterImage()) {
     86         if (!m_imageLoader)
     87             m_imageLoader = HTMLImageLoader::create(this);
     88         m_imageLoader->updateFromElement();
     89         if (renderer())
     90             toRenderImage(renderer())->imageResource()->setImageResource(m_imageLoader->image());
     91     }
     92 }
     93 
     94 void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
     95 {
     96     if (name == widthAttr)
     97         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
     98     else if (name == heightAttr)
     99         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    100     else
    101         HTMLMediaElement::collectStyleForPresentationAttribute(name, value, style);
    102 }
    103 
    104 bool HTMLVideoElement::isPresentationAttribute(const QualifiedName& name) const
    105 {
    106     if (name == widthAttr || name == heightAttr)
    107         return true;
    108     return HTMLMediaElement::isPresentationAttribute(name);
    109 }
    110 
    111 void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    112 {
    113     if (name == posterAttr) {
    114         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
    115         HTMLMediaElement::setDisplayMode(Unknown);
    116         updateDisplayState();
    117         if (shouldDisplayPosterImage()) {
    118             if (!m_imageLoader)
    119                 m_imageLoader = HTMLImageLoader::create(this);
    120             m_imageLoader->updateFromElementIgnoringPreviousError();
    121         } else {
    122             if (renderer())
    123                 toRenderImage(renderer())->imageResource()->setImageResource(0);
    124         }
    125         // Notify the player when the poster image URL changes.
    126         if (player())
    127             player()->setPoster(posterImageURL());
    128     } else
    129         HTMLMediaElement::parseAttribute(name, value);
    130 }
    131 
    132 bool HTMLVideoElement::supportsFullscreen() const
    133 {
    134     if (!document().page())
    135         return false;
    136 
    137     if (!player())
    138         return false;
    139 
    140     return true;
    141 }
    142 
    143 unsigned HTMLVideoElement::videoWidth() const
    144 {
    145     if (!webMediaPlayer())
    146         return 0;
    147     return webMediaPlayer()->naturalSize().width;
    148 }
    149 
    150 unsigned HTMLVideoElement::videoHeight() const
    151 {
    152     if (!webMediaPlayer())
    153         return 0;
    154     return webMediaPlayer()->naturalSize().height;
    155 }
    156 
    157 bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const
    158 {
    159     return attribute.name() == posterAttr || HTMLMediaElement::isURLAttribute(attribute);
    160 }
    161 
    162 const AtomicString HTMLVideoElement::imageSourceURL() const
    163 {
    164     const AtomicString& url = getAttribute(posterAttr);
    165     if (!stripLeadingAndTrailingHTMLSpaces(url).isEmpty())
    166         return url;
    167     return m_defaultPosterURL;
    168 }
    169 
    170 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
    171 {
    172     DisplayMode oldMode = displayMode();
    173     KURL poster = posterImageURL();
    174 
    175     if (!poster.isEmpty()) {
    176         // We have a poster path, but only show it until the user triggers display by playing or seeking and the
    177         // media engine has something to display.
    178         // Don't show the poster if there is a seek operation or
    179         // the video has restarted because of loop attribute
    180         if (mode == Video && oldMode == Poster && !hasAvailableVideoFrame())
    181             mode = PosterWaitingForVideo;
    182     }
    183 
    184     HTMLMediaElement::setDisplayMode(mode);
    185 
    186     if (renderer() && displayMode() != oldMode)
    187         renderer()->updateFromElement();
    188 }
    189 
    190 void HTMLVideoElement::updateDisplayState()
    191 {
    192     if (posterImageURL().isEmpty())
    193         setDisplayMode(Video);
    194     else if (displayMode() < Poster)
    195         setDisplayMode(Poster);
    196 }
    197 
    198 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect) const
    199 {
    200     MediaPlayer* player = HTMLMediaElement::player();
    201     if (!player)
    202         return;
    203     player->paint(context, destRect);
    204 }
    205 
    206 bool HTMLVideoElement::copyVideoTextureToPlatformTexture(blink::WebGraphicsContext3D* context, Platform3DObject texture, GLint level, GLenum type, GLenum internalFormat, bool premultiplyAlpha, bool flipY)
    207 {
    208     if (!player())
    209         return false;
    210     return player()->copyVideoTextureToPlatformTexture(context, texture, level, type, internalFormat, premultiplyAlpha, flipY);
    211 }
    212 
    213 bool HTMLVideoElement::hasAvailableVideoFrame() const
    214 {
    215     if (!webMediaPlayer())
    216         return false;
    217 
    218     return webMediaPlayer()->hasVideo() && webMediaPlayer()->readyState() >= blink::WebMediaPlayer::ReadyStateHaveCurrentData;
    219 }
    220 
    221 void HTMLVideoElement::webkitEnterFullscreen(ExceptionState& exceptionState)
    222 {
    223     if (isFullscreen())
    224         return;
    225 
    226     if (!supportsFullscreen()) {
    227         exceptionState.throwDOMException(InvalidStateError, "This element does not support fullscreen mode.");
    228         return;
    229     }
    230 
    231     enterFullscreen();
    232 }
    233 
    234 void HTMLVideoElement::webkitExitFullscreen()
    235 {
    236     if (isFullscreen())
    237         exitFullscreen();
    238 }
    239 
    240 bool HTMLVideoElement::webkitSupportsFullscreen()
    241 {
    242     return supportsFullscreen();
    243 }
    244 
    245 bool HTMLVideoElement::webkitDisplayingFullscreen()
    246 {
    247     return isFullscreen();
    248 }
    249 
    250 void HTMLVideoElement::didMoveToNewDocument(Document& oldDocument)
    251 {
    252     if (m_imageLoader)
    253         m_imageLoader->elementDidMoveToNewDocument();
    254     HTMLMediaElement::didMoveToNewDocument(oldDocument);
    255 }
    256 
    257 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
    258 {
    259     if (!webMediaPlayer())
    260         return 0;
    261 
    262     return webMediaPlayer()->decodedFrameCount();
    263 }
    264 
    265 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
    266 {
    267     if (!webMediaPlayer())
    268         return 0;
    269 
    270     return webMediaPlayer()->droppedFrameCount();
    271 }
    272 
    273 KURL HTMLVideoElement::posterImageURL() const
    274 {
    275     String url = stripLeadingAndTrailingHTMLSpaces(imageSourceURL());
    276     if (url.isEmpty())
    277         return KURL();
    278     return document().completeURL(url);
    279 }
    280 
    281 KURL HTMLVideoElement::mediaPlayerPosterURL()
    282 {
    283     return posterImageURL();
    284 }
    285 
    286 PassRefPtr<Image> HTMLVideoElement::getSourceImageForCanvas(SourceImageMode mode, SourceImageStatus* status) const
    287 {
    288     if (!hasAvailableVideoFrame()) {
    289         *status = InvalidSourceImageStatus;
    290         return nullptr;
    291     }
    292 
    293     IntSize intrinsicSize(videoWidth(), videoHeight());
    294     OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(intrinsicSize);
    295     if (!imageBuffer) {
    296         *status = InvalidSourceImageStatus;
    297         return nullptr;
    298     }
    299 
    300     paintCurrentFrameInContext(imageBuffer->context(), IntRect(IntPoint(0, 0), intrinsicSize));
    301 
    302     *status = NormalSourceImageStatus;
    303     return imageBuffer->copyImage(mode == CopySourceImageIfVolatile ? CopyBackingStore : DontCopyBackingStore, Unscaled);
    304 }
    305 
    306 bool HTMLVideoElement::wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const
    307 {
    308     return !hasSingleSecurityOrigin() || (!(webMediaPlayer() && webMediaPlayer()->didPassCORSAccessCheck()) && destinationSecurityOrigin->taintsCanvas(currentSrc()));
    309 }
    310 
    311 FloatSize HTMLVideoElement::sourceSize() const
    312 {
    313     return FloatSize(videoWidth(), videoHeight());
    314 }
    315 
    316 }
    317