1/* 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28 29#if ENABLE(VIDEO) 30#include "MediaControlsApple.h" 31 32#include "CSSValueKeywords.h" 33#include "ExceptionCodePlaceholder.h" 34#include "HTMLNames.h" 35#include "WheelEvent.h" 36 37namespace WebCore { 38 39MediaControlsApple::MediaControlsApple(Document& document) 40 : MediaControls(document) 41 , m_rewindButton(0) 42 , m_returnToRealTimeButton(0) 43 , m_statusDisplay(0) 44 , m_timeRemainingDisplay(0) 45 , m_timelineContainer(0) 46 , m_seekBackButton(0) 47 , m_seekForwardButton(0) 48 , m_closedCaptionsTrackList(0) 49 , m_closedCaptionsContainer(0) 50 , m_volumeSliderMuteButton(0) 51 , m_volumeSliderContainer(0) 52 , m_fullScreenMinVolumeButton(0) 53 , m_fullScreenVolumeSlider(0) 54 , m_fullScreenMaxVolumeButton(0) 55{ 56} 57 58PassRefPtr<MediaControls> MediaControls::create(Document& document) 59{ 60 return MediaControlsApple::createControls(document); 61} 62 63PassRefPtr<MediaControlsApple> MediaControlsApple::createControls(Document& document) 64{ 65 if (!document.page()) 66 return 0; 67 68 RefPtr<MediaControlsApple> controls = adoptRef(new MediaControlsApple(document)); 69 70 RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(document); 71 72 ExceptionCode ec; 73 74 RefPtr<MediaControlRewindButtonElement> rewindButton = MediaControlRewindButtonElement::create(document); 75 controls->m_rewindButton = rewindButton.get(); 76 panel->appendChild(rewindButton.release(), ec); 77 if (ec) 78 return 0; 79 80 RefPtr<MediaControlPlayButtonElement> playButton = MediaControlPlayButtonElement::create(document); 81 controls->m_playButton = playButton.get(); 82 panel->appendChild(playButton.release(), ec); 83 if (ec) 84 return 0; 85 86 RefPtr<MediaControlReturnToRealtimeButtonElement> returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(document); 87 controls->m_returnToRealTimeButton = returnToRealtimeButton.get(); 88 panel->appendChild(returnToRealtimeButton.release(), ec); 89 if (ec) 90 return 0; 91 92 if (document.page()->theme().usesMediaControlStatusDisplay()) { 93 RefPtr<MediaControlStatusDisplayElement> statusDisplay = MediaControlStatusDisplayElement::create(document); 94 controls->m_statusDisplay = statusDisplay.get(); 95 panel->appendChild(statusDisplay.release(), ec); 96 if (ec) 97 return 0; 98 } 99 100 RefPtr<MediaControlTimelineContainerElement> timelineContainer = MediaControlTimelineContainerElement::create(document); 101 102 RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document); 103 controls->m_currentTimeDisplay = currentTimeDisplay.get(); 104 timelineContainer->appendChild(currentTimeDisplay.release(), ec); 105 if (ec) 106 return 0; 107 108 RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(document, controls.get()); 109 controls->m_timeline = timeline.get(); 110 timelineContainer->appendChild(timeline.release(), ec); 111 if (ec) 112 return 0; 113 114 RefPtr<MediaControlTimeRemainingDisplayElement> timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(document); 115 controls->m_timeRemainingDisplay = timeRemainingDisplay.get(); 116 timelineContainer->appendChild(timeRemainingDisplay.release(), ec); 117 if (ec) 118 return 0; 119 120 controls->m_timelineContainer = timelineContainer.get(); 121 panel->appendChild(timelineContainer.release(), ec); 122 if (ec) 123 return 0; 124 125 // FIXME: Only create when needed <http://webkit.org/b/57163> 126 RefPtr<MediaControlSeekBackButtonElement> seekBackButton = MediaControlSeekBackButtonElement::create(document); 127 controls->m_seekBackButton = seekBackButton.get(); 128 panel->appendChild(seekBackButton.release(), ec); 129 if (ec) 130 return 0; 131 132 // FIXME: Only create when needed <http://webkit.org/b/57163> 133 RefPtr<MediaControlSeekForwardButtonElement> seekForwardButton = MediaControlSeekForwardButtonElement::create(document); 134 controls->m_seekForwardButton = seekForwardButton.get(); 135 panel->appendChild(seekForwardButton.release(), ec); 136 if (ec) 137 return 0; 138 139 if (document.page()->theme().supportsClosedCaptioning()) { 140 RefPtr<MediaControlClosedCaptionsContainerElement> closedCaptionsContainer = MediaControlClosedCaptionsContainerElement::create(document); 141 142 RefPtr<MediaControlClosedCaptionsTrackListElement> closedCaptionsTrackList = MediaControlClosedCaptionsTrackListElement::create(document, controls.get()); 143 controls->m_closedCaptionsTrackList = closedCaptionsTrackList.get(); 144 closedCaptionsContainer->appendChild(closedCaptionsTrackList.release(), ec); 145 if (ec) 146 return 0; 147 148 RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.get()); 149 controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); 150 panel->appendChild(toggleClosedCaptionsButton.release(), ec); 151 if (ec) 152 return 0; 153 154 controls->m_closedCaptionsContainer = closedCaptionsContainer.get(); 155 controls->appendChild(closedCaptionsContainer.release(), ec); 156 if (ec) 157 return 0; 158 } 159 160 // FIXME: Only create when needed <http://webkit.org/b/57163> 161 RefPtr<MediaControlFullscreenButtonElement> fullScreenButton = MediaControlFullscreenButtonElement::create(document); 162 controls->m_fullScreenButton = fullScreenButton.get(); 163 panel->appendChild(fullScreenButton.release(), ec); 164 165 // The mute button and the slider element should be in the same div. 166 RefPtr<HTMLDivElement> panelVolumeControlContainer = HTMLDivElement::create(document); 167 168 if (document.page()->theme().usesMediaControlVolumeSlider()) { 169 RefPtr<MediaControlVolumeSliderContainerElement> volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document); 170 171 RefPtr<MediaControlPanelVolumeSliderElement> slider = MediaControlPanelVolumeSliderElement::create(document); 172 controls->m_volumeSlider = slider.get(); 173 volumeSliderContainer->appendChild(slider.release(), ec); 174 if (ec) 175 return 0; 176 177 // This is a duplicate mute button, which is visible in some ports at the bottom of the volume bar. 178 // It's important only when the volume bar is displayed below the controls. 179 RefPtr<MediaControlVolumeSliderMuteButtonElement> volumeSliderMuteButton = MediaControlVolumeSliderMuteButtonElement::create(document); 180 controls->m_volumeSliderMuteButton = volumeSliderMuteButton.get(); 181 volumeSliderContainer->appendChild(volumeSliderMuteButton.release(), ec); 182 183 if (ec) 184 return 0; 185 186 controls->m_volumeSliderContainer = volumeSliderContainer.get(); 187 panelVolumeControlContainer->appendChild(volumeSliderContainer.release(), ec); 188 if (ec) 189 return 0; 190 } 191 192 RefPtr<MediaControlPanelMuteButtonElement> panelMuteButton = MediaControlPanelMuteButtonElement::create(document, controls.get()); 193 controls->m_panelMuteButton = panelMuteButton.get(); 194 panelVolumeControlContainer->appendChild(panelMuteButton.release(), ec); 195 if (ec) 196 return 0; 197 198 panel->appendChild(panelVolumeControlContainer, ec); 199 if (ec) 200 return 0; 201 202 // FIXME: Only create when needed <http://webkit.org/b/57163> 203 RefPtr<MediaControlFullscreenVolumeMinButtonElement> fullScreenMinVolumeButton = MediaControlFullscreenVolumeMinButtonElement::create(document); 204 controls->m_fullScreenMinVolumeButton = fullScreenMinVolumeButton.get(); 205 panel->appendChild(fullScreenMinVolumeButton.release(), ec); 206 if (ec) 207 return 0; 208 209 RefPtr<MediaControlFullscreenVolumeSliderElement> fullScreenVolumeSlider = MediaControlFullscreenVolumeSliderElement::create(document); 210 controls->m_fullScreenVolumeSlider = fullScreenVolumeSlider.get(); 211 panel->appendChild(fullScreenVolumeSlider.release(), ec); 212 if (ec) 213 return 0; 214 215 RefPtr<MediaControlFullscreenVolumeMaxButtonElement> fullScreenMaxVolumeButton = MediaControlFullscreenVolumeMaxButtonElement::create(document); 216 controls->m_fullScreenMaxVolumeButton = fullScreenMaxVolumeButton.get(); 217 panel->appendChild(fullScreenMaxVolumeButton.release(), ec); 218 if (ec) 219 return 0; 220 221 controls->m_panel = panel.get(); 222 controls->appendChild(panel.release(), ec); 223 if (ec) 224 return 0; 225 226 return controls.release(); 227} 228 229void MediaControlsApple::setMediaController(MediaControllerInterface* controller) 230{ 231 if (m_mediaController == controller) 232 return; 233 234 MediaControls::setMediaController(controller); 235 236 if (m_rewindButton) 237 m_rewindButton->setMediaController(controller); 238 if (m_returnToRealTimeButton) 239 m_returnToRealTimeButton->setMediaController(controller); 240 if (m_statusDisplay) 241 m_statusDisplay->setMediaController(controller); 242 if (m_timeRemainingDisplay) 243 m_timeRemainingDisplay->setMediaController(controller); 244 if (m_timelineContainer) 245 m_timelineContainer->setMediaController(controller); 246 if (m_seekBackButton) 247 m_seekBackButton->setMediaController(controller); 248 if (m_seekForwardButton) 249 m_seekForwardButton->setMediaController(controller); 250 if (m_volumeSliderMuteButton) 251 m_volumeSliderMuteButton->setMediaController(controller); 252 if (m_volumeSliderContainer) 253 m_volumeSliderContainer->setMediaController(controller); 254 if (m_fullScreenMinVolumeButton) 255 m_fullScreenMinVolumeButton->setMediaController(controller); 256 if (m_fullScreenVolumeSlider) 257 m_fullScreenVolumeSlider->setMediaController(controller); 258 if (m_fullScreenMaxVolumeButton) 259 m_fullScreenMaxVolumeButton->setMediaController(controller); 260 if (m_closedCaptionsTrackList) 261 m_closedCaptionsTrackList->setMediaController(controller); 262 if (m_closedCaptionsContainer) 263 m_closedCaptionsContainer->setMediaController(controller); 264} 265 266void MediaControlsApple::defaultEventHandler(Event* event) 267{ 268 if (event->type() == eventNames().clickEvent) { 269 if (m_closedCaptionsContainer && m_closedCaptionsContainer->isShowing()) { 270 hideClosedCaptionTrackList(); 271 event->setDefaultHandled(); 272 } 273 } 274 275 MediaControls::defaultEventHandler(event); 276} 277 278void MediaControlsApple::hide() 279{ 280 MediaControls::hide(); 281 m_volumeSliderContainer->hide(); 282 if (m_closedCaptionsContainer) 283 hideClosedCaptionTrackList(); 284} 285 286void MediaControlsApple::makeTransparent() 287{ 288 MediaControls::makeTransparent(); 289 m_volumeSliderContainer->hide(); 290 if (m_closedCaptionsContainer) 291 hideClosedCaptionTrackList(); 292} 293 294void MediaControlsApple::changedClosedCaptionsVisibility() 295{ 296 MediaControls::changedClosedCaptionsVisibility(); 297 if (m_closedCaptionsContainer && m_closedCaptionsContainer->isShowing()) 298 hideClosedCaptionTrackList(); 299 300} 301 302void MediaControlsApple::reset() 303{ 304 Page* page = document().page(); 305 if (!page) 306 return; 307 308 updateStatusDisplay(); 309 310 if (m_mediaController->supportsFullscreen()) 311 m_fullScreenButton->show(); 312 else 313 m_fullScreenButton->hide(); 314 315 double duration = m_mediaController->duration(); 316 if (std::isfinite(duration) || page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart)) { 317 m_timeline->setDuration(duration); 318 m_timelineContainer->show(); 319 m_timeline->setPosition(m_mediaController->currentTime()); 320 updateCurrentTimeDisplay(); 321 } else 322 m_timelineContainer->hide(); 323 324 if (m_mediaController->hasAudio() || page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) 325 m_panelMuteButton->show(); 326 else 327 m_panelMuteButton->hide(); 328 329 if (m_volumeSlider) 330 setSliderVolume(); 331 332 if (m_toggleClosedCaptionsButton) { 333 if (m_mediaController->hasClosedCaptions()) 334 m_toggleClosedCaptionsButton->show(); 335 else 336 m_toggleClosedCaptionsButton->hide(); 337 } 338 339 if (m_playButton) 340 m_playButton->updateDisplayType(); 341 342#if ENABLE(FULLSCREEN_API) 343 if (m_fullScreenVolumeSlider) 344 setFullscreenSliderVolume(); 345 346 if (m_isFullscreen) { 347 if (m_mediaController->isLiveStream()) { 348 m_seekBackButton->hide(); 349 m_seekForwardButton->hide(); 350 m_rewindButton->show(); 351 m_returnToRealTimeButton->show(); 352 } else { 353 m_seekBackButton->show(); 354 m_seekForwardButton->show(); 355 m_rewindButton->hide(); 356 m_returnToRealTimeButton->hide(); 357 } 358 } else 359#endif 360 if (!m_mediaController->isLiveStream()) { 361 m_returnToRealTimeButton->hide(); 362 m_rewindButton->show(); 363 } else { 364 m_returnToRealTimeButton->show(); 365 m_rewindButton->hide(); 366 } 367 368 makeOpaque(); 369} 370 371void MediaControlsApple::updateCurrentTimeDisplay() 372{ 373 double now = m_mediaController->currentTime(); 374 double duration = m_mediaController->duration(); 375 376 Page* page = document().page(); 377 if (!page) 378 return; 379 380 // Allow the theme to format the time. 381 m_currentTimeDisplay->setInnerText(page->theme().formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION); 382 m_currentTimeDisplay->setCurrentValue(now); 383 m_timeRemainingDisplay->setInnerText(page->theme().formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION); 384 m_timeRemainingDisplay->setCurrentValue(now - duration); 385} 386 387void MediaControlsApple::reportedError() 388{ 389 Page* page = document().page(); 390 if (!page) 391 return; 392 393 if (!page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart)) 394 m_timelineContainer->hide(); 395 396 if (!page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) 397 m_panelMuteButton->hide(); 398 399 m_fullScreenButton->hide(); 400 401 if (m_volumeSliderContainer) 402 m_volumeSliderContainer->hide(); 403 if (m_toggleClosedCaptionsButton && !page->theme().hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart)) 404 m_toggleClosedCaptionsButton->hide(); 405 if (m_closedCaptionsContainer) 406 hideClosedCaptionTrackList(); 407} 408 409void MediaControlsApple::updateStatusDisplay() 410{ 411 if (m_statusDisplay) 412 m_statusDisplay->update(); 413} 414 415void MediaControlsApple::loadedMetadata() 416{ 417 if (m_statusDisplay && !m_mediaController->isLiveStream()) 418 m_statusDisplay->hide(); 419 420 MediaControls::loadedMetadata(); 421} 422 423void MediaControlsApple::changedMute() 424{ 425 MediaControls::changedMute(); 426 427 if (m_volumeSliderMuteButton) 428 m_volumeSliderMuteButton->changedMute(); 429} 430 431void MediaControlsApple::changedVolume() 432{ 433 MediaControls::changedVolume(); 434 435 if (m_fullScreenVolumeSlider) 436 setFullscreenSliderVolume(); 437} 438 439void MediaControlsApple::enteredFullscreen() 440{ 441 MediaControls::enteredFullscreen(); 442 m_panel->setCanBeDragged(true); 443 444 if (m_mediaController->isLiveStream()) { 445 m_seekBackButton->hide(); 446 m_seekForwardButton->hide(); 447 m_rewindButton->show(); 448 m_returnToRealTimeButton->show(); 449 } else { 450 m_seekBackButton->show(); 451 m_seekForwardButton->show(); 452 m_rewindButton->hide(); 453 m_returnToRealTimeButton->hide(); 454 } 455} 456 457void MediaControlsApple::exitedFullscreen() 458{ 459 m_rewindButton->show(); 460 m_seekBackButton->show(); 461 m_seekForwardButton->show(); 462 m_returnToRealTimeButton->show(); 463 464 m_panel->setCanBeDragged(false); 465 466 // We will keep using the panel, but we want it to go back to the standard position. 467 // This will matter right away because we use the panel even when not fullscreen. 468 // And if we reenter fullscreen we also want the panel in the standard position. 469 m_panel->resetPosition(); 470 471 MediaControls::exitedFullscreen(); 472} 473 474void MediaControlsApple::showVolumeSlider() 475{ 476 if (!m_mediaController->hasAudio()) 477 return; 478 479 if (m_volumeSliderContainer) 480 m_volumeSliderContainer->show(); 481} 482 483void MediaControlsApple::toggleClosedCaptionTrackList() 484{ 485 if (!m_mediaController->hasClosedCaptions()) 486 return; 487 488 if (m_closedCaptionsContainer) { 489 if (m_closedCaptionsContainer->isShowing()) 490 hideClosedCaptionTrackList(); 491 else { 492 if (m_closedCaptionsTrackList) 493 m_closedCaptionsTrackList->updateDisplay(); 494 showClosedCaptionTrackList(); 495 } 496 } 497} 498 499void MediaControlsApple::showClosedCaptionTrackList() 500{ 501 if (!m_closedCaptionsContainer || m_closedCaptionsContainer->isShowing()) 502 return; 503 504 m_closedCaptionsContainer->show(); 505 506 // Ensure the controls panel does not receive any events while the captions 507 // track list is visible as all events now need to be captured by the 508 // track list. 509 m_panel->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone); 510 511 RefPtr<EventListener> listener = eventListener(); 512 m_closedCaptionsContainer->addEventListener(eventNames().wheelEvent, listener, true); 513 514 // Track click events in the capture phase at two levels, first at the document level 515 // such that a click outside of the <video> may dismiss the track list, second at the 516 // media controls level such that a click anywhere outside of the track list hides the 517 // track list. These two levels are necessary since it would not be possible to get a 518 // reference to the track list when handling the event outside of the shadow tree. 519 document().addEventListener(eventNames().clickEvent, listener, true); 520 addEventListener(eventNames().clickEvent, listener, true); 521} 522 523void MediaControlsApple::hideClosedCaptionTrackList() 524{ 525 if (!m_closedCaptionsContainer || !m_closedCaptionsContainer->isShowing()) 526 return; 527 528 m_closedCaptionsContainer->hide(); 529 530 // Buttons in the controls panel may now be interactive. 531 m_panel->removeInlineStyleProperty(CSSPropertyPointerEvents); 532 533 EventListener* listener = eventListener().get(); 534 m_closedCaptionsContainer->removeEventListener(eventNames().wheelEvent, listener, true); 535 document().removeEventListener(eventNames().clickEvent, listener, true); 536 removeEventListener(eventNames().clickEvent, listener, true); 537} 538 539void MediaControlsApple::setFullscreenSliderVolume() 540{ 541 m_fullScreenVolumeSlider->setVolume(m_mediaController->muted() ? 0.0 : m_mediaController->volume()); 542} 543 544bool MediaControlsApple::shouldClosedCaptionsContainerPreventPageScrolling(int wheelDeltaY) 545{ 546 int scrollTop = m_closedCaptionsContainer->scrollTop(); 547 // Scrolling down. 548 if (wheelDeltaY < 0 && (scrollTop + m_closedCaptionsContainer->offsetHeight()) >= m_closedCaptionsContainer->scrollHeight()) 549 return true; 550 // Scrolling up. 551 if (wheelDeltaY > 0 && scrollTop <= 0) 552 return true; 553 return false; 554} 555 556void MediaControlsApple::handleClickEvent(Event* event) 557{ 558 Node* currentTarget = event->currentTarget()->toNode(); 559 Node* target = event->target()->toNode(); 560 561 if ((currentTarget == &document() && !shadowHost()->contains(target)) || (currentTarget == this && !m_closedCaptionsContainer->contains(target))) { 562 hideClosedCaptionTrackList(); 563 event->stopImmediatePropagation(); 564 event->setDefaultHandled(); 565 } 566} 567 568void MediaControlsApple::closedCaptionTracksChanged() 569{ 570 if (m_toggleClosedCaptionsButton) { 571 if (m_mediaController->hasClosedCaptions()) 572 m_toggleClosedCaptionsButton->show(); 573 else 574 m_toggleClosedCaptionsButton->hide(); 575 } 576} 577 578PassRefPtr<MediaControlsAppleEventListener> MediaControlsApple::eventListener() 579{ 580 if (!m_eventListener) 581 m_eventListener = MediaControlsAppleEventListener::create(this); 582 return m_eventListener; 583} 584 585// -------- 586 587void MediaControlsAppleEventListener::handleEvent(ScriptExecutionContext*, Event* event) 588{ 589 if (event->type() == eventNames().clickEvent) 590 m_mediaControls->handleClickEvent(event); 591 else if ((event->type() == eventNames().wheelEvent || event->type() == eventNames().mousewheelEvent) && event->eventInterface() == WheelEventInterfaceType) { 592 WheelEvent* wheelEvent = toWheelEvent(event); 593 if (m_mediaControls->shouldClosedCaptionsContainerPreventPageScrolling(wheelEvent->wheelDeltaY())) 594 event->preventDefault(); 595 } 596} 597 598bool MediaControlsAppleEventListener::operator==(const EventListener& listener) 599{ 600 if (const MediaControlsAppleEventListener* mediaControlsAppleEventListener = MediaControlsAppleEventListener::cast(&listener)) 601 return m_mediaControls == mediaControlsAppleEventListener->m_mediaControls; 602 return false; 603} 604 605} 606 607#endif 608