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