Reviewed by Mitz.
[WebKit-https.git] / WebCore / rendering / RenderVideo.cpp
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 using namespace std;
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 RenderVideo::RenderVideo(HTMLMediaElement* video)
45     : RenderMedia(video, video->player() ? video->player()->naturalSize() : IntSize(300, 150))
46 {
47 }
48
49 RenderVideo::~RenderVideo()
50 {
51     if (MediaPlayer* p = player()) {
52         p->setVisible(false);
53         p->setParentWidget(0);
54     }
55 }
56     
57 void RenderVideo::videoSizeChanged()
58 {
59     if (!player())
60         return;
61     IntSize size = player()->naturalSize();
62     if (size != intrinsicSize()) {
63         setIntrinsicSize(size);
64         setPrefWidthsDirty(true);
65         setNeedsLayout(true);
66     }
67 }
68
69 IntRect RenderVideo::videoBox() const 
70 {
71     IntRect contentRect = contentBox();
72     
73     if (intrinsicSize().isEmpty() || contentRect.isEmpty())
74         return IntRect();
75
76     IntRect resultRect = contentRect;
77     int ratio = contentRect.width() * intrinsicSize().height() - contentRect.height() * intrinsicSize().width();
78     if (ratio > 0) {
79         int newWidth = contentRect.height() * intrinsicSize().width() / intrinsicSize().height();
80         // Just fill the whole area if the difference is one pixel or less (in both sides)
81         if (resultRect.width() - newWidth > 2)
82             resultRect.setWidth(newWidth);
83         resultRect.move((contentRect.width() - resultRect.width()) / 2, 0);
84     } else if (ratio < 0) {
85         int newHeight = contentRect.width() * intrinsicSize().height() / intrinsicSize().width();
86         if (resultRect.height() - newHeight > 2)
87             resultRect.setHeight(newHeight);
88         resultRect.move(0, (contentRect.height() - resultRect.height()) / 2);
89     }
90     return resultRect;
91 }
92     
93 void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
94 {
95     MediaPlayer* mediaPlayer = player();
96     if (!mediaPlayer)
97         return;
98     updatePlayer();
99     IntRect rect = videoBox();
100     if (rect.isEmpty())
101         return;
102     rect.move(tx, ty);
103     mediaPlayer->paint(paintInfo.context, rect);
104 }
105
106 void RenderVideo::layout()
107 {
108     RenderMedia::layout();
109     updatePlayer();
110 }
111     
112 void RenderVideo::updateFromElement()
113 {
114     RenderMedia::updateFromElement();
115     updatePlayer();
116 }
117
118 void RenderVideo::updatePlayer()
119 {
120     MediaPlayer* mediaPlayer = player();
121     if (!mediaPlayer)
122         return;
123     Document* doc = document();
124     if (doc->inPageCache())
125         return;
126     int x;
127     int y;
128     absolutePosition(x, y);
129     IntRect videoBounds = videoBox(); 
130     videoBounds.move(x, y);
131     mediaPlayer->setParentWidget(doc->view());
132     mediaPlayer->setRect(videoBounds);
133     mediaPlayer->setVisible(true);
134 }
135
136 bool RenderVideo::isWidthSpecified() const
137 {
138     switch (style()->width().type()) {
139         case Fixed:
140         case Percent:
141             return true;
142         default:
143             return false;
144     }
145     ASSERT(false);
146     return false;
147 }
148
149 bool RenderVideo::isHeightSpecified() const
150 {
151     switch (style()->height().type()) {
152         case Fixed:
153         case Percent:
154             return true;
155         default:
156             return false;
157     }
158     ASSERT(false);
159     return false;
160 }
161
162 int RenderVideo::calcReplacedWidth() const
163 {
164     int width;
165     if (isWidthSpecified())
166         width = calcReplacedWidthUsing(style()->width());
167     else
168         width = calcAspectRatioWidth();
169
170     int minW = calcReplacedWidthUsing(style()->minWidth());
171     int maxW = style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
172
173     return max(minW, min(width, maxW));
174 }
175
176 int RenderVideo::calcReplacedHeight() const
177 {
178     int height;
179     if (isHeightSpecified())
180         height = calcReplacedHeightUsing(style()->height());
181     else
182         height = calcAspectRatioHeight();
183
184     int minH = calcReplacedHeightUsing(style()->minHeight());
185     int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
186
187     return max(minH, min(height, maxH));
188 }
189
190 int RenderVideo::calcAspectRatioWidth() const
191 {
192     int intrinsicWidth = intrinsicSize().width();
193     int intrinsicHeight = intrinsicSize().height();
194     if (!intrinsicHeight)
195         return 0;
196     return RenderBox::calcReplacedHeight() * intrinsicWidth / intrinsicHeight;
197 }
198
199 int RenderVideo::calcAspectRatioHeight() const
200 {
201     int intrinsicWidth = intrinsicSize().width();
202     int intrinsicHeight = intrinsicSize().height();
203     if (!intrinsicWidth)
204         return 0;
205     return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
206 }
207
208 void RenderVideo::calcPrefWidths()
209 {
210     ASSERT(prefWidthsDirty());
211
212     m_maxPrefWidth = calcReplacedWidth() + paddingLeft() + paddingRight() + borderLeft() + borderRight();
213
214     if (style()->width().isPercent() || style()->height().isPercent() || 
215         style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
216         style()->minWidth().isPercent() || style()->minHeight().isPercent())
217         m_minPrefWidth = 0;
218     else
219         m_minPrefWidth = m_maxPrefWidth;
220
221     setPrefWidthsDirty(false);
222 }
223
224 } // namespace WebCore
225
226 #endif