Home | History | Annotate | Download | only in rendering
      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 
     45 RenderVideo::RenderVideo(HTMLVideoElement* video)
     46     : RenderMedia(video)
     47 {
     48     setIntrinsicSize(calculateIntrinsicSize());
     49 }
     50 
     51 RenderVideo::~RenderVideo()
     52 {
     53 }
     54 
     55 IntSize RenderVideo::defaultSize()
     56 {
     57     return IntSize(defaultWidth, defaultHeight);
     58 }
     59 
     60 void RenderVideo::intrinsicSizeChanged()
     61 {
     62     if (videoElement()->shouldDisplayPosterImage())
     63         RenderMedia::intrinsicSizeChanged();
     64     updateIntrinsicSize();
     65 }
     66 
     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 
     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 
    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 
    132 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 
    141 bool RenderVideo::shouldDisplayVideo() const
    142 {
    143     return !videoElement()->shouldDisplayPosterImage();
    144 }
    145 
    146 void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    147 {
    148     VideoPainter(*this).paintReplaced(paintInfo, paintOffset);
    149 }
    150 
    151 bool RenderVideo::acceleratedRenderingInUse()
    152 {
    153     WebLayer* webLayer = mediaElement()->platformLayer();
    154     return webLayer && !webLayer->isOrphan();
    155 }
    156 
    157 void RenderVideo::layout()
    158 {
    159     updatePlayer();
    160     RenderMedia::layout();
    161 }
    162 
    163 HTMLVideoElement* RenderVideo::videoElement() const
    164 {
    165     return toHTMLVideoElement(node());
    166 }
    167 
    168 void RenderVideo::updateFromElement()
    169 {
    170     RenderMedia::updateFromElement();
    171     updatePlayer();
    172 }
    173 
    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 
    188 LayoutUnit RenderVideo::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
    189 {
    190     return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
    191 }
    192 
    193 LayoutUnit RenderVideo::computeReplacedLogicalHeight() const
    194 {
    195     return RenderReplaced::computeReplacedLogicalHeight();
    196 }
    197 
    198 LayoutUnit RenderVideo::minimumReplacedHeight() const
    199 {
    200     return RenderReplaced::minimumReplacedHeight();
    201 }
    202 
    203 bool RenderVideo::supportsAcceleratedRendering() const
    204 {
    205     return !!mediaElement()->platformLayer();
    206 }
    207 
    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 
    221 LayoutUnit RenderVideo::offsetLeft() const
    222 {
    223     if (const RenderBlock* block = rendererPlaceholder(this))
    224         return block->offsetLeft();
    225     return RenderMedia::offsetLeft();
    226 }
    227 
    228 LayoutUnit RenderVideo::offsetTop() const
    229 {
    230     if (const RenderBlock* block = rendererPlaceholder(this))
    231         return block->offsetTop();
    232     return RenderMedia::offsetTop();
    233 }
    234 
    235 LayoutUnit RenderVideo::offsetWidth() const
    236 {
    237     if (const RenderBlock* block = rendererPlaceholder(this))
    238         return block->offsetWidth();
    239     return RenderMedia::offsetWidth();
    240 }
    241 
    242 LayoutUnit RenderVideo::offsetHeight() const
    243 {
    244     if (const RenderBlock* block = rendererPlaceholder(this))
    245         return block->offsetHeight();
    246     return RenderMedia::offsetHeight();
    247 }
    248 
    249 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