summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/rendering/RenderVideo.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/rendering/RenderVideo.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/rendering/RenderVideo.cpp')
-rw-r--r--Source/WebCore/rendering/RenderVideo.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/RenderVideo.cpp b/Source/WebCore/rendering/RenderVideo.cpp
new file mode 100644
index 0000000..5b82deb
--- /dev/null
+++ b/Source/WebCore/rendering/RenderVideo.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "RenderVideo.h"
+
+#include "Document.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLVideoElement.h"
+#include "MediaPlayer.h"
+#include "RenderView.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderVideo::RenderVideo(HTMLVideoElement* video)
+ : RenderMedia(video)
+{
+ setIntrinsicSize(calculateIntrinsicSize());
+}
+
+RenderVideo::~RenderVideo()
+{
+ if (MediaPlayer* p = player()) {
+ p->setVisible(false);
+ p->setFrameView(0);
+ }
+}
+
+IntSize RenderVideo::defaultSize()
+{
+ // These values are specified in the spec.
+ static const int cDefaultWidth = 300;
+ static const int cDefaultHeight = 150;
+
+ return IntSize(cDefaultWidth, cDefaultHeight);
+}
+
+void RenderVideo::intrinsicSizeChanged()
+{
+ if (videoElement()->shouldDisplayPosterImage())
+ RenderMedia::intrinsicSizeChanged();
+ updateIntrinsicSize();
+}
+
+void RenderVideo::updateIntrinsicSize()
+{
+ IntSize size = calculateIntrinsicSize();
+ size.scale(style()->effectiveZoom());
+
+ // Never set the element size to zero when in a media document.
+ if (size.isEmpty() && node()->ownerDocument() && node()->ownerDocument()->isMediaDocument())
+ return;
+
+ if (size == intrinsicSize())
+ return;
+
+ setIntrinsicSize(size);
+ setPreferredLogicalWidthsDirty(true);
+ setNeedsLayout(true);
+}
+
+IntSize RenderVideo::calculateIntrinsicSize()
+{
+ HTMLVideoElement* video = videoElement();
+
+ // Spec text from 4.8.6
+ //
+ // The intrinsic width of a video element's playback area is the intrinsic width
+ // of the video resource, if that is available; otherwise it is the intrinsic
+ // width of the poster frame, if that is available; otherwise it is 300 CSS pixels.
+ //
+ // The intrinsic height of a video element's playback area is the intrinsic height
+ // of the video resource, if that is available; otherwise it is the intrinsic
+ // height of the poster frame, if that is available; otherwise it is 150 CSS pixels.
+
+ if (player() && video->readyState() >= HTMLVideoElement::HAVE_METADATA)
+ return player()->naturalSize();
+
+ if (video->shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred())
+ return m_cachedImageSize;
+
+ // When the natural size of the video is unavailable, we use the provided
+ // width and height attributes of the video element as the intrinsic size until
+ // better values become available.
+ if (video->hasAttribute(widthAttr) && video->hasAttribute(heightAttr))
+ return IntSize(video->width(), video->height());
+
+ // <video> in standalone media documents should not use the default 300x150
+ // size since they also have audio-only files. By setting the intrinsic
+ // size to 300x1 the video will resize itself in these cases, and audio will
+ // have the correct height (it needs to be > 0 for controls to render properly).
+ if (video->ownerDocument() && video->ownerDocument()->isMediaDocument())
+ return IntSize(defaultSize().width(), 1);
+
+ return defaultSize();
+}
+
+void RenderVideo::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
+{
+ RenderMedia::imageChanged(newImage, rect);
+
+ // Cache the image intrinsic size so we can continue to use it to draw the image correctly
+ // even if we know the video intrinsic size but aren't able to draw video frames yet
+ // (we don't want to scale the poster to the video size without keeping aspect ratio).
+ if (videoElement()->shouldDisplayPosterImage())
+ m_cachedImageSize = intrinsicSize();
+
+ // The intrinsic size is now that of the image, but in case we already had the
+ // intrinsic size of the video we call this here to restore the video size.
+ updateIntrinsicSize();
+}
+
+IntRect RenderVideo::videoBox() const
+{
+ if (m_cachedImageSize.isEmpty() && videoElement()->shouldDisplayPosterImage())
+ return IntRect();
+
+ IntSize elementSize;
+ if (videoElement()->shouldDisplayPosterImage())
+ elementSize = m_cachedImageSize;
+ else
+ elementSize = intrinsicSize();
+
+ IntRect contentRect = contentBoxRect();
+ if (elementSize.isEmpty() || contentRect.isEmpty())
+ return IntRect();
+
+ IntRect renderBox = contentRect;
+ int ratio = renderBox.width() * elementSize.height() - renderBox.height() * elementSize.width();
+ if (ratio > 0) {
+ int newWidth = renderBox.height() * elementSize.width() / elementSize.height();
+ // Just fill the whole area if the difference is one pixel or less (in both sides)
+ if (renderBox.width() - newWidth > 2)
+ renderBox.setWidth(newWidth);
+ renderBox.move((contentRect.width() - renderBox.width()) / 2, 0);
+ } else if (ratio < 0) {
+ int newHeight = renderBox.width() * elementSize.height() / elementSize.width();
+ if (renderBox.height() - newHeight > 2)
+ renderBox.setHeight(newHeight);
+ renderBox.move(0, (contentRect.height() - renderBox.height()) / 2);
+ }
+
+ return renderBox;
+}
+
+bool RenderVideo::shouldDisplayVideo() const
+{
+ return !videoElement()->shouldDisplayPosterImage();
+}
+
+void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
+{
+ MediaPlayer* mediaPlayer = player();
+ bool displayingPoster = videoElement()->shouldDisplayPosterImage();
+
+ if (!displayingPoster) {
+ if (!mediaPlayer)
+ return;
+ updatePlayer();
+ }
+
+ IntRect rect = videoBox();
+ if (rect.isEmpty())
+ return;
+ rect.move(tx, ty);
+
+ if (displayingPoster)
+ paintIntoRect(paintInfo.context, rect);
+ else
+ mediaPlayer->paint(paintInfo.context, rect);
+}
+
+void RenderVideo::layout()
+{
+ RenderMedia::layout();
+ updatePlayer();
+}
+
+HTMLVideoElement* RenderVideo::videoElement() const
+{
+ ASSERT(node()->hasTagName(videoTag));
+ return static_cast<HTMLVideoElement*>(node());
+}
+
+void RenderVideo::updateFromElement()
+{
+ RenderMedia::updateFromElement();
+ updatePlayer();
+}
+
+void RenderVideo::updatePlayer()
+{
+ updateIntrinsicSize();
+
+ MediaPlayer* mediaPlayer = player();
+ if (!mediaPlayer)
+ return;
+
+ if (!videoElement()->inActiveDocument()) {
+ mediaPlayer->setVisible(false);
+ return;
+ }
+
+#if USE(ACCELERATED_COMPOSITING)
+ layer()->contentChanged(RenderLayer::VideoChanged);
+#endif
+
+ IntRect videoBounds = videoBox();
+ mediaPlayer->setFrameView(document()->view());
+ mediaPlayer->setSize(IntSize(videoBounds.width(), videoBounds.height()));
+ mediaPlayer->setVisible(true);
+}
+
+int RenderVideo::computeReplacedLogicalWidth(bool includeMaxWidth) const
+{
+ return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
+}
+
+int RenderVideo::computeReplacedLogicalHeight() const
+{
+ return RenderReplaced::computeReplacedLogicalHeight();
+}
+
+int RenderVideo::minimumReplacedHeight() const
+{
+ return RenderReplaced::minimumReplacedHeight();
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool RenderVideo::supportsAcceleratedRendering() const
+{
+ MediaPlayer* p = player();
+ if (p)
+ return p->supportsAcceleratedRendering();
+
+ return false;
+}
+
+void RenderVideo::acceleratedRenderingStateChanged()
+{
+ MediaPlayer* p = player();
+ if (p)
+ p->acceleratedRenderingStateChanged();
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+} // namespace WebCore
+
+#endif