initial import
[vuplus_webkit] / Source / WebCore / html / HTMLVideoElement.cpp
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 "Frame.h"
38 #include "HTMLImageLoader.h"
39 #include "HTMLNames.h"
40 #include "Page.h"
41 #include "RenderImage.h"
42 #include "RenderVideo.h"
43 #include "ScriptController.h"
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48
49 inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document)
50     : HTMLMediaElement(tagName, document)
51 {
52     ASSERT(hasTagName(videoTag));
53 }
54
55 PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document)
56 {
57     return adoptRef(new HTMLVideoElement(tagName, document));
58 }
59
60 bool HTMLVideoElement::rendererIsNeeded(const NodeRenderingContext& context) 
61 {
62     return HTMLElement::rendererIsNeeded(context); 
63 }
64
65 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
66 RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
67 {
68     return new (arena) RenderVideo(this);
69 }
70 #endif
71
72 void HTMLVideoElement::attach()
73 {
74     HTMLMediaElement::attach();
75
76 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
77     updateDisplayState();
78     if (shouldDisplayPosterImage()) {
79         if (!m_imageLoader)
80             m_imageLoader = adoptPtr(new HTMLImageLoader(this));
81         m_imageLoader->updateFromElement();
82         if (renderer())
83             toRenderImage(renderer())->imageResource()->setCachedImage(m_imageLoader->image()); 
84     }
85 #endif
86 }
87
88 void HTMLVideoElement::detach()
89 {
90     HTMLMediaElement::detach();
91     
92     if (!shouldDisplayPosterImage() && m_imageLoader)
93         m_imageLoader.clear();
94 }
95
96 void HTMLVideoElement::parseMappedAttribute(Attribute* attr)
97 {
98     const QualifiedName& attrName = attr->name();
99
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()) {
106             if (!m_imageLoader)
107                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
108             m_imageLoader->updateFromElementIgnoringPreviousError();
109         } else {
110             if (m_imageLoader)
111                 m_imageLoader.clear();
112             if (renderer())
113                 toRenderImage(renderer())->imageResource()->setCachedImage(0); 
114         }
115 #endif
116     } else if (attrName == widthAttr)
117         addCSSLength(attr, CSSPropertyWidth, attr->value());
118     else if (attrName == heightAttr)
119         addCSSLength(attr, CSSPropertyHeight, attr->value());
120     else
121         HTMLMediaElement::parseMappedAttribute(attr);
122 }
123
124 bool HTMLVideoElement::supportsFullscreen() const
125 {
126     Page* page = document() ? document()->page() : 0;
127     if (!page) 
128         return false;
129
130     if (!player() || !player()->supportsFullscreen() || !player()->hasVideo())
131         return false;
132
133     // Check with the platform client.
134 #if ENABLE(FULLSCREEN_API)
135     if (page->chrome()->client()->supportsFullScreenForElement(this, false))
136         return true;
137 #endif
138
139     return page->chrome()->client()->supportsFullscreenForNode(this);
140 }
141
142 unsigned HTMLVideoElement::videoWidth() const
143 {
144     if (!player())
145         return 0;
146     return player()->naturalSize().width();
147 }
148
149 unsigned HTMLVideoElement::videoHeight() const
150 {
151     if (!player())
152         return 0;
153     return player()->naturalSize().height();
154 }
155
156 unsigned HTMLVideoElement::width() const
157 {
158     bool ok;
159     unsigned w = getAttribute(widthAttr).string().toUInt(&ok);
160     return ok ? w : 0;
161 }
162     
163 unsigned HTMLVideoElement::height() const
164 {
165     bool ok;
166     unsigned h = getAttribute(heightAttr).string().toUInt(&ok);
167     return ok ? h : 0;
168 }
169     
170 bool HTMLVideoElement::isURLAttribute(Attribute* attribute) const
171 {
172     return HTMLMediaElement::isURLAttribute(attribute)
173         || attribute->name() == posterAttr;
174 }
175
176 const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const
177 {
178     return posterAttr;
179 }
180
181 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
182 {
183     DisplayMode oldMode = displayMode();
184     KURL poster = getNonEmptyURLAttribute(posterAttr);
185
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.
189         if (mode == Video) {
190             if (oldMode != Video && player())
191                 player()->prepareForRendering();
192             if (!hasAvailableVideoFrame())
193                 mode = PosterWaitingForVideo;
194         }
195     } else if (oldMode != Video && player())
196         player()->prepareForRendering();
197
198     HTMLMediaElement::setDisplayMode(mode);
199
200     if (player() && player()->canLoadPoster()) {
201         bool canLoad = true;
202         if (!poster.isEmpty()) {
203             Frame* frame = document()->frame();
204             FrameLoader* loader = frame ? frame->loader() : 0;
205             canLoad = loader && loader->willLoadMediaElementURL(poster);
206         }
207         if (canLoad)
208             player()->setPoster(poster);
209     }
210
211 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
212     if (renderer() && displayMode() != oldMode)
213         renderer()->updateFromElement();
214 #endif
215 }
216
217 void HTMLVideoElement::updateDisplayState()
218 {
219     if (getNonEmptyURLAttribute(posterAttr).isEmpty())
220         setDisplayMode(Video);
221     else if (displayMode() < Poster)
222         setDisplayMode(Poster);
223 }
224
225 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
226 {
227     MediaPlayer* player = HTMLMediaElement::player();
228     if (!player)
229         return;
230     
231     player->setVisible(true); // Make player visible or it won't draw.
232     player->paintCurrentFrameInContext(context, destRect);
233 }
234
235 bool HTMLVideoElement::hasAvailableVideoFrame() const
236 {
237     if (!player())
238         return false;
239     
240     return player()->hasAvailableVideoFrame();
241 }
242
243 void HTMLVideoElement::webkitEnterFullscreen(ExceptionCode& ec)
244 {
245     if (isFullscreen())
246         return;
247
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;
252         return;
253     }
254
255     enterFullscreen();
256 }
257
258 void HTMLVideoElement::webkitExitFullscreen()
259 {
260     if (isFullscreen())
261         exitFullscreen();
262 }
263
264 bool HTMLVideoElement::webkitSupportsFullscreen()
265 {
266     return supportsFullscreen();
267 }
268
269 bool HTMLVideoElement::webkitDisplayingFullscreen()
270 {
271     return isFullscreen();
272 }
273
274 void HTMLVideoElement::willMoveToNewOwnerDocument()
275 {
276     if (m_imageLoader)
277         m_imageLoader->elementWillMoveToNewOwnerDocument();
278     HTMLMediaElement::willMoveToNewOwnerDocument();
279 }
280
281 #if ENABLE(MEDIA_STATISTICS)
282 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
283 {
284     if (!player())
285         return 0;
286
287     return player()->decodedFrameCount();
288 }
289
290 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
291 {
292     if (!player())
293         return 0;
294
295     return player()->droppedFrameCount();
296 }
297 #endif
298
299 }
300
301 #endif