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