Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(640)

Side by Side Diff: third_party/WebKit/Source/modules/webusb/USB.cpp

Issue 1850023002: Consume Mojo services directly in Blink's WebUSB implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/webusb/USB.h" 5 #include "modules/webusb/USB.h"
6 6
7 #include "bindings/core/v8/CallbackPromiseAdapter.h"
8 #include "bindings/core/v8/ScriptPromise.h" 7 #include "bindings/core/v8/ScriptPromise.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h" 8 #include "bindings/core/v8/ScriptPromiseResolver.h"
10 #include "core/dom/DOMException.h" 9 #include "core/dom/DOMException.h"
11 #include "core/dom/Document.h" 10 #include "core/dom/Document.h"
12 #include "core/dom/ExceptionCode.h" 11 #include "core/dom/ExceptionCode.h"
13 #include "modules/EventTargetModules.h" 12 #include "modules/EventTargetModules.h"
14 #include "modules/webusb/USBConnectionEvent.h" 13 #include "modules/webusb/USBConnectionEvent.h"
15 #include "modules/webusb/USBController.h"
16 #include "modules/webusb/USBDevice.h" 14 #include "modules/webusb/USBDevice.h"
17 #include "modules/webusb/USBDeviceFilter.h" 15 #include "modules/webusb/USBDeviceFilter.h"
18 #include "modules/webusb/USBDeviceRequestOptions.h" 16 #include "modules/webusb/USBDeviceRequestOptions.h"
19 #include "modules/webusb/USBError.h"
20 #include "platform/UserGestureIndicator.h" 17 #include "platform/UserGestureIndicator.h"
21 #include "public/platform/Platform.h" 18 #include "public/platform/ServiceRegistry.h"
22 #include "public/platform/WebVector.h"
23 #include "public/platform/modules/webusb/WebUSBClient.h"
24 #include "public/platform/modules/webusb/WebUSBDeviceFilter.h"
25 #include "public/platform/modules/webusb/WebUSBDeviceRequestOptions.h"
26 #include "public/platform/modules/webusb/WebUSBError.h"
27 19
28 namespace blink { 20 namespace blink {
29 namespace { 21 namespace {
30 22
31 void convertDeviceFilter(const USBDeviceFilter& filter, WebUSBDeviceFilter* webF ilter) 23 const char kNoServiceError[] = "USB service unavailable.";
32 { 24
33 webFilter->hasVendorID = filter.hasVendorId(); 25 device::usb::blink::DeviceFilterPtr convertDeviceFilter(const USBDeviceFilter& f ilter)
34 if (filter.hasVendorId()) 26 {
35 webFilter->vendorID = filter.vendorId(); 27 auto mojoFilter = device::usb::blink::DeviceFilter::New();
36 webFilter->hasProductID = filter.hasProductId(); 28 mojoFilter->has_vendor_id = filter.hasVendorId();
37 if (filter.hasProductId()) 29 if (mojoFilter->has_vendor_id)
38 webFilter->productID = filter.productId(); 30 mojoFilter->vendor_id = filter.vendorId();
39 webFilter->hasClassCode = filter.hasClassCode(); 31 mojoFilter->has_product_id = filter.hasProductId();
40 if (filter.hasClassCode()) 32 if (mojoFilter->has_product_id)
41 webFilter->classCode = filter.classCode(); 33 mojoFilter->product_id = filter.productId();
42 webFilter->hasSubclassCode = filter.hasSubclassCode(); 34 mojoFilter->has_class_code = filter.hasClassCode();
43 if (filter.hasSubclassCode()) 35 if (mojoFilter->has_class_code)
44 webFilter->subclassCode = filter.subclassCode(); 36 mojoFilter->class_code = filter.classCode();
45 webFilter->hasProtocolCode = filter.hasProtocolCode(); 37 mojoFilter->has_subclass_code = filter.hasSubclassCode();
46 if (filter.hasProtocolCode()) 38 if (mojoFilter->has_subclass_code)
47 webFilter->protocolCode = filter.protocolCode(); 39 mojoFilter->subclass_code = filter.subclassCode();
48 } 40 mojoFilter->has_protocol_code = filter.hasProtocolCode();
49 41 if (mojoFilter->has_protocol_code)
50 void convertDeviceRequestOptions(const USBDeviceRequestOptions& options, WebUSBD eviceRequestOptions* webOptions) 42 mojoFilter->protocol_code = filter.protocolCode();
51 { 43 return mojoFilter;
52 DCHECK(options.hasFilters()); 44 }
53 webOptions->filters = WebVector<WebUSBDeviceFilter>(options.filters().size() ); 45
54 for (size_t i = 0; i < options.filters().size(); ++i) { 46 class DeviceChangeNotificationAdapter : public device::usb::blink::DeviceManager ::GetDeviceChangesCallback::Runnable {
55 convertDeviceFilter(options.filters()[i], &webOptions->filters[i]); 47 WTF_MAKE_NONCOPYABLE(DeviceChangeNotificationAdapter);
56 } 48
57 } 49 public:
58 50 DeviceChangeNotificationAdapter(USB* usb) : m_usb(usb)
59 // Allows using a CallbackPromiseAdapter with a WebVector to resolve the 51 {
60 // getDevices() promise with a HeapVector owning USBDevices. 52 }
61 class DeviceArray { 53
62 STATIC_ONLY(DeviceArray); 54 void Run(device::usb::blink::DeviceChangeNotificationPtr notification) const
63 public: 55 {
64 using WebType = OwnPtr<WebVector<WebUSBDevice*>>; 56 if (m_usb)
65 57 m_usb->onDeviceChanges(std::move(notification));
66 static HeapVector<Member<USBDevice>> take(ScriptPromiseResolver* resolver, P assOwnPtr<WebVector<WebUSBDevice*>> webDevices) 58 }
67 { 59
60 device::usb::blink::DeviceManager::GetDeviceChangesCallback callback()
61 {
62 return device::usb::blink::DeviceManager::GetDeviceChangesCallback(this) ;
63 }
64
65 private:
66 WeakPersistent<USB> m_usb;
67 };
68
69 template <typename Callback>
70 class PromiseAdapterBase : public Callback::Runnable {
71 WTF_MAKE_NONCOPYABLE(PromiseAdapterBase);
72
73 public:
74 PromiseAdapterBase(ScriptPromiseResolver* resolver) : m_resolver(resolver)
75 {
76 }
77
78 ~PromiseAdapterBase() override
79 {
80 if (active())
81 m_resolver->reject(DOMException::create(NotFoundError, kNoServiceErr or));
82 }
83
84 template <typename T>
85 void resolve(T value) const
86 {
87 ASSERT(active());
88 m_resolver->resolve(value);
89 m_resolver = nullptr;
90 }
91
92 template <typename T>
93 void reject(T value) const
94 {
95 ASSERT(active());
96 m_resolver->reject(value);
97 m_resolver = nullptr;
98 }
99
100 bool active() const
101 {
102 return m_resolver && executionContext() && !executionContext()->activeDO MObjectsAreStopped();
103 }
104
105 Callback callback()
106 {
107 return Callback(this);
108 }
109
110 ExecutionContext* executionContext() const { return m_resolver->getExecution Context(); }
111
112 private:
113 // This field is mutable so that resolve() and reject() can be called from
114 // a mojo::Callback::Runnable's const Run() method.
esprehn 2016/04/06 20:10:45 this is really weird, callback interfaces generall
Reilly Grant (use Gerrit) 2016/04/06 22:30:07 mojo::Callback<>::Runnable::Run() is const because
esprehn 2016/04/06 22:42:38 Having to make your members mutable all over the c
115 mutable Persistent<ScriptPromiseResolver> m_resolver;
116 };
117
118 class GetDevicesPromiseAdapter : public PromiseAdapterBase<device::usb::blink::D eviceManager::GetDevicesCallback> {
119 WTF_MAKE_NONCOPYABLE(GetDevicesPromiseAdapter);
120
121 public:
122 GetDevicesPromiseAdapter(USB* usb, ScriptPromiseResolver* resolver)
123 : PromiseAdapterBase(resolver)
124 , m_usb(usb)
125 {
126 }
127
128 void Run(mojo::WTFArray<device::usb::blink::DeviceInfoPtr> deviceInfos) cons t override
129 {
130 if (!active())
131 return;
132
68 HeapVector<Member<USBDevice>> devices; 133 HeapVector<Member<USBDevice>> devices;
69 for (const auto webDevice : *webDevices) 134 for (size_t i = 0; i < deviceInfos.size(); ++i) {
esprehn 2016/04/06 20:10:45 range loop?
Reilly Grant (use Gerrit) 2016/04/06 22:30:07 Done.
70 devices.append(USBDevice::create(adoptPtr(webDevice), resolver->getE xecutionContext())); 135 device::usb::blink::DevicePtr device;
71 return devices; 136 m_usb->deviceManager()->GetDevice(deviceInfos[i]->guid, mojo::GetPro xy(&device));
72 } 137 devices.append(USBDevice::create(std::move(deviceInfos[i]), std::mov e(device), executionContext()));
138 }
139 resolve(devices);
140 }
141
142 private:
143 Persistent<USB> m_usb;
144 };
145
146 class GetPermissionPromiseAdapter : public PromiseAdapterBase<device::usb::blink ::ChooserService::GetPermissionCallback> {
147 WTF_MAKE_NONCOPYABLE(GetPermissionPromiseAdapter);
148
149 public:
150 GetPermissionPromiseAdapter(USB* usb, ScriptPromiseResolver* resolver)
151 : PromiseAdapterBase(resolver)
152 , m_usb(usb)
153 {
154 }
155
156 void Run(device::usb::blink::DeviceInfoPtr deviceInfo) const override
157 {
158 if (!active())
159 return;
160
161 if (deviceInfo) {
162 device::usb::blink::DevicePtr device;
163 m_usb->deviceManager()->GetDevice(deviceInfo->guid, mojo::GetProxy(& device));
164 resolve(USBDevice::create(std::move(deviceInfo), std::move(device), executionContext()));
165 } else {
166 reject(DOMException::create(NotFoundError, "No device selected."));
167 }
168 }
169
170 private:
171 Persistent<USB> m_usb;
73 }; 172 };
74 173
75 } // namespace 174 } // namespace
76 175
77 USB::USB(LocalFrame& frame) 176 USB::USB(LocalFrame& frame)
78 : ContextLifecycleObserver(frame.document()) 177 : ContextLifecycleObserver(frame.document())
79 , m_client(USBController::from(frame).client()) 178 {
80 { 179 frame.serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_deviceMana ger));
81 if (m_client) 180 m_deviceManager.set_connection_error_handler([this]() {
82 m_client->addObserver(this); 181 m_deviceManager.reset();
182 });
183 auto adapter = new DeviceChangeNotificationAdapter(this);
184 m_deviceManager->GetDeviceChanges(adapter->callback());
185 adapter = new DeviceChangeNotificationAdapter(this);
186 m_deviceManager->GetDeviceChanges(adapter->callback());
esprehn 2016/04/06 20:10:45 this seems to just do the exact same thing twice i
Reilly Grant (use Gerrit) 2016/04/06 22:30:07 Sorry, there was a comment why in the original cod
83 } 187 }
84 188
85 USB::~USB() 189 USB::~USB()
86 { 190 {
87 if (m_client)
88 m_client->removeObserver(this);
89 } 191 }
90 192
91 ScriptPromise USB::getDevices(ScriptState* scriptState) 193 ScriptPromise USB::getDevices(ScriptState* scriptState)
92 { 194 {
93 if (!m_client)
94 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(NotSupportedError));
95
96 String errorMessage;
97 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage))
98 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(SecurityError, errorMessage));
99
100 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 195 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
101 ScriptPromise promise = resolver->promise(); 196 ScriptPromise promise = resolver->promise();
102 m_client->getDevices(new CallbackPromiseAdapter<DeviceArray, USBError>(resol ver)); 197 if (!m_deviceManager) {
103 198 resolver->reject(DOMException::create(NotSupportedError));
199 } else {
200 String errorMessage;
201 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
202 resolver->reject(DOMException::create(SecurityError, errorMessage));
203 } else {
204 auto adapter = new GetDevicesPromiseAdapter(this, resolver);
205 m_deviceManager->GetDevices(nullptr, adapter->callback());
206 }
207 }
104 return promise; 208 return promise;
105 } 209 }
106 210
107 ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceReques tOptions& options) 211 ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceReques tOptions& options)
108 { 212 {
109 if (!m_client)
110 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(NotSupportedError));
111
112 String errorMessage;
113 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage))
114 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(SecurityError, errorMessage));
115
116 if (!UserGestureIndicator::consumeUserGesture())
117 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(SecurityError, "Must be handling a user gesture to show a permission requ est."));
118
119 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 213 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
120 ScriptPromise promise = resolver->promise(); 214 ScriptPromise promise = resolver->promise();
121 215
122 WebUSBDeviceRequestOptions webOptions; 216 if (!m_chooserService) {
123 convertDeviceRequestOptions(options, &webOptions); 217 LocalFrame* frame = getExecutionContext() ? static_cast<Document*>(getEx ecutionContext())->frame() : nullptr;
esprehn 2016/04/06 20:10:45 toDocument() don't static_cast types in blink, our
Reilly Grant (use Gerrit) 2016/04/06 22:30:07 Done.
124 m_client->requestDevice(webOptions, new CallbackPromiseAdapter<USBDevice, US BError>(resolver)); 218 if (!frame) {
125 219 resolver->reject(DOMException::create(NotSupportedError));
220 return promise;
221 }
222 frame->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_choos erService));
223 m_chooserService.set_connection_error_handler([this]() {
224 m_chooserService.reset();
225 });
226 }
227
228 String errorMessage;
229 if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
230 resolver->reject(DOMException::create(SecurityError, errorMessage));
231 } else if (!UserGestureIndicator::consumeUserGesture()) {
232 resolver->reject(DOMException::create(SecurityError, "Must be handling a user gesture to show a permission request."));
233 } else {
234 mojo::WTFArray<device::usb::blink::DeviceFilterPtr> mojoFilters(options. hasFilters() ? options.filters().size() : 0);
235 if (options.hasFilters()) {
236 const auto& filters = options.filters();
237 for (size_t i = 0; i < filters.size(); ++i)
238 mojoFilters[i] = convertDeviceFilter(filters[i]);
239 }
240 auto adapter = new GetPermissionPromiseAdapter(this, resolver);
241 m_chooserService->GetPermission(std::move(mojoFilters), adapter->callbac k());
242 }
126 return promise; 243 return promise;
127 } 244 }
128 245
129 ExecutionContext* USB::getExecutionContext() const 246 ExecutionContext* USB::getExecutionContext() const
130 { 247 {
131 return ContextLifecycleObserver::getExecutionContext(); 248 return ContextLifecycleObserver::getExecutionContext();
132 } 249 }
133 250
134 const AtomicString& USB::interfaceName() const 251 const AtomicString& USB::interfaceName() const
135 { 252 {
136 return EventTargetNames::USB; 253 return EventTargetNames::USB;
137 } 254 }
138 255
139 void USB::contextDestroyed() 256 void USB::contextDestroyed()
140 { 257 {
141 if (m_client) 258 m_deviceManager.reset();
142 m_client->removeObserver(this); 259 m_chooserService.reset();
143 m_client = nullptr;
144 } 260 }
145 261
146 void USB::onDeviceConnected(WebPassOwnPtr<WebUSBDevice> device) 262 void USB::onDeviceChanges(device::usb::blink::DeviceChangeNotificationPtr notifi cation)
147 { 263 {
148 dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice: :create(device.release(), getExecutionContext()))); 264 auto adapter = new DeviceChangeNotificationAdapter(this);
149 } 265 m_deviceManager->GetDeviceChanges(adapter->callback());
150 266 for (size_t i = 0; i < notification->devices_added.size(); ++i) {
151 void USB::onDeviceDisconnected(WebPassOwnPtr<WebUSBDevice> device) 267 device::usb::blink::DevicePtr device;
152 { 268 m_deviceManager->GetDevice(notification->devices_added[i]->guid, mojo::G etProxy(&device));
153 dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevi ce::create(device.release(), getExecutionContext()))); 269 dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDev ice::create(std::move(notification->devices_added[i]), std::move(device), getExe cutionContext())));
270 }
271 for (size_t i = 0; i < notification->devices_removed.size(); ++i)
272 dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USB Device::create(std::move(notification->devices_removed[i]), nullptr, getExecutio nContext())));
154 } 273 }
155 274
156 DEFINE_TRACE(USB) 275 DEFINE_TRACE(USB)
157 { 276 {
158 RefCountedGarbageCollectedEventTargetWithInlineData<USB>::trace(visitor); 277 RefCountedGarbageCollectedEventTargetWithInlineData<USB>::trace(visitor);
159 ContextLifecycleObserver::trace(visitor); 278 ContextLifecycleObserver::trace(visitor);
160 } 279 }
161 280
162 } // namespace blink 281 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698