Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/html/HTMLVideoElement.h"
28
29 #include "CSSPropertyNames.h"
30 #include "HTMLNames.h"
31 #include "bindings/v8/ExceptionState.h"
32 #include "core/dom/Attribute.h"
33 #include "core/dom/Document.h"
34 #include "core/dom/ExceptionCode.h"
35 #include "core/html/HTMLImageLoader.h"
36 #include "core/html/parser/HTMLParserIdioms.h"
37 #include "core/frame/Settings.h"
38 #include "core/rendering/RenderImage.h"
39 #include "core/rendering/RenderVideo.h"
40 #include "platform/UserGestureIndicator.h"
41
42 namespace WebCore {
43
44 using namespace HTMLNames;
45
46 inline HTMLVideoElement::HTMLVideoElement(Document& document)
47     : HTMLMediaElement(videoTag, document)
48 {
49     ScriptWrappable::init(this);
50     if (document.settings())
51         m_defaultPosterURL = AtomicString(document.settings()->defaultVideoPosterURL());
52 }
53
54 PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(Document& document)
55 {
56     RefPtr<HTMLVideoElement> videoElement(adoptRef(new HTMLVideoElement(document)));
57     videoElement->suspendIfNeeded();
58     return videoElement.release();
59 }
60
61 bool HTMLVideoElement::rendererIsNeeded(const RenderStyle& style)
62 {
63     return HTMLElement::rendererIsNeeded(style);
64 }
65
66 RenderObject* HTMLVideoElement::createRenderer(RenderStyle*)
67 {
68     return new RenderVideo(this);
69 }
70
71 void HTMLVideoElement::attach(const AttachContext& context)
72 {
73     HTMLMediaElement::attach(context);
74
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()->setImageResource(m_imageLoader->image());
82     }
83 }
84
85 void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
86 {
87     if (name == widthAttr)
88         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
89     else if (name == heightAttr)
90         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
91     else
92         HTMLMediaElement::collectStyleForPresentationAttribute(name, value, style);
93 }
94
95 bool HTMLVideoElement::isPresentationAttribute(const QualifiedName& name) const
96 {
97     if (name == widthAttr || name == heightAttr)
98         return true;
99     return HTMLMediaElement::isPresentationAttribute(name);
100 }
101
102 void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
103 {
104     if (name == posterAttr) {
105         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
106         HTMLMediaElement::setDisplayMode(Unknown);
107         updateDisplayState();
108         if (shouldDisplayPosterImage()) {
109             if (!m_imageLoader)
110                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
111             m_imageLoader->updateFromElementIgnoringPreviousError();
112         } else {
113             if (renderer())
114                 toRenderImage(renderer())->imageResource()->setImageResource(0);
115         }
116         // Notify the player when the poster image URL changes.
117         if (player())
118             player()->setPoster(posterImageURL());
119     } else
120         HTMLMediaElement::parseAttribute(name, value);
121 }
122
123 bool HTMLVideoElement::supportsFullscreen() const
124 {
125     if (!document().page())
126         return false;
127
128     if (!player())
129         return false;
130
131     return true;
132 }
133
134 unsigned HTMLVideoElement::videoWidth() const
135 {
136     if (!player())
137         return 0;
138     return player()->naturalSize().width();
139 }
140
141 unsigned HTMLVideoElement::videoHeight() const
142 {
143     if (!player())
144         return 0;
145     return player()->naturalSize().height();
146 }
147
148 bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const
149 {
150     return attribute.name() == posterAttr || HTMLMediaElement::isURLAttribute(attribute);
151 }
152
153 const AtomicString HTMLVideoElement::imageSourceURL() const
154 {
155     const AtomicString& url = getAttribute(posterAttr);
156     if (!stripLeadingAndTrailingHTMLSpaces(url).isEmpty())
157         return url;
158     return m_defaultPosterURL;
159 }
160
161 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
162 {
163     DisplayMode oldMode = displayMode();
164     KURL poster = posterImageURL();
165
166     if (!poster.isEmpty()) {
167         // We have a poster path, but only show it until the user triggers display by playing or seeking and the
168         // media engine has something to display.
169         if (mode == Video && !hasAvailableVideoFrame())
170             mode = PosterWaitingForVideo;
171     }
172
173     HTMLMediaElement::setDisplayMode(mode);
174
175     if (renderer() && displayMode() != oldMode)
176         renderer()->updateFromElement();
177 }
178
179 void HTMLVideoElement::updateDisplayState()
180 {
181     if (posterImageURL().isEmpty())
182         setDisplayMode(Video);
183     else if (displayMode() < Poster)
184         setDisplayMode(Poster);
185 }
186
187 void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
188 {
189     MediaPlayer* player = HTMLMediaElement::player();
190     if (!player)
191         return;
192     player->paint(context, destRect);
193 }
194
195 bool HTMLVideoElement::copyVideoTextureToPlatformTexture(blink::WebGraphicsContext3D* context, Platform3DObject texture, GLint level, GLenum type, GLenum internalFormat, bool premultiplyAlpha, bool flipY)
196 {
197     if (!player())
198         return false;
199     return player()->copyVideoTextureToPlatformTexture(context, texture, level, type, internalFormat, premultiplyAlpha, flipY);
200 }
201
202 bool HTMLVideoElement::hasAvailableVideoFrame() const
203 {
204     if (!player())
205         return false;
206
207     return player()->hasVideo() && player()->readyState() >= MediaPlayer::HaveCurrentData;
208 }
209
210 void HTMLVideoElement::webkitEnterFullscreen(ExceptionState& exceptionState)
211 {
212     if (isFullscreen())
213         return;
214
215     // Generate an exception if this isn't called in response to a user gesture, or if the
216     // element does not support fullscreen.
217     if (userGestureRequiredForFullscreen() && !UserGestureIndicator::processingUserGesture()) {
218         exceptionState.throwDOMException(InvalidStateError, "This element may only enter fullscreen mode in response to a user gesture ('click', for example).");
219         return;
220     }
221     if (!supportsFullscreen()) {
222         exceptionState.throwDOMException(InvalidStateError, "This element does not support fullscreen mode.");
223         return;
224     }
225
226     enterFullscreen();
227 }
228
229 void HTMLVideoElement::webkitExitFullscreen()
230 {
231     if (isFullscreen())
232         exitFullscreen();
233 }
234
235 bool HTMLVideoElement::webkitSupportsFullscreen()
236 {
237     return supportsFullscreen();
238 }
239
240 bool HTMLVideoElement::webkitDisplayingFullscreen()
241 {
242     return isFullscreen();
243 }
244
245 void HTMLVideoElement::didMoveToNewDocument(Document& oldDocument)
246 {
247     if (m_imageLoader)
248         m_imageLoader->elementDidMoveToNewDocument();
249     HTMLMediaElement::didMoveToNewDocument(oldDocument);
250 }
251
252 unsigned HTMLVideoElement::webkitDecodedFrameCount() const
253 {
254     if (!player())
255         return 0;
256
257     return player()->decodedFrameCount();
258 }
259
260 unsigned HTMLVideoElement::webkitDroppedFrameCount() const
261 {
262     if (!player())
263         return 0;
264
265     return player()->droppedFrameCount();
266 }
267
268 KURL HTMLVideoElement::posterImageURL() const
269 {
270     String url = stripLeadingAndTrailingHTMLSpaces(imageSourceURL());
271     if (url.isEmpty())
272         return KURL();
273     return document().completeURL(url);
274 }
275
276 KURL HTMLVideoElement::mediaPlayerPosterURL()
277 {
278     return posterImageURL();
279 }
280
281 }