• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "config.h"
6 #include "modules/screen_orientation/ScreenOrientationController.h"
7 
8 #include "core/events/Event.h"
9 #include "core/frame/FrameView.h"
10 #include "core/frame/LocalFrame.h"
11 #include "core/page/Page.h"
12 #include "modules/screen_orientation/ScreenOrientation.h"
13 #include "modules/screen_orientation/ScreenOrientationDispatcher.h"
14 #include "platform/LayoutTestSupport.h"
15 #include "platform/PlatformScreen.h"
16 #include "public/platform/WebScreenOrientationClient.h"
17 
18 namespace blink {
19 
~ScreenOrientationController()20 ScreenOrientationController::~ScreenOrientationController()
21 {
22 }
23 
provideTo(LocalFrame & frame,WebScreenOrientationClient * client)24 void ScreenOrientationController::provideTo(LocalFrame& frame, WebScreenOrientationClient* client)
25 {
26     ASSERT(RuntimeEnabledFeatures::screenOrientationEnabled());
27 
28     ScreenOrientationController* controller = new ScreenOrientationController(frame, client);
29     WillBeHeapSupplement<LocalFrame>::provideTo(frame, supplementName(), adoptPtrWillBeNoop(controller));
30 }
31 
from(LocalFrame & frame)32 ScreenOrientationController* ScreenOrientationController::from(LocalFrame& frame)
33 {
34     return static_cast<ScreenOrientationController*>(WillBeHeapSupplement<LocalFrame>::from(frame, supplementName()));
35 }
36 
ScreenOrientationController(LocalFrame & frame,WebScreenOrientationClient * client)37 ScreenOrientationController::ScreenOrientationController(LocalFrame& frame, WebScreenOrientationClient* client)
38     : FrameDestructionObserver(&frame)
39     , PlatformEventController(frame.page())
40     , m_client(client)
41     , m_dispatchEventTimer(this, &ScreenOrientationController::dispatchEventTimerFired)
42 {
43 }
44 
supplementName()45 const char* ScreenOrientationController::supplementName()
46 {
47     return "ScreenOrientationController";
48 }
49 
50 // Compute the screen orientation using the orientation angle and the screen width / height.
computeOrientation(FrameView * view)51 WebScreenOrientationType ScreenOrientationController::computeOrientation(FrameView* view)
52 {
53     // Bypass orientation detection in layout tests to get consistent results.
54     // FIXME: The screen dimension should be fixed when running the layout tests to avoid such
55     // issues.
56     if (LayoutTestSupport::isRunningLayoutTest())
57         return WebScreenOrientationPortraitPrimary;
58 
59     FloatRect rect = screenRect(view);
60     uint16_t rotation = screenOrientationAngle(view);
61     bool isTallDisplay = rotation % 180 ? rect.height() < rect.width() : rect.height() > rect.width();
62     switch (rotation) {
63     case 0:
64         return isTallDisplay ? WebScreenOrientationPortraitPrimary : WebScreenOrientationLandscapePrimary;
65     case 90:
66         return isTallDisplay ? WebScreenOrientationLandscapePrimary : WebScreenOrientationPortraitSecondary;
67     case 180:
68         return isTallDisplay ? WebScreenOrientationPortraitSecondary : WebScreenOrientationLandscapeSecondary;
69     case 270:
70         return isTallDisplay ? WebScreenOrientationLandscapeSecondary : WebScreenOrientationPortraitPrimary;
71     default:
72         ASSERT_NOT_REACHED();
73         return WebScreenOrientationPortraitPrimary;
74     }
75 }
76 
updateOrientation()77 void ScreenOrientationController::updateOrientation()
78 {
79     ASSERT(m_orientation);
80     ASSERT(frame());
81 
82     FrameView* view = frame()->view();
83     WebScreenOrientationType orientationType = screenOrientationType(view);
84     if (orientationType == WebScreenOrientationUndefined) {
85         // The embedder could not provide us with an orientation, deduce it ourselves.
86         orientationType = computeOrientation(view);
87     }
88     ASSERT(orientationType != WebScreenOrientationUndefined);
89 
90     m_orientation->setType(orientationType);
91     m_orientation->setAngle(screenOrientationAngle(view));
92 }
93 
isActiveAndVisible() const94 bool ScreenOrientationController::isActiveAndVisible() const
95 {
96     return m_orientation && frame() && page() && page()->visibilityState() == PageVisibilityStateVisible;
97 }
98 
pageVisibilityChanged()99 void ScreenOrientationController::pageVisibilityChanged()
100 {
101     notifyDispatcher();
102 
103     if (!isActiveAndVisible())
104         return;
105 
106     // The orientation type and angle are tied in a way that if the angle has
107     // changed, the type must have changed.
108     unsigned short currentAngle = screenOrientationAngle(frame()->view());
109 
110     // FIXME: sendOrientationChangeEvent() currently send an event all the
111     // children of the frame, so it should only be called on the frame on
112     // top of the tree. We would need the embedder to call
113     // sendOrientationChangeEvent on every WebFrame part of a WebView to be
114     // able to remove this.
115     if (frame() == frame()->localFrameRoot() && m_orientation->angle() != currentAngle)
116         notifyOrientationChanged();
117 }
118 
notifyOrientationChanged()119 void ScreenOrientationController::notifyOrientationChanged()
120 {
121     ASSERT(RuntimeEnabledFeatures::screenOrientationEnabled());
122 
123     if (!isActiveAndVisible())
124         return;
125 
126     updateOrientation();
127 
128     // Keep track of the frames that need to be notified before notifying the
129     // current frame as it will prevent side effects from the change event
130     // handlers.
131     WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > childFrames;
132     for (Frame* child = frame()->tree().firstChild(); child; child = child->tree().nextSibling()) {
133         if (child->isLocalFrame())
134             childFrames.append(toLocalFrame(child));
135     }
136 
137     // Notify current orientation object.
138     if (!m_dispatchEventTimer.isActive())
139         m_dispatchEventTimer.startOneShot(0, FROM_HERE);
140 
141     // ... and child frames, if they have a ScreenOrientationController.
142     for (size_t i = 0; i < childFrames.size(); ++i) {
143         if (ScreenOrientationController* controller = ScreenOrientationController::from(*childFrames[i]))
144             controller->notifyOrientationChanged();
145     }
146 }
147 
setOrientation(ScreenOrientation * orientation)148 void ScreenOrientationController::setOrientation(ScreenOrientation* orientation)
149 {
150     m_orientation = orientation;
151     if (m_orientation)
152         updateOrientation();
153     notifyDispatcher();
154 }
155 
lock(WebScreenOrientationLockType orientation,WebLockOrientationCallback * callback)156 void ScreenOrientationController::lock(WebScreenOrientationLockType orientation, WebLockOrientationCallback* callback)
157 {
158     // When detached, the client is no longer valid.
159     if (!m_client)
160         return;
161     m_client->lockOrientation(orientation, callback);
162 }
163 
unlock()164 void ScreenOrientationController::unlock()
165 {
166     // When detached, the client is no longer valid.
167     if (!m_client)
168         return;
169     m_client->unlockOrientation();
170 }
171 
dispatchEventTimerFired(Timer<ScreenOrientationController> *)172 void ScreenOrientationController::dispatchEventTimerFired(Timer<ScreenOrientationController>*)
173 {
174     if (!m_orientation)
175         return;
176     m_orientation->dispatchEvent(Event::create(EventTypeNames::change));
177 }
178 
didUpdateData()179 void ScreenOrientationController::didUpdateData()
180 {
181     // Do nothing.
182 }
183 
registerWithDispatcher()184 void ScreenOrientationController::registerWithDispatcher()
185 {
186     ScreenOrientationDispatcher::instance().addController(this);
187 }
188 
unregisterWithDispatcher()189 void ScreenOrientationController::unregisterWithDispatcher()
190 {
191     ScreenOrientationDispatcher::instance().removeController(this);
192 }
193 
hasLastData()194 bool ScreenOrientationController::hasLastData()
195 {
196     return true;
197 }
198 
willDetachFrameHost()199 void ScreenOrientationController::willDetachFrameHost()
200 {
201     m_client = nullptr;
202 }
203 
notifyDispatcher()204 void ScreenOrientationController::notifyDispatcher()
205 {
206     if (m_orientation && page()->visibilityState() == PageVisibilityStateVisible)
207         startUpdating();
208     else
209         stopUpdating();
210 }
211 
trace(Visitor * visitor)212 void ScreenOrientationController::trace(Visitor* visitor)
213 {
214     visitor->trace(m_orientation);
215     FrameDestructionObserver::trace(visitor);
216     WillBeHeapSupplement<LocalFrame>::trace(visitor);
217 }
218 
219 } // namespace blink
220