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