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 if (videoElement().isConnected()) | |
33 attach(); | |
34 } | |
35 | |
36 bool MediaCustomControlsFullscreenDetector::operator==( | |
37 const EventListener& other) const { | |
38 return this == &other; | |
39 } | |
40 | |
41 void MediaCustomControlsFullscreenDetector::attach() { | |
42 videoElement().addEventListener(EventTypeNames::loadedmetadata, this, true); | |
43 videoElement().document().addEventListener( | |
44 EventTypeNames::webkitfullscreenchange, this, true); | |
45 videoElement().document().addEventListener(EventTypeNames::fullscreenchange, | |
46 this, true); | |
47 } | |
48 | |
49 void MediaCustomControlsFullscreenDetector::detach() { | |
50 videoElement().removeEventListener(EventTypeNames::loadedmetadata, this, | |
51 true); | |
52 videoElement().document().removeEventListener( | |
53 EventTypeNames::webkitfullscreenchange, this, true); | |
54 videoElement().document().removeEventListener( | |
55 EventTypeNames::fullscreenchange, this, true); | |
56 m_checkViewportIntersectionTimer.stop(); | |
57 | |
58 if (videoElement().webMediaPlayer()) | |
59 videoElement().webMediaPlayer()->setIsEffectivelyFullscreen(false); | |
60 } | |
61 | |
62 bool MediaCustomControlsFullscreenDetector::computeIsDominantVideoForTests( | |
63 const IntRect& targetRect, | |
64 const IntRect& rootRect, | |
65 const IntRect& intersectionRect) { | |
66 if (targetRect.isEmpty() || rootRect.isEmpty()) | |
67 return false; | |
68 | |
69 const float xOccupationProportion = | |
70 1.0f * intersectionRect.width() / rootRect.width(); | |
71 const float yOccupationProportion = | |
72 1.0f * intersectionRect.height() / rootRect.height(); | |
73 | |
74 // If the viewport is mostly occupied by the video, return true. | |
75 if (std::min(xOccupationProportion, yOccupationProportion) >= | |
76 kMostlyFillViewportThresholdOfOccupationProportion) { | |
77 return true; | |
78 } | |
79 | |
80 // If neither of the dimensions of the viewport is mostly occupied by the | |
81 // video, return false. | |
82 if (std::max(xOccupationProportion, yOccupationProportion) < | |
83 kMostlyFillViewportThresholdOfOccupationProportion) { | |
84 return false; | |
85 } | |
86 | |
87 // If the video is mostly visible in the indominant dimension, return true. | |
88 // Otherwise return false. | |
89 if (xOccupationProportion > yOccupationProportion) { | |
90 return targetRect.height() * | |
91 kMostlyFillViewportThresholdOfVisibleProportion < | |
92 intersectionRect.height(); | |
93 } | |
94 return targetRect.width() * kMostlyFillViewportThresholdOfVisibleProportion < | |
95 intersectionRect.width(); | |
96 } | |
97 | |
98 void MediaCustomControlsFullscreenDetector::handleEvent( | |
99 ExecutionContext* context, | |
100 Event* event) { | |
101 DCHECK(event->type() == EventTypeNames::loadedmetadata || | |
102 event->type() == EventTypeNames::webkitfullscreenchange || | |
103 event->type() == EventTypeNames::fullscreenchange); | |
104 | |
105 // Video is not loaded yet. | |
106 if (videoElement().getReadyState() < HTMLMediaElement::kHaveMetadata) | |
107 return; | |
108 | |
109 if (!videoElement().isConnected() || !isVideoOrParentFullscreen()) { | |
110 m_checkViewportIntersectionTimer.stop(); | |
111 | |
112 if (videoElement().webMediaPlayer()) | |
113 videoElement().webMediaPlayer()->setIsEffectivelyFullscreen(false); | |
114 | |
115 return; | |
116 } | |
117 | |
118 m_checkViewportIntersectionTimer.startOneShot(kCheckFullscreenIntervalSeconds, | |
119 BLINK_FROM_HERE); | |
120 } | |
121 | |
122 void MediaCustomControlsFullscreenDetector::contextDestroyed() { | |
123 // This method is called by HTMLVideoElement when it observes context destroy. | |
124 // The reason is that when HTMLMediaElement observes context destroy, it will | |
125 // destroy webMediaPlayer() thus the final setIsEffectivelyFullscreen(false) | |
126 // is not called. | |
127 detach(); | |
128 } | |
129 | |
130 void MediaCustomControlsFullscreenDetector:: | |
131 onCheckViewportIntersectionTimerFired(TimerBase*) { | |
132 DCHECK(isVideoOrParentFullscreen()); | |
133 IntersectionGeometry geometry(nullptr, videoElement(), Vector<Length>(), | |
134 true); | |
135 geometry.computeGeometry(); | |
136 | |
137 bool isDominant = computeIsDominantVideoForTests( | |
138 geometry.targetIntRect(), geometry.rootIntRect(), | |
139 geometry.intersectionIntRect()); | |
140 | |
141 if (videoElement().webMediaPlayer()) | |
142 videoElement().webMediaPlayer()->setIsEffectivelyFullscreen(isDominant); | |
143 } | |
144 | |
145 bool MediaCustomControlsFullscreenDetector::isVideoOrParentFullscreen() { | |
146 Element* fullscreenElement = | |
147 Fullscreen::currentFullScreenElementFrom(videoElement().document()); | |
148 if (!fullscreenElement) | |
149 return false; | |
150 | |
151 return fullscreenElement->contains(&videoElement()); | |
152 } | |
153 | |
154 DEFINE_TRACE(MediaCustomControlsFullscreenDetector) { | |
155 EventListener::trace(visitor); | |
156 visitor->trace(m_videoElement); | |
157 } | |
158 | |
159 } // namespace blink | |
OLD | NEW |