• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 #if ENABLE(VIDEO)
29 #include "RenderVideo.h"
30 
31 #include "Document.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLNames.h"
35 #include "HTMLVideoElement.h"
36 #include "MediaPlayer.h"
37 
38 #if USE(ACCELERATED_COMPOSITING)
39 #include "RenderLayer.h"
40 #include "RenderLayerBacking.h"
41 #endif
42 
43 using namespace std;
44 
45 namespace WebCore {
46 
47 using namespace HTMLNames;
48 
49 static const int cDefaultWidth = 300;
50 static const int cDefaultHeight = 150;
51 
RenderVideo(HTMLMediaElement * video)52 RenderVideo::RenderVideo(HTMLMediaElement* video)
53     : RenderMedia(video)
54 {
55     if (video->player())
56         setIntrinsicSize(video->player()->naturalSize());
57     else {
58         // Video in standalone media documents should not use the default 300x150
59         // size since they also have audio thrown at them. By setting the intrinsic
60         // size to 300x1 the video will resize itself in these cases, and audio will
61         // have the correct height (it needs to be > 0 for controls to render properly).
62         if (video->ownerDocument() && video->ownerDocument()->isMediaDocument())
63             setIntrinsicSize(IntSize(cDefaultWidth, 1));
64         else
65             setIntrinsicSize(IntSize(cDefaultWidth, cDefaultHeight));
66     }
67 }
68 
~RenderVideo()69 RenderVideo::~RenderVideo()
70 {
71     if (MediaPlayer* p = player()) {
72         p->setVisible(false);
73         p->setFrameView(0);
74     }
75 }
76 
videoSizeChanged()77 void RenderVideo::videoSizeChanged()
78 {
79     if (!player())
80         return;
81     IntSize size = player()->naturalSize();
82     if (!size.isEmpty() && size != intrinsicSize()) {
83         setIntrinsicSize(size);
84         setPrefWidthsDirty(true);
85         setNeedsLayout(true);
86     }
87 }
88 
videoBox() const89 IntRect RenderVideo::videoBox() const
90 {
91     IntRect contentRect = contentBoxRect();
92 
93     if (intrinsicSize().isEmpty() || contentRect.isEmpty())
94         return IntRect();
95 
96     IntRect resultRect = contentRect;
97     int ratio = contentRect.width() * intrinsicSize().height() - contentRect.height() * intrinsicSize().width();
98     if (ratio > 0) {
99         int newWidth = contentRect.height() * intrinsicSize().width() / intrinsicSize().height();
100         // Just fill the whole area if the difference is one pixel or less (in both sides)
101         if (resultRect.width() - newWidth > 2)
102             resultRect.setWidth(newWidth);
103         resultRect.move((contentRect.width() - resultRect.width()) / 2, 0);
104     } else if (ratio < 0) {
105         int newHeight = contentRect.width() * intrinsicSize().height() / intrinsicSize().width();
106         if (resultRect.height() - newHeight > 2)
107             resultRect.setHeight(newHeight);
108         resultRect.move(0, (contentRect.height() - resultRect.height()) / 2);
109     }
110     return resultRect;
111 }
112 
paintReplaced(PaintInfo & paintInfo,int tx,int ty)113 void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
114 {
115     MediaPlayer* mediaPlayer = player();
116     if (!mediaPlayer)
117         return;
118     updatePlayer();
119     IntRect rect = videoBox();
120     if (rect.isEmpty())
121         return;
122     rect.move(tx, ty);
123     mediaPlayer->paint(paintInfo.context, rect);
124 }
125 
layout()126 void RenderVideo::layout()
127 {
128     RenderMedia::layout();
129     updatePlayer();
130 }
131 
updateFromElement()132 void RenderVideo::updateFromElement()
133 {
134     RenderMedia::updateFromElement();
135     updatePlayer();
136 }
137 
updatePlayer()138 void RenderVideo::updatePlayer()
139 {
140     MediaPlayer* mediaPlayer = player();
141     if (!mediaPlayer)
142         return;
143     if (!mediaElement()->inActiveDocument()) {
144         mediaPlayer->setVisible(false);
145         return;
146     }
147 
148 #if USE(ACCELERATED_COMPOSITING)
149     layer()->rendererContentChanged();
150 #endif
151 
152     IntRect videoBounds = videoBox();
153     mediaPlayer->setFrameView(document()->view());
154     mediaPlayer->setSize(IntSize(videoBounds.width(), videoBounds.height()));
155     mediaPlayer->setVisible(true);
156 }
157 
isWidthSpecified() const158 bool RenderVideo::isWidthSpecified() const
159 {
160     switch (style()->width().type()) {
161         case Fixed:
162         case Percent:
163             return true;
164         case Auto:
165         case Relative: // FIXME: Shouldn't this case return true? It doesn't for images.
166         case Static:
167         case Intrinsic:
168         case MinIntrinsic:
169             return false;
170     }
171     ASSERT(false);
172     return false;
173 }
174 
isHeightSpecified() const175 bool RenderVideo::isHeightSpecified() const
176 {
177     switch (style()->height().type()) {
178         case Fixed:
179         case Percent:
180             return true;
181         case Auto:
182         case Relative: // FIXME: Shouldn't this case return true? It doesn't for images.
183         case Static:
184         case Intrinsic:
185         case MinIntrinsic:
186             return false;
187     }
188     ASSERT(false);
189     return false;
190 }
191 
calcReplacedWidth(bool includeMaxWidth) const192 int RenderVideo::calcReplacedWidth(bool includeMaxWidth) const
193 {
194     int width;
195     if (isWidthSpecified())
196         width = calcReplacedWidthUsing(style()->width());
197     else
198         width = calcAspectRatioWidth() * style()->effectiveZoom();
199 
200     int minW = calcReplacedWidthUsing(style()->minWidth());
201     int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
202 
203     return max(minW, min(width, maxW));
204 }
205 
calcReplacedHeight() const206 int RenderVideo::calcReplacedHeight() const
207 {
208     int height;
209     if (isHeightSpecified())
210         height = calcReplacedHeightUsing(style()->height());
211     else
212         height = calcAspectRatioHeight() * style()->effectiveZoom();
213 
214     int minH = calcReplacedHeightUsing(style()->minHeight());
215     int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
216 
217     return max(minH, min(height, maxH));
218 }
219 
calcAspectRatioWidth() const220 int RenderVideo::calcAspectRatioWidth() const
221 {
222     int intrinsicWidth = intrinsicSize().width();
223     int intrinsicHeight = intrinsicSize().height();
224     if (!intrinsicHeight)
225         return 0;
226     return RenderBox::calcReplacedHeight() * intrinsicWidth / intrinsicHeight;
227 }
228 
calcAspectRatioHeight() const229 int RenderVideo::calcAspectRatioHeight() const
230 {
231     int intrinsicWidth = intrinsicSize().width();
232     int intrinsicHeight = intrinsicSize().height();
233     if (!intrinsicWidth)
234         return 0;
235     return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
236 }
237 
calcPrefWidths()238 void RenderVideo::calcPrefWidths()
239 {
240     ASSERT(prefWidthsDirty());
241 
242     int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight();
243     m_maxPrefWidth = calcReplacedWidth(false) + paddingAndBorders;
244 
245     if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
246         m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0));
247 
248     if (style()->width().isPercent() || style()->height().isPercent() ||
249         style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
250         style()->minWidth().isPercent() || style()->minHeight().isPercent())
251         m_minPrefWidth = 0;
252     else
253         m_minPrefWidth = m_maxPrefWidth;
254 
255     setPrefWidthsDirty(false);
256 }
257 
258 #if USE(ACCELERATED_COMPOSITING)
supportsAcceleratedRendering() const259 bool RenderVideo::supportsAcceleratedRendering() const
260 {
261     MediaPlayer* p = player();
262     if (p)
263         return p->supportsAcceleratedRendering();
264 
265     return false;
266 }
267 
acceleratedRenderingStateChanged()268 void RenderVideo::acceleratedRenderingStateChanged()
269 {
270     MediaPlayer* p = player();
271     if (p)
272         p->acceleratedRenderingStateChanged();
273 }
274 
videoGraphicsLayer() const275 GraphicsLayer* RenderVideo::videoGraphicsLayer() const
276 {
277     if (hasLayer() && layer()->isComposited())
278         return layer()->backing()->graphicsLayer();
279 
280     return 0;
281 }
282 #endif  // USE(ACCELERATED_COMPOSITING)
283 
284 } // namespace WebCore
285 
286 #endif
287