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 "CSSPropertyNames.h"
     30 #include "HTMLNames.h"
     31 #include "bindings/v8/ExceptionState.h"
     32 #include "core/dom/Attribute.h"
     33 #include "core/dom/Document.h"
     34 #include "core/dom/ExceptionCode.h"
     35 #include "core/html/HTMLImageLoader.h"
     36 #include "core/html/parser/HTMLParserIdioms.h"
     37 #include "core/frame/Settings.h"
     38 #include "core/rendering/RenderImage.h"
     39 #include "core/rendering/RenderVideo.h"
     40 #include "platform/UserGestureIndicator.h"
     41 
     42 namespace WebCore {
     43 
     44 using namespace HTMLNames;
     45 
     46 inline HTMLVideoElement::HTMLVideoElement(Document& document, bool createdByParser)
     47     : HTMLMediaElement(videoTag, document, createdByParser)
     48 {
     49     ScriptWrappable::init(this);
     50     if (document.settings())
     51         m_defaultPosterURL = document.settings()->defaultVideoPosterURL();
     52 }
     53 
     54 PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(Document& document, bool createdByParser)
     55 {
     56     RefPtr<HTMLVideoElement> videoElement(adoptRef(new HTMLVideoElement(document, createdByParser)));
     57     videoElement->suspendIfNeeded();
     58     return videoElement.release();
     59 }
     60 
     61 bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style)
     62 {
     63     return HTMLElement::rendererIsNeeded(style);
     64 }
     65 
     66 RenderObject* HTMLVideoElement::createRenderer(RenderStyle*)
     67 {
     68     return new RenderVideo(this);
     69 }
     70 
     71 void HTMLVideoElement::attach(const AttachContext& context)
     72 {
     73     HTMLMediaElement::attach(context);
     74 
     75     updateDisplayState();
     76     if (shouldDisplayPosterImage()) {
     77         if (!m_imageLoader)
     78             m_imageLoader = adoptPtr(new HTMLImageLoader(this));
     79         m_imageLoader->updateFromElement();
     80         if (renderer())
     81             toRenderImage(renderer())->imageResource()->setImageResource(m_imageLoader->image());
     82     }
     83 }
     84 
     85 void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
     86 {
     87     if (name == widthAttr)
     88         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
     89     else if (name == heightAttr)
     90         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
     91     else
     92         HTMLMediaElement::collectStyleForPresentationAttribute(name, value, style);
     93 }
     94 
     95 bool HTMLVideoElement::isPresentationAttribute(const QualifiedName& name) const
     96 {
     97     if (name == widthAttr || name == heightAttr)
     98         return true;
     99     return HTMLMediaElement::isPresentationAttribute(name);
    100 }
    101 
    102 void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    103 {
    104     if (name == posterAttr) {
    105         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
    106         HTMLMediaElement::setDisplayMode(Unknown);
    107         updateDisplayState();
    108         if (shouldDisplayPosterImage()) {
    109             if (!m_imageLoader)
    110                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
    111             m_imageLoader->updateFromElementIgnoringPreviousError();
    112         } else {
    113             if (renderer())
    114                 toRenderImage(renderer())->imageResource()->setImageResource(0);
    115         }
    116     } else
    117         HTMLMediaElement::parseAttribute(name, value);
    118 }
    119 
    120 bool HTMLVideoElement::supportsFullscreen() const
    121 {
    122     if (!document().page())
    123         return false;
    124 
    125     if (!player() || !player()->supportsFullscreen())
    126         return false;
    127 
    128     return true;
    129 }
    130 
    131 unsigned HTMLVideoElement::videoWidth() const
    132 {
    133     if (!player())
    134         return 0;
    135     return player()->naturalSize().width();
    136 }
    137 
    138 unsigned HTMLVideoElement::videoHeight() const
    139 {
    140     if (!player())
    141         return 0;
    142     return player()->naturalSize().height();
    143 }
    144 
    145 bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const
    146 {
    147     return attribute.name() == posterAttr || HTMLMediaElement::isURLAttribute(attribute);
    148 }
    149 
    150 const AtomicString HTMLVideoElement::imageSourceURL() const
    151 {
    152     const AtomicString& url = getAttribute(posterAttr);
    153     if (!stripLeadingAndTrailingHTMLSpaces(url).isEmpty())
    154         return url;
    155     return m_defaultPosterURL;
    156 }
    157 
    158 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
    159 {
    160     DisplayMode oldMode = displayMode();
    161     KURL poster = posterImageURL();
    162 
    163     if (!poster.isEmpty()) {
    164         // We have a poster path, but only show it until the user triggers display by playing or seeking and the
    165         // media engine has something to display.
    166         if (mode == Video && !hasAvailableVideoFrame())
    167             mode = PosterWaitingForVideo;
    168     }
    169 
    170     HTMLMediaElement::setDisplayMode(mode);
    171 
    172     if (renderer() && displayMode() != oldMode)
    173         renderer()->updateFromElement();
    174 }
    175 
    176 void HTMLVideoElement::updateDisplayState()
    177 {
    178     if (posterImageURL().isEmpty())
    179         setDisplayMode(Video);
    180     else if (displayMode() < Poster)
    181         setDisplayMode(Poster);
    182 }
    183 
    184 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
    185 {
    186     MediaPlayer* player = HTMLMediaElement::player();
    187     if (!player)
    188         return;
    189     player->paint(context, destRect);
    190 }
    191 
    192 bool HTMLVideoElement::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject texture, GC3Dint level, GC3Denum type, GC3Denum internalFormat, bool premultiplyAlpha, bool flipY)
    193 {
    194     if (!player())
    195         return false;
    196     return player()->copyVideoTextureToPlatformTexture(context, texture, level, type, internalFormat, premultiplyAlpha, flipY);
    197 }
    198 
    199 bool HTMLVideoElement::hasAvailableVideoFrame() const
    200 {
    201     if (!player())
    202         return false;
    203 
    204     return player()->hasVideo() && player()->readyState() >= MediaPlayer::HaveCurrentData;
    205 }
    206 
    207 void HTMLVideoElement::webkitEnterFullscreen(ExceptionState& exceptionState)
    208 {
    209     if (isFullscreen())
    210         return;
    211 
    212     // Generate an exception if this isn't called in response to a user gesture, or if the
    213     // element does not support fullscreen.
    214     if (userGestureRequiredForFullscreen() && !UserGestureIndicator::processingUserGesture()) {
    215         exceptionState.throwDOMException(InvalidStateError, "This element may only enter fullscreen mode in response to a user gesture ('click', for example).");
    216         return;
    217     }
    218     if (!supportsFullscreen()) {
    219         exceptionState.throwDOMException(InvalidStateError, "This element does not support fullscreen mode.");
    220         return;
    221     }
    222 
    223     enterFullscreen();
    224 }
    225 
    226 void HTMLVideoElement::webkitExitFullscreen()
    227 {
    228     if (isFullscreen())
    229         exitFullscreen();
    230 }
    231 
    232 bool HTMLVideoElement::webkitSupportsFullscreen()
    233 {
    234     return supportsFullscreen();
    235 }
    236 
    237 bool HTMLVideoElement::webkitDisplayingFullscreen()
    238 {
    239     return isFullscreen();
    240 }
    241 
    242 void HTMLVideoElement::didMoveToNewDocument(Document& oldDocument)
    243 {
    244     if (m_imageLoader)
    245         m_imageLoader->elementDidMoveToNewDocument();
    246     HTMLMediaElement::didMoveToNewDocument(oldDocument);
    247 }
    248 
    249 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
    250 {
    251     if (!player())
    252         return 0;
    253 
    254     return player()->decodedFrameCount();
    255 }
    256 
    257 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
    258 {
    259     if (!player())
    260         return 0;
    261 
    262     return player()->droppedFrameCount();
    263 }
    264 
    265 KURL HTMLVideoElement::posterImageURL() const
    266 {
    267     String url = stripLeadingAndTrailingHTMLSpaces(imageSourceURL());
    268     if (url.isEmpty())
    269         return KURL();
    270     return document().completeURL(url);
    271 }
    272 
    273 }
    274