Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderVideo.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 #include "core/rendering/RenderVideo.h"
29
30 #include "core/HTMLNames.h"
31 #include "core/dom/Document.h"
32 #include "core/frame/FrameView.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/html/HTMLVideoElement.h"
35 #include "core/rendering/PaintInfo.h"
36 #include "core/rendering/RenderFullScreen.h"
37 #include "platform/graphics/media/MediaPlayer.h"
38 #include "public/platform/WebLayer.h"
39
40 namespace blink {
41
42 using namespace HTMLNames;
43
44 RenderVideo::RenderVideo(HTMLVideoElement* video)
45     : RenderMedia(video)
46 {
47     setIntrinsicSize(calculateIntrinsicSize());
48 }
49
50 RenderVideo::~RenderVideo()
51 {
52 }
53
54 IntSize RenderVideo::defaultSize()
55 {
56     // These values are specified in the spec.
57     static const int cDefaultWidth = 300;
58     static const int cDefaultHeight = 150;
59
60     return IntSize(cDefaultWidth, cDefaultHeight);
61 }
62
63 void RenderVideo::intrinsicSizeChanged()
64 {
65     if (videoElement()->shouldDisplayPosterImage())
66         RenderMedia::intrinsicSizeChanged();
67     updateIntrinsicSize();
68 }
69
70 void RenderVideo::updateIntrinsicSize()
71 {
72     LayoutSize size = calculateIntrinsicSize();
73     size.scale(style()->effectiveZoom());
74
75     // Never set the element size to zero when in a media document.
76     if (size.isEmpty() && node()->ownerDocument() && node()->ownerDocument()->isMediaDocument())
77         return;
78
79     if (size == intrinsicSize())
80         return;
81
82     setIntrinsicSize(size);
83     setPreferredLogicalWidthsDirty();
84     setNeedsLayoutAndFullPaintInvalidation();
85 }
86
87 LayoutSize RenderVideo::calculateIntrinsicSize()
88 {
89     HTMLVideoElement* video = videoElement();
90
91     // Spec text from 4.8.6
92     //
93     // The intrinsic width of a video element's playback area is the intrinsic width
94     // of the video resource, if that is available; otherwise it is the intrinsic
95     // width of the poster frame, if that is available; otherwise it is 300 CSS pixels.
96     //
97     // The intrinsic height of a video element's playback area is the intrinsic height
98     // of the video resource, if that is available; otherwise it is the intrinsic
99     // height of the poster frame, if that is available; otherwise it is 150 CSS pixels.
100     WebMediaPlayer* webMediaPlayer = mediaElement()->webMediaPlayer();
101     if (webMediaPlayer && video->readyState() >= HTMLVideoElement::HAVE_METADATA) {
102         IntSize size = webMediaPlayer->naturalSize();
103         if (!size.isEmpty())
104             return size;
105     }
106
107     if (video->shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred())
108         return m_cachedImageSize;
109
110     // <video> in standalone media documents should not use the default 300x150
111     // size since they also have audio-only files. By setting the intrinsic
112     // size to 300x1 the video will resize itself in these cases, and audio will
113     // have the correct height (it needs to be > 0 for controls to render properly).
114     if (video->ownerDocument() && video->ownerDocument()->isMediaDocument())
115         return LayoutSize(defaultSize().width(), 1);
116
117     return defaultSize();
118 }
119
120 void RenderVideo::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
121 {
122     RenderMedia::imageChanged(newImage, rect);
123
124     // Cache the image intrinsic size so we can continue to use it to draw the image correctly
125     // even if we know the video intrinsic size but aren't able to draw video frames yet
126     // (we don't want to scale the poster to the video size without keeping aspect ratio).
127     if (videoElement()->shouldDisplayPosterImage())
128         m_cachedImageSize = intrinsicSize();
129
130     // The intrinsic size is now that of the image, but in case we already had the
131     // intrinsic size of the video we call this here to restore the video size.
132     updateIntrinsicSize();
133 }
134
135 IntRect RenderVideo::videoBox() const
136 {
137     const LayoutSize* overriddenIntrinsicSize = 0;
138     if (videoElement()->shouldDisplayPosterImage())
139         overriddenIntrinsicSize = &m_cachedImageSize;
140
141     return pixelSnappedIntRect(replacedContentRect(overriddenIntrinsicSize));
142 }
143
144 bool RenderVideo::shouldDisplayVideo() const
145 {
146     return !videoElement()->shouldDisplayPosterImage();
147 }
148
149 void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
150 {
151     MediaPlayer* mediaPlayer = mediaElement()->player();
152     bool displayingPoster = videoElement()->shouldDisplayPosterImage();
153     if (!displayingPoster && !mediaPlayer)
154         return;
155
156     LayoutRect rect = videoBox();
157     if (rect.isEmpty())
158         return;
159     rect.moveBy(paintOffset);
160
161     LayoutRect contentRect = contentBoxRect();
162     contentRect.moveBy(paintOffset);
163     GraphicsContext* context = paintInfo.context;
164     bool clip = !contentRect.contains(rect);
165     if (clip) {
166         context->save();
167         context->clip(contentRect);
168     }
169
170     if (displayingPoster)
171         paintIntoRect(context, rect);
172     else if ((document().view() && document().view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) || !acceleratedRenderingInUse())
173         videoElement()->paintCurrentFrameInContext(context, pixelSnappedIntRect(rect));
174
175     if (clip)
176         context->restore();
177 }
178
179 bool RenderVideo::acceleratedRenderingInUse()
180 {
181     WebLayer* webLayer = mediaElement()->platformLayer();
182     return webLayer && !webLayer->isOrphan();
183 }
184
185 void RenderVideo::layout()
186 {
187     updatePlayer();
188     RenderMedia::layout();
189 }
190
191 HTMLVideoElement* RenderVideo::videoElement() const
192 {
193     return toHTMLVideoElement(node());
194 }
195
196 void RenderVideo::updateFromElement()
197 {
198     RenderMedia::updateFromElement();
199     updatePlayer();
200 }
201
202 void RenderVideo::updatePlayer()
203 {
204     updateIntrinsicSize();
205
206     MediaPlayer* mediaPlayer = mediaElement()->player();
207     if (!mediaPlayer)
208         return;
209
210     if (!videoElement()->isActive())
211         return;
212
213     videoElement()->setNeedsCompositingUpdate();
214 }
215
216 LayoutUnit RenderVideo::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
217 {
218     return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
219 }
220
221 LayoutUnit RenderVideo::computeReplacedLogicalHeight() const
222 {
223     return RenderReplaced::computeReplacedLogicalHeight();
224 }
225
226 LayoutUnit RenderVideo::minimumReplacedHeight() const
227 {
228     return RenderReplaced::minimumReplacedHeight();
229 }
230
231 bool RenderVideo::supportsAcceleratedRendering() const
232 {
233     return !!mediaElement()->platformLayer();
234 }
235
236 static const RenderBlock* rendererPlaceholder(const RenderObject* renderer)
237 {
238     RenderObject* parent = renderer->parent();
239     if (!parent)
240         return 0;
241
242     RenderFullScreen* fullScreen = parent->isRenderFullScreen() ? toRenderFullScreen(parent) : 0;
243     if (!fullScreen)
244         return 0;
245
246     return fullScreen->placeholder();
247 }
248
249 LayoutUnit RenderVideo::offsetLeft() const
250 {
251     if (const RenderBlock* block = rendererPlaceholder(this))
252         return block->offsetLeft();
253     return RenderMedia::offsetLeft();
254 }
255
256 LayoutUnit RenderVideo::offsetTop() const
257 {
258     if (const RenderBlock* block = rendererPlaceholder(this))
259         return block->offsetTop();
260     return RenderMedia::offsetTop();
261 }
262
263 LayoutUnit RenderVideo::offsetWidth() const
264 {
265     if (const RenderBlock* block = rendererPlaceholder(this))
266         return block->offsetWidth();
267     return RenderMedia::offsetWidth();
268 }
269
270 LayoutUnit RenderVideo::offsetHeight() const
271 {
272     if (const RenderBlock* block = rendererPlaceholder(this))
273         return block->offsetHeight();
274     return RenderMedia::offsetHeight();
275 }
276
277 CompositingReasons RenderVideo::additionalCompositingReasons() const
278 {
279     if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) {
280         HTMLMediaElement* media = toHTMLMediaElement(node());
281         if (media->isFullscreen())
282             return CompositingReasonVideo;
283     }
284
285     if (shouldDisplayVideo() && supportsAcceleratedRendering())
286         return CompositingReasonVideo;
287
288     return CompositingReasonNone;
289 }
290
291 } // namespace blink