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/core/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 #include "platform/graphics/GraphicsContext.h"
     44 #include "platform/graphics/gpu/Extensions3DUtil.h"
     45 #include "public/platform/WebCanvas.h"
     46 #include "public/platform/WebGraphicsContext3D.h"
     47 
     48 namespace blink {
     49 
     50 using namespace HTMLNames;
     51 
     52 inline HTMLVideoElement::HTMLVideoElement(Document& document)
     53     : HTMLMediaElement(videoTag, document)
     54 {
     55     if (document.settings())
     56         m_defaultPosterURL = AtomicString(document.settings()->defaultVideoPosterURL());
     57 }
     58 
     59 PassRefPtrWillBeRawPtr<HTMLVideoElement> HTMLVideoElement::create(Document& document)
     60 {
     61     RefPtrWillBeRawPtr<HTMLVideoElement> video = adoptRefWillBeNoop(new HTMLVideoElement(document));
     62     video->ensureUserAgentShadowRoot();
     63     video->suspendIfNeeded();
     64     return video.release();
     65 }
     66 
     67 void HTMLVideoElement::trace(Visitor* visitor)
     68 {
     69     visitor->trace(m_imageLoader);
     70     HTMLMediaElement::trace(visitor);
     71 }
     72 
     73 bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style)
     74 {
     75     return HTMLElement::rendererIsNeeded(style);
     76 }
     77 
     78 RenderObject* HTMLVideoElement::createRenderer(RenderStyle*)
     79 {
     80     return new RenderVideo(this);
     81 }
     82 
     83 void HTMLVideoElement::attach(const AttachContext& context)
     84 {
     85     HTMLMediaElement::attach(context);
     86 
     87     updateDisplayState();
     88     if (shouldDisplayPosterImage()) {
     89         if (!m_imageLoader)
     90             m_imageLoader = HTMLImageLoader::create(this);
     91         m_imageLoader->updateFromElement();
     92         if (renderer())
     93             toRenderImage(renderer())->imageResource()->setImageResource(m_imageLoader->image());
     94     }
     95 }
     96 
     97 void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
     98 {
     99     if (name == widthAttr)
    100         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    101     else if (name == heightAttr)
    102         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    103     else
    104         HTMLMediaElement::collectStyleForPresentationAttribute(name, value, style);
    105 }
    106 
    107 bool HTMLVideoElement::isPresentationAttribute(const QualifiedName& name) const
    108 {
    109     if (name == widthAttr || name == heightAttr)
    110         return true;
    111     return HTMLMediaElement::isPresentationAttribute(name);
    112 }
    113 
    114 void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    115 {
    116     if (name == posterAttr) {
    117         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
    118         HTMLMediaElement::setDisplayMode(Unknown);
    119         updateDisplayState();
    120         if (shouldDisplayPosterImage()) {
    121             if (!m_imageLoader)
    122                 m_imageLoader = HTMLImageLoader::create(this);
    123             m_imageLoader->updateFromElement(ImageLoader::UpdateIgnorePreviousError);
    124         } else {
    125             if (renderer())
    126                 toRenderImage(renderer())->imageResource()->setImageResource(0);
    127         }
    128         // Notify the player when the poster image URL changes.
    129         if (webMediaPlayer())
    130             webMediaPlayer()->setPoster(posterImageURL());
    131     } else {
    132         HTMLMediaElement::parseAttribute(name, value);
    133     }
    134 }
    135 
    136 bool HTMLVideoElement::supportsFullscreen() const
    137 {
    138     if (!document().page())
    139         return false;
    140 
    141     if (!webMediaPlayer())
    142         return false;
    143 
    144     return true;
    145 }
    146 
    147 unsigned HTMLVideoElement::videoWidth() const
    148 {
    149     if (!webMediaPlayer())
    150         return 0;
    151     return webMediaPlayer()->naturalSize().width;
    152 }
    153 
    154 unsigned HTMLVideoElement::videoHeight() const
    155 {
    156     if (!webMediaPlayer())
    157         return 0;
    158     return webMediaPlayer()->naturalSize().height;
    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         // Don't show the poster if there is a seek operation or
    183         // the video has restarted because of loop attribute
    184         if (mode == Video && oldMode == Poster && !hasAvailableVideoFrame())
    185             mode = PosterWaitingForVideo;
    186     }
    187 
    188     HTMLMediaElement::setDisplayMode(mode);
    189 
    190     if (renderer() && displayMode() != oldMode)
    191         renderer()->updateFromElement();
    192 }
    193 
    194 void HTMLVideoElement::updateDisplayState()
    195 {
    196     if (posterImageURL().isEmpty())
    197         setDisplayMode(Video);
    198     else if (displayMode() < Poster)
    199         setDisplayMode(Poster);
    200 }
    201 
    202 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect) const
    203 {
    204     if (!webMediaPlayer())
    205         return;
    206 
    207     WebCanvas* canvas = context->canvas();
    208     SkXfermode::Mode mode = WebCoreCompositeToSkiaComposite(context->compositeOperation(), context->blendModeOperation());
    209     webMediaPlayer()->paint(canvas, destRect, context->getNormalizedAlpha(), mode);
    210 }
    211 
    212 bool HTMLVideoElement::copyVideoTextureToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLint level, GLenum internalFormat, GLenum type, bool premultiplyAlpha, bool flipY)
    213 {
    214     if (!webMediaPlayer())
    215         return false;
    216 
    217     if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, type, level))
    218         return false;
    219 
    220     return webMediaPlayer()->copyVideoTextureToPlatformTexture(context, texture, level, internalFormat, type, premultiplyAlpha, flipY);
    221 }
    222 
    223 bool HTMLVideoElement::hasAvailableVideoFrame() const
    224 {
    225     if (!webMediaPlayer())
    226         return false;
    227 
    228     return webMediaPlayer()->hasVideo() && webMediaPlayer()->readyState() >= blink::WebMediaPlayer::ReadyStateHaveCurrentData;
    229 }
    230 
    231 void HTMLVideoElement::webkitEnterFullscreen(ExceptionState& exceptionState)
    232 {
    233     if (isFullscreen())
    234         return;
    235 
    236     if (!supportsFullscreen()) {
    237         exceptionState.throwDOMException(InvalidStateError, "This element does not support fullscreen mode.");
    238         return;
    239     }
    240 
    241     enterFullscreen();
    242 }
    243 
    244 void HTMLVideoElement::webkitExitFullscreen()
    245 {
    246     if (isFullscreen())
    247         exitFullscreen();
    248 }
    249 
    250 bool HTMLVideoElement::webkitSupportsFullscreen()
    251 {
    252     return supportsFullscreen();
    253 }
    254 
    255 bool HTMLVideoElement::webkitDisplayingFullscreen()
    256 {
    257     return isFullscreen();
    258 }
    259 
    260 void HTMLVideoElement::didMoveToNewDocument(Document& oldDocument)
    261 {
    262     if (m_imageLoader)
    263         m_imageLoader->elementDidMoveToNewDocument();
    264     HTMLMediaElement::didMoveToNewDocument(oldDocument);
    265 }
    266 
    267 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
    268 {
    269     if (!webMediaPlayer())
    270         return 0;
    271 
    272     return webMediaPlayer()->decodedFrameCount();
    273 }
    274 
    275 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
    276 {
    277     if (!webMediaPlayer())
    278         return 0;
    279 
    280     return webMediaPlayer()->droppedFrameCount();
    281 }
    282 
    283 KURL HTMLVideoElement::posterImageURL() const
    284 {
    285     String url = stripLeadingAndTrailingHTMLSpaces(imageSourceURL());
    286     if (url.isEmpty())
    287         return KURL();
    288     return document().completeURL(url);
    289 }
    290 
    291 KURL HTMLVideoElement::mediaPlayerPosterURL()
    292 {
    293     return posterImageURL();
    294 }
    295 
    296 PassRefPtr<Image> HTMLVideoElement::getSourceImageForCanvas(SourceImageMode mode, SourceImageStatus* status) const
    297 {
    298     if (!hasAvailableVideoFrame()) {
    299         *status = InvalidSourceImageStatus;
    300         return nullptr;
    301     }
    302 
    303     IntSize intrinsicSize(videoWidth(), videoHeight());
    304     OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(intrinsicSize);
    305     if (!imageBuffer) {
    306         *status = InvalidSourceImageStatus;
    307         return nullptr;
    308     }
    309 
    310     paintCurrentFrameInContext(imageBuffer->context(), IntRect(IntPoint(0, 0), intrinsicSize));
    311 
    312     *status = NormalSourceImageStatus;
    313     return imageBuffer->copyImage(mode == CopySourceImageIfVolatile ? CopyBackingStore : DontCopyBackingStore, Unscaled);
    314 }
    315 
    316 bool HTMLVideoElement::wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const
    317 {
    318     return !hasSingleSecurityOrigin() || (!(webMediaPlayer() && webMediaPlayer()->didPassCORSAccessCheck()) && destinationSecurityOrigin->taintsCanvas(currentSrc()));
    319 }
    320 
    321 FloatSize HTMLVideoElement::sourceSize() const
    322 {
    323     return FloatSize(videoWidth(), videoHeight());
    324 }
    325 
    326 }
    327