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