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 43namespace WebCore { 44 45using namespace HTMLNames; 46 47inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document) 48 : HTMLMediaElement(tagName, document) 49{ 50 ASSERT(hasTagName(videoTag)); 51} 52 53PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document) 54{ 55 return adoptRef(new HTMLVideoElement(tagName, document)); 56} 57 58bool HTMLVideoElement::rendererIsNeeded(RenderStyle* style) 59{ 60 return HTMLElement::rendererIsNeeded(style); 61} 62 63#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) 64RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*) 65{ 66 return new (arena) RenderVideo(this); 67} 68#endif 69 70void 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 86void HTMLVideoElement::detach() 87{ 88 HTMLMediaElement::detach(); 89 90 if (!shouldDisplayPosterImage() && m_imageLoader) 91 m_imageLoader.clear(); 92} 93 94void 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 122bool 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 140unsigned HTMLVideoElement::videoWidth() const 141{ 142 if (!player()) 143 return 0; 144 return player()->naturalSize().width(); 145} 146 147unsigned HTMLVideoElement::videoHeight() const 148{ 149 if (!player()) 150 return 0; 151 return player()->naturalSize().height(); 152} 153 154unsigned HTMLVideoElement::width() const 155{ 156 bool ok; 157 unsigned w = getAttribute(widthAttr).string().toUInt(&ok); 158 return ok ? w : 0; 159} 160 161unsigned HTMLVideoElement::height() const 162{ 163 bool ok; 164 unsigned h = getAttribute(heightAttr).string().toUInt(&ok); 165 return ok ? h : 0; 166} 167 168bool HTMLVideoElement::isURLAttribute(Attribute* attribute) const 169{ 170 return HTMLMediaElement::isURLAttribute(attribute) 171 || attribute->name() == posterAttr; 172} 173 174const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const 175{ 176 return posterAttr; 177} 178 179void 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 207void HTMLVideoElement::updateDisplayState() 208{ 209 if (getNonEmptyURLAttribute(posterAttr).isEmpty()) 210 setDisplayMode(Video); 211 else if (displayMode() < Poster) 212 setDisplayMode(Poster); 213} 214 215void 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 225bool HTMLVideoElement::hasAvailableVideoFrame() const 226{ 227 if (!player()) 228 return false; 229 230 return player()->hasAvailableVideoFrame(); 231} 232 233void 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 248void HTMLVideoElement::webkitExitFullscreen() 249{ 250 if (isFullscreen()) 251 exitFullscreen(); 252} 253 254bool HTMLVideoElement::webkitSupportsFullscreen() 255{ 256 return supportsFullscreen(); 257} 258 259bool HTMLVideoElement::webkitDisplayingFullscreen() 260{ 261 return isFullscreen(); 262} 263 264void HTMLVideoElement::willMoveToNewOwnerDocument() 265{ 266 if (m_imageLoader) 267 m_imageLoader->elementWillMoveToNewOwnerDocument(); 268 HTMLMediaElement::willMoveToNewOwnerDocument(); 269} 270 271#if ENABLE(MEDIA_STATISTICS) 272unsigned HTMLVideoElement::webkitDecodedFrameCount() const 273{ 274 if (!player()) 275 return 0; 276 277 return player()->decodedFrameCount(); 278} 279 280unsigned HTMLVideoElement::webkitDroppedFrameCount() const 281{ 282 if (!player()) 283 return 0; 284 285 return player()->droppedFrameCount(); 286} 287#endif 288 289} 290 291#endif 292