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
44namespace WebCore {
45
46using namespace HTMLNames;
47
48HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* doc)
49    : HTMLMediaElement(tagName, doc)
50    , m_shouldDisplayPosterImage(false)
51{
52    ASSERT(hasTagName(videoTag));
53}
54
55bool HTMLVideoElement::rendererIsNeeded(RenderStyle* style)
56{
57    return HTMLElement::rendererIsNeeded(style);
58}
59
60#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
61RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
62{
63    return new (arena) RenderVideo(this);
64}
65#endif
66
67void 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
85void HTMLVideoElement::detach()
86{
87    HTMLMediaElement::detach();
88
89    if (!m_shouldDisplayPosterImage)
90        if (m_imageLoader)
91            m_imageLoader.clear();
92}
93
94void 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
119bool 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
132unsigned HTMLVideoElement::videoWidth() const
133{
134    if (!m_player)
135        return 0;
136    return m_player->naturalSize().width();
137}
138
139unsigned HTMLVideoElement::videoHeight() const
140{
141    if (!m_player)
142        return 0;
143    return m_player->naturalSize().height();
144}
145
146unsigned HTMLVideoElement::width() const
147{
148    bool ok;
149    unsigned w = getAttribute(widthAttr).string().toUInt(&ok);
150    return ok ? w : 0;
151}
152
153void HTMLVideoElement::setWidth(unsigned value)
154{
155    setAttribute(widthAttr, String::number(value));
156}
157
158unsigned HTMLVideoElement::height() const
159{
160    bool ok;
161    unsigned h = getAttribute(heightAttr).string().toUInt(&ok);
162    return ok ? h : 0;
163}
164
165void HTMLVideoElement::setHeight(unsigned value)
166{
167    setAttribute(heightAttr, String::number(value));
168}
169
170void HTMLVideoElement::setPoster(const String& value)
171{
172    setAttribute(posterAttr, value);
173}
174
175bool HTMLVideoElement::isURLAttribute(Attribute* attr) const
176{
177    return attr->name() == posterAttr;
178}
179
180const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const
181{
182    return posterAttr;
183}
184
185void 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
199void 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
209void 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
219bool HTMLVideoElement::hasAvailableVideoFrame() const
220{
221    if (!m_player)
222        return false;
223
224    return m_player->hasAvailableVideoFrame();
225}
226
227void 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
242void HTMLVideoElement::webkitExitFullScreen()
243{
244    if (m_isFullscreen)
245        exitFullscreen();
246}
247
248bool HTMLVideoElement::webkitSupportsFullscreen()
249{
250    return supportsFullscreen();
251}
252
253bool HTMLVideoElement::webkitDisplayingFullscreen()
254{
255    return m_isFullscreen;
256}
257
258
259}
260#endif
261