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