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 "Chrome.h" 32 #include "ChromeClient.h" 33 #include "CSSHelper.h" 34 #include "CSSPropertyNames.h" 35 #include "Document.h" 36 #include "ExceptionCode.h" 37 #include "HTMLImageLoader.h" 38 #include "HTMLNames.h" 39 #include "MappedAttribute.h" 40 #include "Page.h" 41 #include "RenderImage.h" 42 #include "RenderVideo.h" 43 44 namespace WebCore { 45 46 using namespace HTMLNames; 47 48 HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* doc) 49 : HTMLMediaElement(tagName, doc) 50 , m_shouldDisplayPosterImage(false) 51 { 52 ASSERT(hasTagName(videoTag)); 53 } 54 55 bool HTMLVideoElement::rendererIsNeeded(RenderStyle* style) 56 { 57 return HTMLElement::rendererIsNeeded(style); 58 } 59 60 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) 61 RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*) 62 { 63 return new (arena) RenderVideo(this); 64 } 65 #endif 66 67 void HTMLVideoElement::attach() 68 { 69 HTMLMediaElement::attach(); 70 71 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) 72 updatePosterImage(); 73 if (m_shouldDisplayPosterImage) { 74 if (!m_imageLoader) 75 m_imageLoader.set(new HTMLImageLoader(this)); 76 m_imageLoader->updateFromElement(); 77 if (renderer()) { 78 RenderImage* imageRenderer = toRenderImage(renderer()); 79 imageRenderer->setCachedImage(m_imageLoader->image()); 80 } 81 } 82 #endif 83 } 84 85 void HTMLVideoElement::detach() 86 { 87 HTMLMediaElement::detach(); 88 89 if (!m_shouldDisplayPosterImage) 90 if (m_imageLoader) 91 m_imageLoader.clear(); 92 } 93 94 void HTMLVideoElement::parseMappedAttribute(MappedAttribute* attr) 95 { 96 const QualifiedName& attrName = attr->name(); 97 98 if (attrName == posterAttr) { 99 m_posterURL = document()->completeURL(attr->value()); 100 updatePosterImage(); 101 if (m_shouldDisplayPosterImage) { 102 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) 103 if (!m_imageLoader) 104 m_imageLoader.set(new HTMLImageLoader(this)); 105 m_imageLoader->updateFromElementIgnoringPreviousError(); 106 #else 107 if (m_player) 108 m_player->setPoster(poster()); 109 #endif 110 } 111 } else if (attrName == widthAttr) 112 addCSSLength(attr, CSSPropertyWidth, attr->value()); 113 else if (attrName == heightAttr) 114 addCSSLength(attr, CSSPropertyHeight, attr->value()); 115 else 116 HTMLMediaElement::parseMappedAttribute(attr); 117 } 118 119 bool HTMLVideoElement::supportsFullscreen() const 120 { 121 Page* page = document() ? document()->page() : 0; 122 if (!page) 123 return false; 124 125 if (!m_player || !m_player->supportsFullscreen() || !m_player->hasVideo()) 126 return false; 127 128 // Check with the platform client. 129 return page->chrome()->client()->supportsFullscreenForNode(this); 130 } 131 132 unsigned HTMLVideoElement::videoWidth() const 133 { 134 if (!m_player) 135 return 0; 136 return m_player->naturalSize().width(); 137 } 138 139 unsigned HTMLVideoElement::videoHeight() const 140 { 141 if (!m_player) 142 return 0; 143 return m_player->naturalSize().height(); 144 } 145 146 unsigned HTMLVideoElement::width() const 147 { 148 bool ok; 149 unsigned w = getAttribute(widthAttr).string().toUInt(&ok); 150 return ok ? w : 0; 151 } 152 153 void HTMLVideoElement::setWidth(unsigned value) 154 { 155 setAttribute(widthAttr, String::number(value)); 156 } 157 158 unsigned HTMLVideoElement::height() const 159 { 160 bool ok; 161 unsigned h = getAttribute(heightAttr).string().toUInt(&ok); 162 return ok ? h : 0; 163 } 164 165 void HTMLVideoElement::setHeight(unsigned value) 166 { 167 setAttribute(heightAttr, String::number(value)); 168 } 169 170 void HTMLVideoElement::setPoster(const String& value) 171 { 172 setAttribute(posterAttr, value); 173 } 174 175 bool HTMLVideoElement::isURLAttribute(Attribute* attr) const 176 { 177 return attr->name() == posterAttr; 178 } 179 180 const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const 181 { 182 return posterAttr; 183 } 184 185 void HTMLVideoElement::updatePosterImage() 186 { 187 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) 188 bool oldShouldShowPosterImage = m_shouldDisplayPosterImage; 189 #endif 190 191 m_shouldDisplayPosterImage = !poster().isEmpty() && !hasAvailableVideoFrame(); 192 193 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) 194 if (renderer() && oldShouldShowPosterImage != m_shouldDisplayPosterImage) 195 renderer()->updateFromElement(); 196 #endif 197 } 198 199 void HTMLVideoElement::paint(GraphicsContext* context, const IntRect& destRect) 200 { 201 MediaPlayer* player = HTMLMediaElement::player(); 202 if (!player) 203 return; 204 205 player->setVisible(true); // Make player visible or it won't draw. 206 player->paint(context, destRect); 207 } 208 209 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect) 210 { 211 MediaPlayer* player = HTMLMediaElement::player(); 212 if (!player) 213 return; 214 215 player->setVisible(true); // Make player visible or it won't draw. 216 player->paintCurrentFrameInContext(context, destRect); 217 } 218 219 bool HTMLVideoElement::hasAvailableVideoFrame() const 220 { 221 if (!m_player) 222 return false; 223 224 return m_player->hasAvailableVideoFrame(); 225 } 226 227 void HTMLVideoElement::webkitEnterFullScreen(bool isUserGesture, ExceptionCode& ec) 228 { 229 if (m_isFullscreen) 230 return; 231 232 // Generate an exception if this isn't called in response to a user gesture, or if the 233 // element does not support fullscreen. 234 if (!isUserGesture || !supportsFullscreen()) { 235 ec = INVALID_STATE_ERR; 236 return; 237 } 238 239 enterFullscreen(); 240 } 241 242 void HTMLVideoElement::webkitExitFullScreen() 243 { 244 if (m_isFullscreen) 245 exitFullscreen(); 246 } 247 248 bool HTMLVideoElement::webkitSupportsFullscreen() 249 { 250 return supportsFullscreen(); 251 } 252 253 bool HTMLVideoElement::webkitDisplayingFullscreen() 254 { 255 return m_isFullscreen; 256 } 257 258 259 } 260 #endif 261