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 "third_party/blink/renderer/modules/device_orientation/device_orientation_controller.h"
6 
7 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/renderer/core/frame/deprecation.h"
10 #include "third_party/blink/renderer/core/frame/frame_console.h"
11 #include "third_party/blink/renderer/core/frame/settings.h"
12 #include "third_party/blink/renderer/core/inspector/console_message.h"
13 #include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h"
14 #include "third_party/blink/renderer/modules/device_orientation/device_orientation_event.h"
15 #include "third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.h"
16 #include "third_party/blink/renderer/modules/event_modules.h"
17 #include "third_party/blink/renderer/platform/heap/heap.h"
18 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
19 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
20 #include "third_party/blink/renderer/platform/wtf/assertions.h"
21 
22 namespace blink {
23 
DeviceOrientationController(LocalDOMWindow & window)24 DeviceOrientationController::DeviceOrientationController(LocalDOMWindow& window)
25     : DeviceSingleWindowEventController(window),
26       Supplement<LocalDOMWindow>(window) {}
27 
28 DeviceOrientationController::~DeviceOrientationController() = default;
29 
DidUpdateData()30 void DeviceOrientationController::DidUpdateData() {
31   if (override_orientation_data_)
32     return;
33   DispatchDeviceEvent(LastEvent());
34 }
35 
36 const char DeviceOrientationController::kSupplementName[] =
37     "DeviceOrientationController";
38 
From(LocalDOMWindow & window)39 DeviceOrientationController& DeviceOrientationController::From(
40     LocalDOMWindow& window) {
41   DeviceOrientationController* controller =
42       Supplement<LocalDOMWindow>::From<DeviceOrientationController>(window);
43   if (!controller) {
44     controller = MakeGarbageCollected<DeviceOrientationController>(window);
45     ProvideTo(window, controller);
46   }
47   return *controller;
48 }
49 
DidAddEventListener(LocalDOMWindow * window,const AtomicString & event_type)50 void DeviceOrientationController::DidAddEventListener(
51     LocalDOMWindow* window,
52     const AtomicString& event_type) {
53   if (event_type != EventTypeName())
54     return;
55 
56   // The window could be detached, e.g. if it is the `contentWindow` of an
57   // <iframe> that has been removed from the DOM of its parent frame.
58   if (GetWindow().IsContextDestroyed())
59     return;
60 
61   // The API is not exposed to Workers or Worklets, so if the current realm
62   // execution context is valid, it must have a responsible browsing context.
63   SECURITY_CHECK(GetWindow().GetFrame());
64 
65   // The event handler property on `window` is restricted to [SecureContext],
66   // but nothing prevents a site from calling `window.addEventListener(...)`
67   // from a non-secure browsing context.
68   if (!GetWindow().IsSecureContext())
69     return;
70 
71   UseCounter::Count(GetWindow(), WebFeature::kDeviceOrientationSecureOrigin);
72 
73   if (!has_event_listener_) {
74     if (!CheckPolicyFeatures(
75             {mojom::blink::FeaturePolicyFeature::kAccelerometer,
76              mojom::blink::FeaturePolicyFeature::kGyroscope})) {
77       LogToConsolePolicyFeaturesDisabled(*GetWindow().GetFrame(),
78                                          EventTypeName());
79       return;
80     }
81   }
82 
83   DeviceSingleWindowEventController::DidAddEventListener(window, event_type);
84 }
85 
LastData() const86 DeviceOrientationData* DeviceOrientationController::LastData() const {
87   return override_orientation_data_
88              ? override_orientation_data_.Get()
89              : orientation_event_pump_
90                    ? orientation_event_pump_->LatestDeviceOrientationData()
91                    : nullptr;
92 }
93 
HasLastData()94 bool DeviceOrientationController::HasLastData() {
95   return LastData();
96 }
97 
RegisterWithDispatcher()98 void DeviceOrientationController::RegisterWithDispatcher() {
99   RegisterWithOrientationEventPump(false /* absolute */);
100 }
101 
UnregisterWithDispatcher()102 void DeviceOrientationController::UnregisterWithDispatcher() {
103   if (orientation_event_pump_)
104     orientation_event_pump_->RemoveController();
105 }
106 
LastEvent() const107 Event* DeviceOrientationController::LastEvent() const {
108   return DeviceOrientationEvent::Create(EventTypeName(), LastData());
109 }
110 
IsNullEvent(Event * event) const111 bool DeviceOrientationController::IsNullEvent(Event* event) const {
112   auto* orientation_event = To<DeviceOrientationEvent>(event);
113   return !orientation_event->Orientation()->CanProvideEventData();
114 }
115 
EventTypeName() const116 const AtomicString& DeviceOrientationController::EventTypeName() const {
117   return event_type_names::kDeviceorientation;
118 }
119 
SetOverride(DeviceOrientationData * device_orientation_data)120 void DeviceOrientationController::SetOverride(
121     DeviceOrientationData* device_orientation_data) {
122   DCHECK(device_orientation_data);
123   override_orientation_data_ = device_orientation_data;
124   DispatchDeviceEvent(LastEvent());
125 }
126 
ClearOverride()127 void DeviceOrientationController::ClearOverride() {
128   if (!override_orientation_data_)
129     return;
130   override_orientation_data_.Clear();
131   if (LastData())
132     DidUpdateData();
133 }
134 
Trace(Visitor * visitor) const135 void DeviceOrientationController::Trace(Visitor* visitor) const {
136   visitor->Trace(override_orientation_data_);
137   visitor->Trace(orientation_event_pump_);
138   DeviceSingleWindowEventController::Trace(visitor);
139   Supplement<LocalDOMWindow>::Trace(visitor);
140 }
141 
RegisterWithOrientationEventPump(bool absolute)142 void DeviceOrientationController::RegisterWithOrientationEventPump(
143     bool absolute) {
144   if (!orientation_event_pump_) {
145     orientation_event_pump_ = MakeGarbageCollected<DeviceOrientationEventPump>(
146         *GetWindow().GetFrame(), absolute);
147   }
148   orientation_event_pump_->SetController(this);
149 }
150 
151 // static
LogToConsolePolicyFeaturesDisabled(LocalFrame & frame,const AtomicString & event_name)152 void DeviceOrientationController::LogToConsolePolicyFeaturesDisabled(
153     LocalFrame& frame,
154     const AtomicString& event_name) {
155   const String& message = String::Format(
156       "The %s events are blocked by feature policy. "
157       "See "
158       "https://github.com/WICG/feature-policy/blob/master/"
159       "features.md#sensor-features",
160       event_name.Ascii().c_str());
161   auto* console_message = MakeGarbageCollected<ConsoleMessage>(
162       mojom::ConsoleMessageSource::kJavaScript,
163       mojom::ConsoleMessageLevel::kWarning, std::move(message));
164   frame.Console().AddMessage(console_message);
165 }
166 
167 }  // namespace blink
168