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 
     28 #if ENABLE(VIDEO)
     29 #include "HTMLVideoElement.h"
     30 
     31 #include "Attribute.h"
     32 #include "CSSPropertyNames.h"
     33 #include "Chrome.h"
     34 #include "ChromeClient.h"
     35 #include "Document.h"
     36 #include "ExceptionCode.h"
     37 #include "HTMLImageLoader.h"
     38 #include "HTMLNames.h"
     39 #include "Page.h"
     40 #include "RenderImage.h"
     41 #include "RenderVideo.h"
     42 
     43 namespace WebCore {
     44 
     45 using namespace HTMLNames;
     46 
     47 inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document)
     48     : HTMLMediaElement(tagName, document)
     49 {
     50     ASSERT(hasTagName(videoTag));
     51 }
     52 
     53 PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document)
     54 {
     55     return adoptRef(new HTMLVideoElement(tagName, document));
     56 }
     57 
     58 bool HTMLVideoElement::rendererIsNeeded(RenderStyle* style)
     59 {
     60     return HTMLElement::rendererIsNeeded(style);
     61 }
     62 
     63 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     64 RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
     65 {
     66     return new (arena) RenderVideo(this);
     67 }
     68 #endif
     69 
     70 void HTMLVideoElement::attach()
     71 {
     72     HTMLMediaElement::attach();
     73 
     74 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     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()->setCachedImage(m_imageLoader->image());
     82     }
     83 #endif
     84 }
     85 
     86 void HTMLVideoElement::detach()
     87 {
     88     HTMLMediaElement::detach();
     89 
     90     if (!shouldDisplayPosterImage() && m_imageLoader)
     91         m_imageLoader.clear();
     92 }
     93 
     94 void HTMLVideoElement::parseMappedAttribute(Attribute* attr)
     95 {
     96     const QualifiedName& attrName = attr->name();
     97 
     98     if (attrName == posterAttr) {
     99         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
    100         HTMLMediaElement::setDisplayMode(Unknown);
    101         updateDisplayState();
    102 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    103         if (shouldDisplayPosterImage()) {
    104             if (!m_imageLoader)
    105                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
    106             m_imageLoader->updateFromElementIgnoringPreviousError();
    107         } else {
    108             if (m_imageLoader)
    109                 m_imageLoader.clear();
    110             if (renderer())
    111                 toRenderImage(renderer())->imageResource()->setCachedImage(0);
    112         }
    113 #endif
    114     } else if (attrName == widthAttr)
    115         addCSSLength(attr, CSSPropertyWidth, attr->value());
    116     else if (attrName == heightAttr)
    117         addCSSLength(attr, CSSPropertyHeight, attr->value());
    118     else
    119         HTMLMediaElement::parseMappedAttribute(attr);
    120 }
    121 
    122 bool HTMLVideoElement::supportsFullscreen() const
    123 {
    124     Page* page = document() ? document()->page() : 0;
    125     if (!page)
    126         return false;
    127 
    128     if (!player() || !player()->supportsFullscreen() || !player()->hasVideo())
    129         return false;
    130 
    131     // Check with the platform client.
    132 #if ENABLE(FULLSCREEN_API)
    133     if (page->chrome()->client()->supportsFullScreenForElement(this, false))
    134         return true;
    135 #endif
    136 
    137     return page->chrome()->client()->supportsFullscreenForNode(this);
    138 }
    139 
    140 unsigned HTMLVideoElement::videoWidth() const
    141 {
    142     if (!player())
    143         return 0;
    144     return player()->naturalSize().width();
    145 }
    146 
    147 unsigned HTMLVideoElement::videoHeight() const
    148 {
    149     if (!player())
    150         return 0;
    151     return player()->naturalSize().height();
    152 }
    153 
    154 unsigned HTMLVideoElement::width() const
    155 {
    156     bool ok;
    157     unsigned w = getAttribute(widthAttr).string().toUInt(&ok);
    158     return ok ? w : 0;
    159 }
    160 
    161 unsigned HTMLVideoElement::height() const
    162 {
    163     bool ok;
    164     unsigned h = getAttribute(heightAttr).string().toUInt(&ok);
    165     return ok ? h : 0;
    166 }
    167 
    168 bool HTMLVideoElement::isURLAttribute(Attribute* attribute) const
    169 {
    170     return HTMLMediaElement::isURLAttribute(attribute)
    171         || attribute->name() == posterAttr;
    172 }
    173 
    174 const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const
    175 {
    176     return posterAttr;
    177 }
    178 
    179 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
    180 {
    181     DisplayMode oldMode = displayMode();
    182     KURL poster = getNonEmptyURLAttribute(posterAttr);
    183 
    184     if (!poster.isEmpty()) {
    185         // We have a poster path, but only show it until the user triggers display by playing or seeking and the
    186         // media engine has something to display.
    187         if (mode == Video) {
    188             if (oldMode != Video && player())
    189                 player()->prepareForRendering();
    190             if (!hasAvailableVideoFrame())
    191                 mode = PosterWaitingForVideo;
    192         }
    193     } else if (oldMode != Video && player())
    194         player()->prepareForRendering();
    195 
    196     HTMLMediaElement::setDisplayMode(mode);
    197 
    198     if (player() && player()->canLoadPoster())
    199         player()->setPoster(poster);
    200 
    201 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    202     if (renderer() && displayMode() != oldMode)
    203         renderer()->updateFromElement();
    204 #endif
    205 }
    206 
    207 void HTMLVideoElement::updateDisplayState()
    208 {
    209     if (getNonEmptyURLAttribute(posterAttr).isEmpty())
    210         setDisplayMode(Video);
    211     else if (displayMode() < Poster)
    212         setDisplayMode(Poster);
    213 }
    214 
    215 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
    216 {
    217     MediaPlayer* player = HTMLMediaElement::player();
    218     if (!player)
    219         return;
    220 
    221     player->setVisible(true); // Make player visible or it won't draw.
    222     player->paintCurrentFrameInContext(context, destRect);
    223 }
    224 
    225 bool HTMLVideoElement::hasAvailableVideoFrame() const
    226 {
    227     if (!player())
    228         return false;
    229 
    230     return player()->hasAvailableVideoFrame();
    231 }
    232 
    233 void HTMLVideoElement::webkitEnterFullscreen(bool isUserGesture, ExceptionCode& ec)
    234 {
    235     if (isFullscreen())
    236         return;
    237 
    238     // Generate an exception if this isn't called in response to a user gesture, or if the
    239     // element does not support fullscreen.
    240     if ((requireUserGestureForFullScreen() && !isUserGesture) || !supportsFullscreen()) {
    241         ec = INVALID_STATE_ERR;
    242         return;
    243     }
    244 
    245     enterFullscreen();
    246 }
    247 
    248 void HTMLVideoElement::webkitExitFullscreen()
    249 {
    250     if (isFullscreen())
    251         exitFullscreen();
    252 }
    253 
    254 bool HTMLVideoElement::webkitSupportsFullscreen()
    255 {
    256     return supportsFullscreen();
    257 }
    258 
    259 bool HTMLVideoElement::webkitDisplayingFullscreen()
    260 {
    261     return isFullscreen();
    262 }
    263 
    264 void HTMLVideoElement::willMoveToNewOwnerDocument()
    265 {
    266     if (m_imageLoader)
    267         m_imageLoader->elementWillMoveToNewOwnerDocument();
    268     HTMLMediaElement::willMoveToNewOwnerDocument();
    269 }
    270 
    271 #if ENABLE(MEDIA_STATISTICS)
    272 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
    273 {
    274     if (!player())
    275         return 0;
    276 
    277     return player()->decodedFrameCount();
    278 }
    279 
    280 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
    281 {
    282     if (!player())
    283         return 0;
    284 
    285     return player()->droppedFrameCount();
    286 }
    287 #endif
    288 
    289 }
    290 
    291 #endif
    292