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