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.
6 #include "modules/screen_orientation/ScreenOrientationController.h"
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"
20 ScreenOrientationController::~ScreenOrientationController()
24 void ScreenOrientationController::provideTo(LocalFrame& frame, WebScreenOrientationClient* client)
26 ASSERT(RuntimeEnabledFeatures::screenOrientationEnabled());
28 ScreenOrientationController* controller = new ScreenOrientationController(frame, client);
29 WillBeHeapSupplement<LocalFrame>::provideTo(frame, supplementName(), adoptPtrWillBeNoop(controller));
32 ScreenOrientationController* ScreenOrientationController::from(LocalFrame& frame)
34 return static_cast<ScreenOrientationController*>(WillBeHeapSupplement<LocalFrame>::from(frame, supplementName()));
37 ScreenOrientationController::ScreenOrientationController(LocalFrame& frame, WebScreenOrientationClient* client)
38 : FrameDestructionObserver(&frame)
39 , PlatformEventController(frame.page())
41 , m_dispatchEventTimer(this, &ScreenOrientationController::dispatchEventTimerFired)
45 const char* ScreenOrientationController::supplementName()
47 return "ScreenOrientationController";
50 // Compute the screen orientation using the orientation angle and the screen width / height.
51 WebScreenOrientationType ScreenOrientationController::computeOrientation(FrameView* view)
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
56 if (LayoutTestSupport::isRunningLayoutTest())
57 return WebScreenOrientationPortraitPrimary;
59 FloatRect rect = screenRect(view);
60 uint16_t rotation = screenOrientationAngle(view);
61 bool isTallDisplay = rotation % 180 ? rect.height() < rect.width() : rect.height() > rect.width();
64 return isTallDisplay ? WebScreenOrientationPortraitPrimary : WebScreenOrientationLandscapePrimary;
66 return isTallDisplay ? WebScreenOrientationLandscapePrimary : WebScreenOrientationPortraitSecondary;
68 return isTallDisplay ? WebScreenOrientationPortraitSecondary : WebScreenOrientationLandscapeSecondary;
70 return isTallDisplay ? WebScreenOrientationLandscapeSecondary : WebScreenOrientationPortraitPrimary;
73 return WebScreenOrientationPortraitPrimary;
77 void ScreenOrientationController::updateOrientation()
79 ASSERT(m_orientation);
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);
88 ASSERT(orientationType != WebScreenOrientationUndefined);
90 m_orientation->setType(orientationType);
91 m_orientation->setAngle(screenOrientationAngle(view));
94 bool ScreenOrientationController::isActiveAndVisible() const
96 return m_orientation && frame() && page() && page()->visibilityState() == PageVisibilityStateVisible;
99 void ScreenOrientationController::pageVisibilityChanged()
103 if (!isActiveAndVisible())
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());
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();
119 void ScreenOrientationController::notifyOrientationChanged()
121 ASSERT(RuntimeEnabledFeatures::screenOrientationEnabled());
123 if (!isActiveAndVisible())
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
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));
137 // Notify current orientation object.
138 if (!m_dispatchEventTimer.isActive())
139 m_dispatchEventTimer.startOneShot(0, FROM_HERE);
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();
148 void ScreenOrientationController::setOrientation(ScreenOrientation* orientation)
150 m_orientation = orientation;
156 void ScreenOrientationController::lock(WebScreenOrientationLockType orientation, WebLockOrientationCallback* callback)
158 // When detached, the client is no longer valid.
161 m_client->lockOrientation(orientation, callback);
164 void ScreenOrientationController::unlock()
166 // When detached, the client is no longer valid.
169 m_client->unlockOrientation();
172 void ScreenOrientationController::dispatchEventTimerFired(Timer<ScreenOrientationController>*)
176 m_orientation->dispatchEvent(Event::create(EventTypeNames::change));
179 void ScreenOrientationController::didUpdateData()
184 void ScreenOrientationController::registerWithDispatcher()
186 ScreenOrientationDispatcher::instance().addController(this);
189 void ScreenOrientationController::unregisterWithDispatcher()
191 ScreenOrientationDispatcher::instance().removeController(this);
194 bool ScreenOrientationController::hasLastData()
199 void ScreenOrientationController::willDetachFrameHost()
204 void ScreenOrientationController::notifyDispatcher()
206 if (m_orientation && page()->visibilityState() == PageVisibilityStateVisible)
212 void ScreenOrientationController::trace(Visitor* visitor)
214 visitor->trace(m_orientation);
215 FrameDestructionObserver::trace(visitor);
216 WillBeHeapSupplement<LocalFrame>::trace(visitor);