CTTE: RenderMedia and RenderVideo are never anonymous.
[WebKit-https.git] / 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 #if ENABLE(VIDEO)
28 #include "HTMLVideoElement.h"
29
30 #include "Attribute.h"
31 #include "CSSPropertyNames.h"
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "Document.h"
35 #include "ExceptionCode.h"
36 #include "Frame.h"
37 #include "HTMLImageLoader.h"
38 #include "HTMLNames.h"
39 #include "HTMLParserIdioms.h"
40 #include "Page.h"
41 #include "RenderImage.h"
42 #include "RenderVideo.h"
43 #include "ScriptController.h"
44 #include "Settings.h"
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document& document, bool createdByParser)
51     : HTMLMediaElement(tagName, document, createdByParser)
52 {
53     ASSERT(hasTagName(videoTag));
54     setHasCustomStyleResolveCallbacks();
55     if (document.settings())
56         m_defaultPosterURL = document.settings()->defaultVideoPosterURL();
57 }
58
59 PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document& document, bool createdByParser)
60 {
61     RefPtr<HTMLVideoElement> videoElement(adoptRef(new HTMLVideoElement(tagName, document, createdByParser)));
62     videoElement->suspendIfNeeded();
63     return videoElement.release();
64 }
65
66 bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style) 
67 {
68     return HTMLElement::rendererIsNeeded(style); 
69 }
70
71 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
72 RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
73 {
74     return new (arena) RenderVideo(*this);
75 }
76 #endif
77
78 void HTMLVideoElement::didAttachRenderers()
79 {
80     HTMLMediaElement::didAttachRenderers();
81
82 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
83     updateDisplayState();
84     if (shouldDisplayPosterImage()) {
85         if (!m_imageLoader)
86             m_imageLoader = adoptPtr(new HTMLImageLoader(this));
87         m_imageLoader->updateFromElement();
88         if (renderer())
89             toRenderImage(renderer())->imageResource()->setCachedImage(m_imageLoader->image()); 
90     }
91 #endif
92 }
93
94 void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
95 {
96     if (name == widthAttr)
97         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
98     else if (name == heightAttr)
99         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
100     else
101         HTMLMediaElement::collectStyleForPresentationAttribute(name, value, style);
102 }
103
104 bool HTMLVideoElement::isPresentationAttribute(const QualifiedName& name) const
105 {
106     if (name == widthAttr || name == heightAttr)
107         return true;
108     return HTMLMediaElement::isPresentationAttribute(name);
109 }
110
111 void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
112 {
113     if (name == posterAttr) {
114         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
115         HTMLMediaElement::setDisplayMode(Unknown);
116         updateDisplayState();
117 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
118         if (shouldDisplayPosterImage()) {
119             if (!m_imageLoader)
120                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
121             m_imageLoader->updateFromElementIgnoringPreviousError();
122         } else {
123             if (renderer())
124                 toRenderImage(renderer())->imageResource()->setCachedImage(0); 
125         }
126 #endif
127     } else
128         HTMLMediaElement::parseAttribute(name, value);
129 }
130
131 bool HTMLVideoElement::supportsFullscreen() const
132 {
133     Page* page = document().page();
134     if (!page) 
135         return false;
136
137     if (!player() || !player()->supportsFullscreen())
138         return false;
139
140 #if ENABLE(FULLSCREEN_API)
141     // If the full screen API is enabled and is supported for the current element
142     // do not require that the player has a video track to enter full screen.
143     if (page->chrome().client().supportsFullScreenForElement(this, false))
144         return true;
145 #endif
146
147     if (!player()->hasVideo())
148         return false;
149
150     return page->chrome().client().supportsFullscreenForNode(this);
151 }
152
153 unsigned HTMLVideoElement::videoWidth() const
154 {
155     if (!player())
156         return 0;
157     return player()->naturalSize().width();
158 }
159
160 unsigned HTMLVideoElement::videoHeight() const
161 {
162     if (!player())
163         return 0;
164     return player()->naturalSize().height();
165 }
166
167 unsigned HTMLVideoElement::width() const
168 {
169     bool ok;
170     unsigned w = getAttribute(widthAttr).string().toUInt(&ok);
171     return ok ? w : 0;
172 }
173     
174 unsigned HTMLVideoElement::height() const
175 {
176     bool ok;
177     unsigned h = getAttribute(heightAttr).string().toUInt(&ok);
178     return ok ? h : 0;
179 }
180     
181 bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const
182 {
183     return attribute.name() == posterAttr || HTMLMediaElement::isURLAttribute(attribute);
184 }
185
186 const AtomicString& HTMLVideoElement::imageSourceURL() const
187 {
188     const AtomicString& url = getAttribute(posterAttr);
189     if (!stripLeadingAndTrailingHTMLSpaces(url).isEmpty())
190         return url;
191     return m_defaultPosterURL;
192 }
193
194 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
195 {
196     DisplayMode oldMode = displayMode();
197     KURL poster = posterImageURL();
198
199     if (!poster.isEmpty()) {
200         // We have a poster path, but only show it until the user triggers display by playing or seeking and the
201         // media engine has something to display.
202         if (mode == Video) {
203             if (oldMode != Video && player())
204                 player()->prepareForRendering();
205             if (!hasAvailableVideoFrame())
206                 mode = PosterWaitingForVideo;
207         }
208     } else if (oldMode != Video && player())
209         player()->prepareForRendering();
210
211     HTMLMediaElement::setDisplayMode(mode);
212
213     if (player() && player()->canLoadPoster()) {
214         bool canLoad = true;
215         if (!poster.isEmpty()) {
216             if (Frame* frame = document().frame())
217                 canLoad = frame->loader().willLoadMediaElementURL(poster);
218         }
219         if (canLoad)
220             player()->setPoster(poster);
221     }
222
223 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
224     if (renderer() && displayMode() != oldMode)
225         renderer()->updateFromElement();
226 #endif
227 }
228
229 void HTMLVideoElement::updateDisplayState()
230 {
231     if (posterImageURL().isEmpty())
232         setDisplayMode(Video);
233     else if (displayMode() < Poster)
234         setDisplayMode(Poster);
235 }
236
237 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
238 {
239     MediaPlayer* player = HTMLMediaElement::player();
240     if (!player)
241         return;
242     
243     player->setVisible(true); // Make player visible or it won't draw.
244     player->paintCurrentFrameInContext(context, destRect);
245 }
246
247 bool HTMLVideoElement::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject texture, GC3Dint level, GC3Denum type, GC3Denum internalFormat, bool premultiplyAlpha, bool flipY)
248 {
249     if (!player())
250         return false;
251     return player()->copyVideoTextureToPlatformTexture(context, texture, level, type, internalFormat, premultiplyAlpha, flipY);
252 }
253
254 bool HTMLVideoElement::hasAvailableVideoFrame() const
255 {
256     if (!player())
257         return false;
258     
259     return player()->hasVideo() && player()->hasAvailableVideoFrame();
260 }
261
262 void HTMLVideoElement::webkitEnterFullscreen(ExceptionCode& ec)
263 {
264     if (isFullscreen())
265         return;
266
267     // Generate an exception if this isn't called in response to a user gesture, or if the 
268     // element does not support fullscreen.
269     if ((userGestureRequiredForFullscreen() && !ScriptController::processingUserGesture()) || !supportsFullscreen()) {
270         ec = INVALID_STATE_ERR;
271         return;
272     }
273
274     enterFullscreen();
275 }
276
277 void HTMLVideoElement::webkitExitFullscreen()
278 {
279     if (isFullscreen())
280         exitFullscreen();
281 }
282
283 bool HTMLVideoElement::webkitSupportsFullscreen()
284 {
285     return supportsFullscreen();
286 }
287
288 bool HTMLVideoElement::webkitDisplayingFullscreen()
289 {
290     return isFullscreen();
291 }
292
293 void HTMLVideoElement::didMoveToNewDocument(Document* oldDocument)
294 {
295     if (m_imageLoader)
296         m_imageLoader->elementDidMoveToNewDocument();
297     HTMLMediaElement::didMoveToNewDocument(oldDocument);
298 }
299
300 #if ENABLE(MEDIA_STATISTICS)
301 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
302 {
303     if (!player())
304         return 0;
305
306     return player()->decodedFrameCount();
307 }
308
309 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
310 {
311     if (!player())
312         return 0;
313
314     return player()->droppedFrameCount();
315 }
316 #endif
317
318 KURL HTMLVideoElement::posterImageURL() const
319 {
320     String url = stripLeadingAndTrailingHTMLSpaces(imageSourceURL());
321     if (url.isEmpty())
322         return KURL();
323     return document().completeURL(url);
324 }
325
326 }
327
328 #endif