• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 WebCore {
41 
42 using namespace HTMLNames;
43 
RenderVideo(HTMLVideoElement * video)44 RenderVideo::RenderVideo(HTMLVideoElement* video)
45     : RenderMedia(video)
46 {
47     setIntrinsicSize(calculateIntrinsicSize());
48 }
49 
~RenderVideo()50 RenderVideo::~RenderVideo()
51 {
52 }
53 
defaultSize()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 
intrinsicSizeChanged()63 void RenderVideo::intrinsicSizeChanged()
64 {
65     if (videoElement()->shouldDisplayPosterImage())
66         RenderMedia::intrinsicSizeChanged();
67     updateIntrinsicSize();
68 }
69 
updateIntrinsicSize()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 
calculateIntrinsicSize()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     blink::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 
imageChanged(WrappedImagePtr newImage,const IntRect * rect)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 
videoBox() const135 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 
shouldDisplayVideo() const144 bool RenderVideo::shouldDisplayVideo() const
145 {
146     return !videoElement()->shouldDisplayPosterImage();
147 }
148 
paintReplaced(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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         mediaPlayer->paint(context, pixelSnappedIntRect(rect));
174 
175     if (clip)
176         context->restore();
177 }
178 
acceleratedRenderingInUse()179 bool RenderVideo::acceleratedRenderingInUse()
180 {
181     blink::WebLayer* webLayer = mediaElement()->platformLayer();
182     return webLayer && !webLayer->isOrphan();
183 }
184 
layout()185 void RenderVideo::layout()
186 {
187     updatePlayer();
188     RenderMedia::layout();
189 }
190 
videoElement() const191 HTMLVideoElement* RenderVideo::videoElement() const
192 {
193     return toHTMLVideoElement(node());
194 }
195 
updateFromElement()196 void RenderVideo::updateFromElement()
197 {
198     RenderMedia::updateFromElement();
199     updatePlayer();
200 }
201 
updatePlayer()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 
computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const216 LayoutUnit RenderVideo::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
217 {
218     return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
219 }
220 
computeReplacedLogicalHeight() const221 LayoutUnit RenderVideo::computeReplacedLogicalHeight() const
222 {
223     return RenderReplaced::computeReplacedLogicalHeight();
224 }
225 
minimumReplacedHeight() const226 LayoutUnit RenderVideo::minimumReplacedHeight() const
227 {
228     return RenderReplaced::minimumReplacedHeight();
229 }
230 
supportsAcceleratedRendering() const231 bool RenderVideo::supportsAcceleratedRendering() const
232 {
233     return !!mediaElement()->platformLayer();
234 }
235 
rendererPlaceholder(const RenderObject * renderer)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 
offsetLeft() const249 LayoutUnit RenderVideo::offsetLeft() const
250 {
251     if (const RenderBlock* block = rendererPlaceholder(this))
252         return block->offsetLeft();
253     return RenderMedia::offsetLeft();
254 }
255 
offsetTop() const256 LayoutUnit RenderVideo::offsetTop() const
257 {
258     if (const RenderBlock* block = rendererPlaceholder(this))
259         return block->offsetTop();
260     return RenderMedia::offsetTop();
261 }
262 
offsetWidth() const263 LayoutUnit RenderVideo::offsetWidth() const
264 {
265     if (const RenderBlock* block = rendererPlaceholder(this))
266         return block->offsetWidth();
267     return RenderMedia::offsetWidth();
268 }
269 
offsetHeight() const270 LayoutUnit RenderVideo::offsetHeight() const
271 {
272     if (const RenderBlock* block = rendererPlaceholder(this))
273         return block->offsetHeight();
274     return RenderMedia::offsetHeight();
275 }
276 
additionalCompositingReasons(CompositingTriggerFlags triggers) const277 CompositingReasons RenderVideo::additionalCompositingReasons(CompositingTriggerFlags triggers) const
278 {
279     if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) {
280         HTMLMediaElement* media = toHTMLMediaElement(node());
281         if (media->isFullscreen())
282             return CompositingReasonVideo;
283     }
284 
285     if ((triggers & VideoTrigger) && shouldDisplayVideo() && supportsAcceleratedRendering())
286         return CompositingReasonVideo;
287 
288     return CompositingReasonNone;
289 }
290 
291 } // namespace WebCore
292