| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "core/html/MediaCustomControlsFullscreenDetector.h" |
| 6 |
| 7 #include "core/dom/Fullscreen.h" |
| 8 #include "core/dom/TaskRunnerHelper.h" |
| 9 #include "core/events/Event.h" |
| 10 #include "core/html/HTMLVideoElement.h" |
| 11 #include "core/layout/IntersectionGeometry.h" |
| 12 |
| 13 namespace blink { |
| 14 |
| 15 namespace { |
| 16 |
| 17 constexpr double kCheckFullscreenIntervalSeconds = 1.0f; |
| 18 constexpr float kMostlyFillViewportThresholdOfOccupationProportion = 0.85f; |
| 19 constexpr float kMostlyFillViewportThresholdOfVisibleProportion = 0.75f; |
| 20 |
| 21 } // anonymous namespace |
| 22 |
| 23 MediaCustomControlsFullscreenDetector::MediaCustomControlsFullscreenDetector( |
| 24 HTMLVideoElement& video) |
| 25 : EventListener(CPPEventListenerType), |
| 26 m_videoElement(video), |
| 27 m_checkViewportIntersectionTimer( |
| 28 TaskRunnerHelper::get(TaskType::Unthrottled, &video.document()), |
| 29 this, |
| 30 &MediaCustomControlsFullscreenDetector:: |
| 31 onCheckViewportIntersectionTimerFired) { |
| 32 videoElement().addEventListener(EventTypeNames::DOMNodeInsertedIntoDocument, |
| 33 this, false); |
| 34 videoElement().addEventListener(EventTypeNames::DOMNodeRemovedFromDocument, |
| 35 this, false); |
| 36 |
| 37 videoElement().addEventListener(EventTypeNames::loadedmetadata, this, true); |
| 38 } |
| 39 |
| 40 bool MediaCustomControlsFullscreenDetector::operator==( |
| 41 const EventListener& other) const { |
| 42 return this == &other; |
| 43 } |
| 44 |
| 45 void MediaCustomControlsFullscreenDetector::attach() { |
| 46 videoElement().document().addEventListener( |
| 47 EventTypeNames::webkitfullscreenchange, this, true); |
| 48 videoElement().document().addEventListener(EventTypeNames::fullscreenchange, |
| 49 this, true); |
| 50 } |
| 51 |
| 52 void MediaCustomControlsFullscreenDetector::detach() { |
| 53 videoElement().document().removeEventListener( |
| 54 EventTypeNames::webkitfullscreenchange, this, true); |
| 55 videoElement().document().removeEventListener( |
| 56 EventTypeNames::fullscreenchange, this, true); |
| 57 } |
| 58 |
| 59 bool MediaCustomControlsFullscreenDetector::computeIsDominantVideoForTests( |
| 60 const IntRect& targetRect, |
| 61 const IntRect& rootRect, |
| 62 const IntRect& intersectionRect) { |
| 63 if (targetRect.isEmpty() || rootRect.isEmpty()) |
| 64 return false; |
| 65 |
| 66 const float xOccupationProportion = |
| 67 1.0f * intersectionRect.width() / rootRect.width(); |
| 68 const float yOccupationProportion = |
| 69 1.0f * intersectionRect.height() / rootRect.height(); |
| 70 |
| 71 // If the viewport is mostly occupied by the video, return true. |
| 72 if (std::min(xOccupationProportion, yOccupationProportion) >= |
| 73 kMostlyFillViewportThresholdOfOccupationProportion) { |
| 74 return true; |
| 75 } |
| 76 |
| 77 // If neither of the dimensions of the viewport is mostly occupied by the |
| 78 // video, return false. |
| 79 if (std::max(xOccupationProportion, yOccupationProportion) < |
| 80 kMostlyFillViewportThresholdOfOccupationProportion) { |
| 81 return false; |
| 82 } |
| 83 |
| 84 // If the video is mostly visible in the indominant dimension, return true. |
| 85 // Otherwise return false. |
| 86 if (xOccupationProportion > yOccupationProportion) { |
| 87 return targetRect.height() * |
| 88 kMostlyFillViewportThresholdOfVisibleProportion < |
| 89 intersectionRect.height(); |
| 90 } |
| 91 return targetRect.width() * kMostlyFillViewportThresholdOfVisibleProportion < |
| 92 intersectionRect.width(); |
| 93 } |
| 94 |
| 95 void MediaCustomControlsFullscreenDetector::handleEvent( |
| 96 ExecutionContext* context, |
| 97 Event* event) { |
| 98 DCHECK(event->type() == EventTypeNames::DOMNodeInsertedIntoDocument || |
| 99 event->type() == EventTypeNames::DOMNodeRemovedFromDocument || |
| 100 event->type() == EventTypeNames::loadedmetadata || |
| 101 event->type() == EventTypeNames::webkitfullscreenchange || |
| 102 event->type() == EventTypeNames::fullscreenchange); |
| 103 |
| 104 // Don't early return when the video is inserted into/removed from the |
| 105 // document, as the document might already be in fullscreen. |
| 106 if (event->type() == EventTypeNames::DOMNodeInsertedIntoDocument) { |
| 107 attach(); |
| 108 } else if (event->type() == EventTypeNames::DOMNodeRemovedFromDocument) { |
| 109 detach(); |
| 110 } |
| 111 |
| 112 // Video is not loaded yet. |
| 113 if (videoElement().getReadyState() < HTMLMediaElement::kHaveMetadata) |
| 114 return; |
| 115 |
| 116 if (!videoElement().isConnected() || !isVideoOrParentFullscreen()) { |
| 117 m_checkViewportIntersectionTimer.stop(); |
| 118 |
| 119 if (videoElement().webMediaPlayer()) |
| 120 videoElement().webMediaPlayer()->setIsEffectivelyFullscreen(false); |
| 121 |
| 122 return; |
| 123 } |
| 124 |
| 125 m_checkViewportIntersectionTimer.startOneShot(kCheckFullscreenIntervalSeconds, |
| 126 BLINK_FROM_HERE); |
| 127 } |
| 128 |
| 129 void MediaCustomControlsFullscreenDetector:: |
| 130 onCheckViewportIntersectionTimerFired(TimerBase*) { |
| 131 DCHECK(isVideoOrParentFullscreen()); |
| 132 IntersectionGeometry geometry(nullptr, videoElement(), Vector<Length>(), |
| 133 true); |
| 134 geometry.computeGeometry(); |
| 135 |
| 136 bool isDominant = computeIsDominantVideoForTests( |
| 137 geometry.targetIntRect(), geometry.rootIntRect(), |
| 138 geometry.intersectionIntRect()); |
| 139 |
| 140 if (videoElement().webMediaPlayer()) |
| 141 videoElement().webMediaPlayer()->setIsEffectivelyFullscreen(isDominant); |
| 142 } |
| 143 |
| 144 bool MediaCustomControlsFullscreenDetector::isVideoOrParentFullscreen() { |
| 145 Element* fullscreenElement = |
| 146 Fullscreen::currentFullScreenElementFrom(videoElement().document()); |
| 147 if (!fullscreenElement) |
| 148 return false; |
| 149 |
| 150 return fullscreenElement->contains(&videoElement()); |
| 151 } |
| 152 |
| 153 DEFINE_TRACE(MediaCustomControlsFullscreenDetector) { |
| 154 EventListener::trace(visitor); |
| 155 visitor->trace(m_videoElement); |
| 156 } |
| 157 |
| 158 } // namespace blink |
| OLD | NEW |