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