2 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "HTMLVideoElement.h"
31 #include "Attribute.h"
32 #include "CSSPropertyNames.h"
34 #include "ChromeClient.h"
36 #include "ExceptionCode.h"
38 #include "HTMLImageLoader.h"
39 #include "HTMLNames.h"
41 #include "RenderImage.h"
42 #include "RenderVideo.h"
43 #include "ScriptController.h"
47 using namespace HTMLNames;
49 inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document)
50 : HTMLMediaElement(tagName, document)
52 ASSERT(hasTagName(videoTag));
55 PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document)
57 return adoptRef(new HTMLVideoElement(tagName, document));
60 bool HTMLVideoElement::rendererIsNeeded(const NodeRenderingContext& context)
62 return HTMLElement::rendererIsNeeded(context);
65 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
66 RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
68 return new (arena) RenderVideo(this);
72 void HTMLVideoElement::attach()
74 HTMLMediaElement::attach();
76 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
78 if (shouldDisplayPosterImage()) {
80 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
81 m_imageLoader->updateFromElement();
83 toRenderImage(renderer())->imageResource()->setCachedImage(m_imageLoader->image());
88 void HTMLVideoElement::detach()
90 HTMLMediaElement::detach();
92 if (!shouldDisplayPosterImage() && m_imageLoader)
93 m_imageLoader.clear();
96 void HTMLVideoElement::parseMappedAttribute(Attribute* attr)
98 const QualifiedName& attrName = attr->name();
100 if (attrName == posterAttr) {
101 // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
102 HTMLMediaElement::setDisplayMode(Unknown);
103 updateDisplayState();
104 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
105 if (shouldDisplayPosterImage()) {
107 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
108 m_imageLoader->updateFromElementIgnoringPreviousError();
111 m_imageLoader.clear();
113 toRenderImage(renderer())->imageResource()->setCachedImage(0);
116 } else if (attrName == widthAttr)
117 addCSSLength(attr, CSSPropertyWidth, attr->value());
118 else if (attrName == heightAttr)
119 addCSSLength(attr, CSSPropertyHeight, attr->value());
121 HTMLMediaElement::parseMappedAttribute(attr);
124 bool HTMLVideoElement::supportsFullscreen() const
126 Page* page = document() ? document()->page() : 0;
130 if (!player() || !player()->supportsFullscreen() || !player()->hasVideo())
133 // Check with the platform client.
134 #if ENABLE(FULLSCREEN_API)
135 if (page->chrome()->client()->supportsFullScreenForElement(this, false))
139 return page->chrome()->client()->supportsFullscreenForNode(this);
142 unsigned HTMLVideoElement::videoWidth() const
146 return player()->naturalSize().width();
149 unsigned HTMLVideoElement::videoHeight() const
153 return player()->naturalSize().height();
156 unsigned HTMLVideoElement::width() const
159 unsigned w = getAttribute(widthAttr).string().toUInt(&ok);
163 unsigned HTMLVideoElement::height() const
166 unsigned h = getAttribute(heightAttr).string().toUInt(&ok);
170 bool HTMLVideoElement::isURLAttribute(Attribute* attribute) const
172 return HTMLMediaElement::isURLAttribute(attribute)
173 || attribute->name() == posterAttr;
176 const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const
181 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
183 DisplayMode oldMode = displayMode();
184 KURL poster = getNonEmptyURLAttribute(posterAttr);
186 if (!poster.isEmpty()) {
187 // We have a poster path, but only show it until the user triggers display by playing or seeking and the
188 // media engine has something to display.
190 if (oldMode != Video && player())
191 player()->prepareForRendering();
192 if (!hasAvailableVideoFrame())
193 mode = PosterWaitingForVideo;
195 } else if (oldMode != Video && player())
196 player()->prepareForRendering();
198 HTMLMediaElement::setDisplayMode(mode);
200 if (player() && player()->canLoadPoster()) {
202 if (!poster.isEmpty()) {
203 Frame* frame = document()->frame();
204 FrameLoader* loader = frame ? frame->loader() : 0;
205 canLoad = loader && loader->willLoadMediaElementURL(poster);
208 player()->setPoster(poster);
211 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
212 if (renderer() && displayMode() != oldMode)
213 renderer()->updateFromElement();
217 void HTMLVideoElement::updateDisplayState()
219 if (getNonEmptyURLAttribute(posterAttr).isEmpty())
220 setDisplayMode(Video);
221 else if (displayMode() < Poster)
222 setDisplayMode(Poster);
225 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
227 MediaPlayer* player = HTMLMediaElement::player();
231 player->setVisible(true); // Make player visible or it won't draw.
232 player->paintCurrentFrameInContext(context, destRect);
235 bool HTMLVideoElement::hasAvailableVideoFrame() const
240 return player()->hasAvailableVideoFrame();
243 void HTMLVideoElement::webkitEnterFullscreen(ExceptionCode& ec)
248 // Generate an exception if this isn't called in response to a user gesture, or if the
249 // element does not support fullscreen.
250 if ((userGestureRequiredForFullscreen() && !ScriptController::processingUserGesture()) || !supportsFullscreen()) {
251 ec = INVALID_STATE_ERR;
258 void HTMLVideoElement::webkitExitFullscreen()
264 bool HTMLVideoElement::webkitSupportsFullscreen()
266 return supportsFullscreen();
269 bool HTMLVideoElement::webkitDisplayingFullscreen()
271 return isFullscreen();
274 void HTMLVideoElement::willMoveToNewOwnerDocument()
277 m_imageLoader->elementWillMoveToNewOwnerDocument();
278 HTMLMediaElement::willMoveToNewOwnerDocument();
281 #if ENABLE(MEDIA_STATISTICS)
282 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
287 return player()->decodedFrameCount();
290 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
295 return player()->droppedFrameCount();