2 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "core/rendering/RenderVideo.h"
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"
42 using namespace HTMLNames;
44 RenderVideo::RenderVideo(HTMLVideoElement* video)
47 setIntrinsicSize(calculateIntrinsicSize());
50 RenderVideo::~RenderVideo()
54 IntSize RenderVideo::defaultSize()
56 // These values are specified in the spec.
57 static const int cDefaultWidth = 300;
58 static const int cDefaultHeight = 150;
60 return IntSize(cDefaultWidth, cDefaultHeight);
63 void RenderVideo::intrinsicSizeChanged()
65 if (videoElement()->shouldDisplayPosterImage())
66 RenderMedia::intrinsicSizeChanged();
67 updateIntrinsicSize();
70 void RenderVideo::updateIntrinsicSize()
72 LayoutSize size = calculateIntrinsicSize();
73 size.scale(style()->effectiveZoom());
75 // Never set the element size to zero when in a media document.
76 if (size.isEmpty() && node()->ownerDocument() && node()->ownerDocument()->isMediaDocument())
79 if (size == intrinsicSize())
82 setIntrinsicSize(size);
83 setPreferredLogicalWidthsDirty();
84 setNeedsLayoutAndFullPaintInvalidation();
87 LayoutSize RenderVideo::calculateIntrinsicSize()
89 HTMLVideoElement* video = videoElement();
91 // Spec text from 4.8.6
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.
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();
107 if (video->shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred())
108 return m_cachedImageSize;
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);
117 return defaultSize();
120 void RenderVideo::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
122 RenderMedia::imageChanged(newImage, rect);
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();
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();
135 IntRect RenderVideo::videoBox() const
137 const LayoutSize* overriddenIntrinsicSize = 0;
138 if (videoElement()->shouldDisplayPosterImage())
139 overriddenIntrinsicSize = &m_cachedImageSize;
141 return pixelSnappedIntRect(replacedContentRect(overriddenIntrinsicSize));
144 bool RenderVideo::shouldDisplayVideo() const
146 return !videoElement()->shouldDisplayPosterImage();
149 void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
151 MediaPlayer* mediaPlayer = mediaElement()->player();
152 bool displayingPoster = videoElement()->shouldDisplayPosterImage();
153 if (!displayingPoster && !mediaPlayer)
156 LayoutRect rect = videoBox();
159 rect.moveBy(paintOffset);
161 LayoutRect contentRect = contentBoxRect();
162 contentRect.moveBy(paintOffset);
163 GraphicsContext* context = paintInfo.context;
164 bool clip = !contentRect.contains(rect);
167 context->clip(contentRect);
170 if (displayingPoster)
171 paintIntoRect(context, rect);
172 else if ((document().view() && document().view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) || !acceleratedRenderingInUse())
173 videoElement()->paintCurrentFrameInContext(context, pixelSnappedIntRect(rect));
179 bool RenderVideo::acceleratedRenderingInUse()
181 WebLayer* webLayer = mediaElement()->platformLayer();
182 return webLayer && !webLayer->isOrphan();
185 void RenderVideo::layout()
188 RenderMedia::layout();
191 HTMLVideoElement* RenderVideo::videoElement() const
193 return toHTMLVideoElement(node());
196 void RenderVideo::updateFromElement()
198 RenderMedia::updateFromElement();
202 void RenderVideo::updatePlayer()
204 updateIntrinsicSize();
206 MediaPlayer* mediaPlayer = mediaElement()->player();
210 if (!videoElement()->isActive())
213 videoElement()->setNeedsCompositingUpdate();
216 LayoutUnit RenderVideo::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
218 return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
221 LayoutUnit RenderVideo::computeReplacedLogicalHeight() const
223 return RenderReplaced::computeReplacedLogicalHeight();
226 LayoutUnit RenderVideo::minimumReplacedHeight() const
228 return RenderReplaced::minimumReplacedHeight();
231 bool RenderVideo::supportsAcceleratedRendering() const
233 return !!mediaElement()->platformLayer();
236 static const RenderBlock* rendererPlaceholder(const RenderObject* renderer)
238 RenderObject* parent = renderer->parent();
242 RenderFullScreen* fullScreen = parent->isRenderFullScreen() ? toRenderFullScreen(parent) : 0;
246 return fullScreen->placeholder();
249 LayoutUnit RenderVideo::offsetLeft() const
251 if (const RenderBlock* block = rendererPlaceholder(this))
252 return block->offsetLeft();
253 return RenderMedia::offsetLeft();
256 LayoutUnit RenderVideo::offsetTop() const
258 if (const RenderBlock* block = rendererPlaceholder(this))
259 return block->offsetTop();
260 return RenderMedia::offsetTop();
263 LayoutUnit RenderVideo::offsetWidth() const
265 if (const RenderBlock* block = rendererPlaceholder(this))
266 return block->offsetWidth();
267 return RenderMedia::offsetWidth();
270 LayoutUnit RenderVideo::offsetHeight() const
272 if (const RenderBlock* block = rendererPlaceholder(this))
273 return block->offsetHeight();
274 return RenderMedia::offsetHeight();
277 CompositingReasons RenderVideo::additionalCompositingReasons() const
279 if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) {
280 HTMLMediaElement* media = toHTMLMediaElement(node());
281 if (media->isFullscreen())
282 return CompositingReasonVideo;
285 if (shouldDisplayVideo() && supportsAcceleratedRendering())
286 return CompositingReasonVideo;
288 return CompositingReasonNone;