|
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 #if ENABLE(VIDEO) |
|
29 #include "RenderMedia.h" |
|
30 |
|
31 #include "EventNames.h" |
|
32 #include "FloatConversion.h" |
|
33 #include "HTMLNames.h" |
|
34 #include "MediaControlElements.h" |
|
35 #include "MouseEvent.h" |
|
36 #include "Page.h" |
|
37 #include "RenderTheme.h" |
|
38 #include <wtf/CurrentTime.h> |
|
39 #include <wtf/MathExtras.h> |
|
40 |
|
41 using namespace std; |
|
42 |
|
43 namespace WebCore { |
|
44 |
|
45 using namespace HTMLNames; |
|
46 |
|
47 static const double cTimeUpdateRepeatDelay = 0.2; |
|
48 static const double cOpacityAnimationRepeatDelay = 0.05; |
|
49 |
|
50 RenderMedia::RenderMedia(HTMLMediaElement* video) |
|
51 : RenderImage(video) |
|
52 , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired) |
|
53 , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) |
|
54 , m_mouseOver(false) |
|
55 , m_opacityAnimationStartTime(0) |
|
56 , m_opacityAnimationDuration(0) |
|
57 , m_opacityAnimationFrom(0) |
|
58 , m_opacityAnimationTo(1.0f) |
|
59 { |
|
60 } |
|
61 |
|
62 RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize) |
|
63 : RenderImage(video) |
|
64 , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired) |
|
65 , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) |
|
66 , m_mouseOver(false) |
|
67 , m_opacityAnimationStartTime(0) |
|
68 , m_opacityAnimationDuration(0) |
|
69 , m_opacityAnimationFrom(0) |
|
70 , m_opacityAnimationTo(1.0f) |
|
71 { |
|
72 setIntrinsicSize(intrinsicSize); |
|
73 } |
|
74 |
|
75 RenderMedia::~RenderMedia() |
|
76 { |
|
77 } |
|
78 |
|
79 void RenderMedia::destroy() |
|
80 { |
|
81 if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) { |
|
82 |
|
83 // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach() |
|
84 // when display: style changes |
|
85 m_panel->detach(); |
|
86 |
|
87 removeChild(m_controlsShadowRoot->renderer()); |
|
88 m_controlsShadowRoot->detach(); |
|
89 m_controlsShadowRoot = 0; |
|
90 } |
|
91 RenderImage::destroy(); |
|
92 } |
|
93 |
|
94 HTMLMediaElement* RenderMedia::mediaElement() const |
|
95 { |
|
96 return static_cast<HTMLMediaElement*>(node()); |
|
97 } |
|
98 |
|
99 MediaPlayer* RenderMedia::player() const |
|
100 { |
|
101 return mediaElement()->player(); |
|
102 } |
|
103 |
|
104 void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) |
|
105 { |
|
106 RenderImage::styleDidChange(diff, oldStyle); |
|
107 |
|
108 if (m_controlsShadowRoot) { |
|
109 if (m_panel) |
|
110 m_panel->updateStyle(); |
|
111 if (m_muteButton) |
|
112 m_muteButton->updateStyle(); |
|
113 if (m_playButton) |
|
114 m_playButton->updateStyle(); |
|
115 if (m_seekBackButton) |
|
116 m_seekBackButton->updateStyle(); |
|
117 if (m_seekForwardButton) |
|
118 m_seekForwardButton->updateStyle(); |
|
119 if (m_rewindButton) |
|
120 m_rewindButton->updateStyle(); |
|
121 if (m_returnToRealtimeButton) |
|
122 m_returnToRealtimeButton->updateStyle(); |
|
123 if (m_toggleClosedCaptionsButton) |
|
124 m_toggleClosedCaptionsButton->updateStyle(); |
|
125 if (m_statusDisplay) |
|
126 m_statusDisplay->updateStyle(); |
|
127 if (m_timelineContainer) |
|
128 m_timelineContainer->updateStyle(); |
|
129 if (m_timeline) |
|
130 m_timeline->updateStyle(); |
|
131 if (m_fullscreenButton) |
|
132 m_fullscreenButton->updateStyle(); |
|
133 if (m_currentTimeDisplay) |
|
134 m_currentTimeDisplay->updateStyle(); |
|
135 if (m_timeRemainingDisplay) |
|
136 m_timeRemainingDisplay->updateStyle(); |
|
137 if (m_volumeSliderContainer) |
|
138 m_volumeSliderContainer->updateStyle(); |
|
139 if (m_volumeSliderMuteButton) |
|
140 m_volumeSliderMuteButton->updateStyle(); |
|
141 if (m_volumeSlider) |
|
142 m_volumeSlider->updateStyle(); |
|
143 } |
|
144 } |
|
145 |
|
146 void RenderMedia::layout() |
|
147 { |
|
148 IntSize oldSize = contentBoxRect().size(); |
|
149 |
|
150 RenderImage::layout(); |
|
151 |
|
152 RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0; |
|
153 if (!controlsRenderer) |
|
154 return; |
|
155 IntSize newSize = contentBoxRect().size(); |
|
156 if (newSize != oldSize || controlsRenderer->needsLayout()) { |
|
157 |
|
158 if (m_currentTimeDisplay && m_timeRemainingDisplay) { |
|
159 bool shouldShowTimeDisplays = shouldShowTimeDisplayControls(); |
|
160 m_currentTimeDisplay->setVisible(shouldShowTimeDisplays); |
|
161 m_timeRemainingDisplay->setVisible(shouldShowTimeDisplays); |
|
162 } |
|
163 |
|
164 controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); |
|
165 controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); |
|
166 controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); |
|
167 controlsRenderer->setNeedsLayout(true, false); |
|
168 controlsRenderer->layout(); |
|
169 setChildNeedsLayout(false); |
|
170 } |
|
171 } |
|
172 |
|
173 void RenderMedia::createControlsShadowRoot() |
|
174 { |
|
175 ASSERT(!m_controlsShadowRoot); |
|
176 m_controlsShadowRoot = MediaControlShadowRootElement::create(mediaElement()); |
|
177 addChild(m_controlsShadowRoot->renderer()); |
|
178 } |
|
179 |
|
180 void RenderMedia::createPanel() |
|
181 { |
|
182 ASSERT(!m_panel); |
|
183 m_panel = MediaControlElement::create(mediaElement(), MEDIA_CONTROLS_PANEL); |
|
184 m_panel->attachToParent(m_controlsShadowRoot.get()); |
|
185 } |
|
186 |
|
187 void RenderMedia::createMuteButton() |
|
188 { |
|
189 ASSERT(!m_muteButton); |
|
190 m_muteButton = MediaControlMuteButtonElement::create(mediaElement(), MediaControlMuteButtonElement::Controller); |
|
191 m_muteButton->attachToParent(m_panel.get()); |
|
192 } |
|
193 |
|
194 void RenderMedia::createPlayButton() |
|
195 { |
|
196 ASSERT(!m_playButton); |
|
197 m_playButton = MediaControlPlayButtonElement::create(mediaElement()); |
|
198 m_playButton->attachToParent(m_panel.get()); |
|
199 } |
|
200 |
|
201 void RenderMedia::createSeekBackButton() |
|
202 { |
|
203 ASSERT(!m_seekBackButton); |
|
204 m_seekBackButton = MediaControlSeekButtonElement::create(mediaElement(), MEDIA_CONTROLS_SEEK_BACK_BUTTON); |
|
205 m_seekBackButton->attachToParent(m_panel.get()); |
|
206 } |
|
207 |
|
208 void RenderMedia::createSeekForwardButton() |
|
209 { |
|
210 ASSERT(!m_seekForwardButton); |
|
211 m_seekForwardButton = MediaControlSeekButtonElement::create(mediaElement(), MEDIA_CONTROLS_SEEK_FORWARD_BUTTON); |
|
212 m_seekForwardButton->attachToParent(m_panel.get()); |
|
213 } |
|
214 |
|
215 void RenderMedia::createRewindButton() |
|
216 { |
|
217 ASSERT(!m_rewindButton); |
|
218 m_rewindButton = MediaControlRewindButtonElement::create(mediaElement()); |
|
219 m_rewindButton->attachToParent(m_panel.get()); |
|
220 } |
|
221 |
|
222 void RenderMedia::createReturnToRealtimeButton() |
|
223 { |
|
224 ASSERT(!m_returnToRealtimeButton); |
|
225 m_returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(mediaElement()); |
|
226 m_returnToRealtimeButton->attachToParent(m_panel.get()); |
|
227 } |
|
228 |
|
229 void RenderMedia::createToggleClosedCaptionsButton() |
|
230 { |
|
231 ASSERT(!m_toggleClosedCaptionsButton); |
|
232 m_toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(mediaElement()); |
|
233 m_toggleClosedCaptionsButton->attachToParent(m_panel.get()); |
|
234 } |
|
235 |
|
236 void RenderMedia::createStatusDisplay() |
|
237 { |
|
238 ASSERT(!m_statusDisplay); |
|
239 m_statusDisplay = MediaControlStatusDisplayElement::create(mediaElement()); |
|
240 m_statusDisplay->attachToParent(m_panel.get()); |
|
241 } |
|
242 |
|
243 void RenderMedia::createTimelineContainer() |
|
244 { |
|
245 ASSERT(!m_timelineContainer); |
|
246 m_timelineContainer = MediaControlTimelineContainerElement::create(mediaElement()); |
|
247 m_timelineContainer->attachToParent(m_panel.get()); |
|
248 } |
|
249 |
|
250 void RenderMedia::createTimeline() |
|
251 { |
|
252 ASSERT(!m_timeline); |
|
253 m_timeline = MediaControlTimelineElement::create(mediaElement()); |
|
254 m_timeline->setAttribute(precisionAttr, "float"); |
|
255 m_timeline->attachToParent(m_timelineContainer.get()); |
|
256 } |
|
257 |
|
258 void RenderMedia::createVolumeSliderContainer() |
|
259 { |
|
260 ASSERT(!m_volumeSliderContainer); |
|
261 m_volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(mediaElement()); |
|
262 m_volumeSliderContainer->attachToParent(m_panel.get()); |
|
263 } |
|
264 |
|
265 void RenderMedia::createVolumeSlider() |
|
266 { |
|
267 ASSERT(!m_volumeSlider); |
|
268 m_volumeSlider = MediaControlVolumeSliderElement::create(mediaElement()); |
|
269 m_volumeSlider->setAttribute(precisionAttr, "float"); |
|
270 m_volumeSlider->setAttribute(maxAttr, "1"); |
|
271 m_volumeSlider->setAttribute(valueAttr, String::number(mediaElement()->volume())); |
|
272 m_volumeSlider->attachToParent(m_volumeSliderContainer.get()); |
|
273 } |
|
274 |
|
275 void RenderMedia::createVolumeSliderMuteButton() |
|
276 { |
|
277 ASSERT(!m_volumeSliderMuteButton); |
|
278 m_volumeSliderMuteButton = MediaControlMuteButtonElement::create(mediaElement(), MediaControlMuteButtonElement::VolumeSlider); |
|
279 m_volumeSliderMuteButton->attachToParent(m_volumeSliderContainer.get()); |
|
280 |
|
281 } |
|
282 |
|
283 void RenderMedia::createCurrentTimeDisplay() |
|
284 { |
|
285 ASSERT(!m_currentTimeDisplay); |
|
286 m_currentTimeDisplay = MediaControlTimeDisplayElement::create(mediaElement(), MEDIA_CONTROLS_CURRENT_TIME_DISPLAY); |
|
287 m_currentTimeDisplay->attachToParent(m_timelineContainer.get()); |
|
288 } |
|
289 |
|
290 void RenderMedia::createTimeRemainingDisplay() |
|
291 { |
|
292 ASSERT(!m_timeRemainingDisplay); |
|
293 m_timeRemainingDisplay = MediaControlTimeDisplayElement::create(mediaElement(), MEDIA_CONTROLS_TIME_REMAINING_DISPLAY); |
|
294 m_timeRemainingDisplay->attachToParent(m_timelineContainer.get()); |
|
295 } |
|
296 |
|
297 void RenderMedia::createFullscreenButton() |
|
298 { |
|
299 ASSERT(!m_fullscreenButton); |
|
300 m_fullscreenButton = MediaControlFullscreenButtonElement::create(mediaElement()); |
|
301 m_fullscreenButton->attachToParent(m_panel.get()); |
|
302 } |
|
303 |
|
304 void RenderMedia::updateFromElement() |
|
305 { |
|
306 updateControls(); |
|
307 } |
|
308 |
|
309 void RenderMedia::updateControls() |
|
310 { |
|
311 HTMLMediaElement* media = mediaElement(); |
|
312 if (!media->controls() || !media->inActiveDocument()) { |
|
313 if (m_controlsShadowRoot) { |
|
314 m_controlsShadowRoot->detach(); |
|
315 m_panel = 0; |
|
316 m_muteButton = 0; |
|
317 m_playButton = 0; |
|
318 m_statusDisplay = 0; |
|
319 m_timelineContainer = 0; |
|
320 m_timeline = 0; |
|
321 m_seekBackButton = 0; |
|
322 m_seekForwardButton = 0; |
|
323 m_rewindButton = 0; |
|
324 m_returnToRealtimeButton = 0; |
|
325 m_currentTimeDisplay = 0; |
|
326 m_timeRemainingDisplay = 0; |
|
327 m_fullscreenButton = 0; |
|
328 m_volumeSliderContainer = 0; |
|
329 m_volumeSlider = 0; |
|
330 m_volumeSliderMuteButton = 0; |
|
331 m_controlsShadowRoot = 0; |
|
332 m_toggleClosedCaptionsButton = 0; |
|
333 } |
|
334 m_opacityAnimationTo = 1.0f; |
|
335 m_opacityAnimationTimer.stop(); |
|
336 m_timeUpdateTimer.stop(); |
|
337 return; |
|
338 } |
|
339 |
|
340 if (!m_controlsShadowRoot) { |
|
341 createControlsShadowRoot(); |
|
342 createPanel(); |
|
343 if (m_panel) { |
|
344 createRewindButton(); |
|
345 createPlayButton(); |
|
346 createReturnToRealtimeButton(); |
|
347 createStatusDisplay(); |
|
348 createTimelineContainer(); |
|
349 if (m_timelineContainer) { |
|
350 createCurrentTimeDisplay(); |
|
351 createTimeline(); |
|
352 createTimeRemainingDisplay(); |
|
353 } |
|
354 createSeekBackButton(); |
|
355 createSeekForwardButton(); |
|
356 createToggleClosedCaptionsButton(); |
|
357 createFullscreenButton(); |
|
358 createMuteButton(); |
|
359 createVolumeSliderContainer(); |
|
360 if (m_volumeSliderContainer) { |
|
361 createVolumeSlider(); |
|
362 createVolumeSliderMuteButton(); |
|
363 } |
|
364 m_panel->attach(); |
|
365 } |
|
366 } |
|
367 |
|
368 if (media->canPlay()) { |
|
369 if (m_timeUpdateTimer.isActive()) |
|
370 m_timeUpdateTimer.stop(); |
|
371 } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE) { |
|
372 m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay); |
|
373 } |
|
374 |
|
375 |
|
376 if (m_panel) { |
|
377 // update() might alter the opacity of the element, especially if we are in the middle |
|
378 // of an animation. This is the only element concerned as we animate only this element. |
|
379 float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0; |
|
380 m_panel->update(); |
|
381 changeOpacity(m_panel.get(), opacityBeforeChangingStyle); |
|
382 } |
|
383 if (m_muteButton) |
|
384 m_muteButton->update(); |
|
385 if (m_playButton) |
|
386 m_playButton->update(); |
|
387 if (m_timelineContainer) |
|
388 m_timelineContainer->update(); |
|
389 if (m_volumeSliderContainer) |
|
390 m_volumeSliderContainer->update(); |
|
391 if (m_timeline) |
|
392 m_timeline->update(); |
|
393 if (m_currentTimeDisplay) |
|
394 m_currentTimeDisplay->update(); |
|
395 if (m_timeRemainingDisplay) |
|
396 m_timeRemainingDisplay->update(); |
|
397 if (m_seekBackButton) |
|
398 m_seekBackButton->update(); |
|
399 if (m_seekForwardButton) |
|
400 m_seekForwardButton->update(); |
|
401 if (m_rewindButton) |
|
402 m_rewindButton->update(); |
|
403 if (m_returnToRealtimeButton) |
|
404 m_returnToRealtimeButton->update(); |
|
405 if (m_toggleClosedCaptionsButton) |
|
406 m_toggleClosedCaptionsButton->update(); |
|
407 if (m_statusDisplay) |
|
408 m_statusDisplay->update(); |
|
409 if (m_fullscreenButton) |
|
410 m_fullscreenButton->update(); |
|
411 if (m_volumeSlider) |
|
412 m_volumeSlider->update(); |
|
413 if (m_volumeSliderMuteButton) |
|
414 m_volumeSliderMuteButton->update(); |
|
415 |
|
416 updateTimeDisplay(); |
|
417 updateControlVisibility(); |
|
418 } |
|
419 |
|
420 void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*) |
|
421 { |
|
422 if (m_timeline) |
|
423 m_timeline->update(false); |
|
424 updateTimeDisplay(); |
|
425 } |
|
426 |
|
427 void RenderMedia::updateTimeDisplay() |
|
428 { |
|
429 if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE) |
|
430 return; |
|
431 |
|
432 float now = mediaElement()->currentTime(); |
|
433 float duration = mediaElement()->duration(); |
|
434 |
|
435 // Allow the theme to format the time |
|
436 ExceptionCode ec; |
|
437 m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec); |
|
438 m_currentTimeDisplay->setCurrentValue(now); |
|
439 m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec); |
|
440 m_timeRemainingDisplay->setCurrentValue(now - duration); |
|
441 } |
|
442 |
|
443 void RenderMedia::updateControlVisibility() |
|
444 { |
|
445 if (!m_panel || !m_panel->renderer()) |
|
446 return; |
|
447 |
|
448 // Don't fade for audio controls. |
|
449 HTMLMediaElement* media = mediaElement(); |
|
450 if (!media->hasVideo()) |
|
451 return; |
|
452 |
|
453 // Don't fade if the media element is not visible |
|
454 if (style()->visibility() != VISIBLE) |
|
455 return; |
|
456 |
|
457 bool shouldHideController = !m_mouseOver && !media->canPlay(); |
|
458 |
|
459 // Do fading manually, css animations don't work with shadow trees |
|
460 |
|
461 float animateFrom = m_panel->renderer()->style()->opacity(); |
|
462 float animateTo = shouldHideController ? 0.0f : 1.0f; |
|
463 |
|
464 if (animateFrom == animateTo) |
|
465 return; |
|
466 |
|
467 if (m_opacityAnimationTimer.isActive()) { |
|
468 if (m_opacityAnimationTo == animateTo) |
|
469 return; |
|
470 m_opacityAnimationTimer.stop(); |
|
471 } |
|
472 |
|
473 if (animateFrom < animateTo) |
|
474 m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration(); |
|
475 else |
|
476 m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration(); |
|
477 |
|
478 m_opacityAnimationFrom = animateFrom; |
|
479 m_opacityAnimationTo = animateTo; |
|
480 |
|
481 m_opacityAnimationStartTime = currentTime(); |
|
482 m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay); |
|
483 } |
|
484 |
|
485 void RenderMedia::changeOpacity(HTMLElement* e, float opacity) |
|
486 { |
|
487 if (!e || !e->renderer() || !e->renderer()->style()) |
|
488 return; |
|
489 RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style()); |
|
490 s->setOpacity(opacity); |
|
491 // z-index can't be auto if opacity is used |
|
492 s->setZIndex(0); |
|
493 e->renderer()->setStyle(s.release()); |
|
494 } |
|
495 |
|
496 void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*) |
|
497 { |
|
498 double time = currentTime() - m_opacityAnimationStartTime; |
|
499 if (time >= m_opacityAnimationDuration) { |
|
500 time = m_opacityAnimationDuration; |
|
501 m_opacityAnimationTimer.stop(); |
|
502 } |
|
503 float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration); |
|
504 changeOpacity(m_panel.get(), opacity); |
|
505 } |
|
506 |
|
507 void RenderMedia::updateVolumeSliderContainer(bool visible) |
|
508 { |
|
509 if (!mediaElement()->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider) |
|
510 return; |
|
511 |
|
512 if (visible && !m_volumeSliderContainer->isVisible()) { |
|
513 if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox()) |
|
514 return; |
|
515 |
|
516 RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement(); |
|
517 int height = s->height().isPercent() ? 0 : s->height().value(); |
|
518 int width = s->width().isPercent() ? 0 : s->width().value(); |
|
519 IntPoint offset = document()->page()->theme()->volumeSliderOffsetFromMuteButton(m_muteButton->renderer()->node(), IntSize(width, height)); |
|
520 int x = offset.x() + m_muteButton->renderBox()->offsetLeft(); |
|
521 int y = offset.y() + m_muteButton->renderBox()->offsetTop(); |
|
522 |
|
523 m_volumeSliderContainer->setPosition(x, y); |
|
524 m_volumeSliderContainer->setVisible(true); |
|
525 m_volumeSliderContainer->update(); |
|
526 m_volumeSlider->update(); |
|
527 } else if (!visible && m_volumeSliderContainer->isVisible()) { |
|
528 m_volumeSliderContainer->setVisible(false); |
|
529 m_volumeSliderContainer->updateStyle(); |
|
530 } |
|
531 } |
|
532 |
|
533 void RenderMedia::forwardEvent(Event* event) |
|
534 { |
|
535 if (event->isMouseEvent() && m_controlsShadowRoot) { |
|
536 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); |
|
537 IntPoint point(mouseEvent->absoluteLocation()); |
|
538 |
|
539 bool defaultHandled = false; |
|
540 if (m_volumeSliderMuteButton && m_volumeSliderMuteButton->hitTest(point)) { |
|
541 m_volumeSliderMuteButton->defaultEventHandler(event); |
|
542 defaultHandled = event->defaultHandled(); |
|
543 } |
|
544 |
|
545 bool showVolumeSlider = false; |
|
546 if (!defaultHandled && m_muteButton && m_muteButton->hitTest(point)) { |
|
547 m_muteButton->defaultEventHandler(event); |
|
548 if (event->type() != eventNames().mouseoutEvent) |
|
549 showVolumeSlider = true; |
|
550 } |
|
551 |
|
552 if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point)) |
|
553 showVolumeSlider = true; |
|
554 |
|
555 if (m_volumeSlider && m_volumeSlider->hitTest(point)) { |
|
556 m_volumeSlider->defaultEventHandler(event); |
|
557 showVolumeSlider = true; |
|
558 } |
|
559 |
|
560 updateVolumeSliderContainer(showVolumeSlider); |
|
561 |
|
562 if (m_playButton && m_playButton->hitTest(point)) |
|
563 m_playButton->defaultEventHandler(event); |
|
564 |
|
565 if (m_seekBackButton && m_seekBackButton->hitTest(point)) |
|
566 m_seekBackButton->defaultEventHandler(event); |
|
567 |
|
568 if (m_seekForwardButton && m_seekForwardButton->hitTest(point)) |
|
569 m_seekForwardButton->defaultEventHandler(event); |
|
570 |
|
571 if (m_rewindButton && m_rewindButton->hitTest(point)) |
|
572 m_rewindButton->defaultEventHandler(event); |
|
573 |
|
574 if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point)) |
|
575 m_returnToRealtimeButton->defaultEventHandler(event); |
|
576 |
|
577 if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point)) |
|
578 m_toggleClosedCaptionsButton->defaultEventHandler(event); |
|
579 |
|
580 if (m_timeline && m_timeline->hitTest(point)) |
|
581 m_timeline->defaultEventHandler(event); |
|
582 |
|
583 if (m_fullscreenButton && m_fullscreenButton->hitTest(point)) |
|
584 m_fullscreenButton->defaultEventHandler(event); |
|
585 |
|
586 if (event->type() == eventNames().mouseoverEvent) { |
|
587 m_mouseOver = true; |
|
588 updateControlVisibility(); |
|
589 } |
|
590 if (event->type() == eventNames().mouseoutEvent) { |
|
591 // When the scrollbar thumb captures mouse events, we should treat the mouse as still being over our renderer if the new target is a descendant |
|
592 Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0; |
|
593 RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0; |
|
594 m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(this); |
|
595 updateControlVisibility(); |
|
596 } |
|
597 } |
|
598 } |
|
599 |
|
600 int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const |
|
601 { |
|
602 int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf); |
|
603 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) |
|
604 return bottom; |
|
605 |
|
606 return max(bottom, m_controlsShadowRoot->renderBox()->y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf)); |
|
607 } |
|
608 |
|
609 int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const |
|
610 { |
|
611 int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf); |
|
612 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) |
|
613 return right; |
|
614 |
|
615 return max(right, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf)); |
|
616 } |
|
617 |
|
618 int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const |
|
619 { |
|
620 int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf); |
|
621 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) |
|
622 return left; |
|
623 |
|
624 return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf)); |
|
625 } |
|
626 |
|
627 |
|
628 // We want the timeline slider to be at least 100 pixels wide. |
|
629 static const int minWidthToDisplayTimeDisplays = 16 + 16 + 45 + 100 + 45 + 16 + 1; |
|
630 |
|
631 bool RenderMedia::shouldShowTimeDisplayControls() const |
|
632 { |
|
633 if (!m_currentTimeDisplay && !m_timeRemainingDisplay) |
|
634 return false; |
|
635 |
|
636 int width = mediaElement()->renderBox()->width(); |
|
637 return width >= minWidthToDisplayTimeDisplays * style()->effectiveZoom(); |
|
638 } |
|
639 |
|
640 } // namespace WebCore |
|
641 |
|
642 #endif |