Index: third_party/WebKit/Source/modules/webusb/USB.cpp |
diff --git a/third_party/WebKit/Source/modules/webusb/USB.cpp b/third_party/WebKit/Source/modules/webusb/USB.cpp |
index 3bd8b8fc2ed3e2bf0c951120c0da1548f8850d94..07e4a442343872abd708661387ca1da73e6a3861 100644 |
--- a/third_party/WebKit/Source/modules/webusb/USB.cpp |
+++ b/third_party/WebKit/Source/modules/webusb/USB.cpp |
@@ -4,7 +4,6 @@ |
#include "modules/webusb/USB.h" |
-#include "bindings/core/v8/CallbackPromiseAdapter.h" |
#include "bindings/core/v8/ScriptPromise.h" |
#include "bindings/core/v8/ScriptPromiseResolver.h" |
#include "core/dom/DOMException.h" |
@@ -12,117 +11,235 @@ |
#include "core/dom/ExceptionCode.h" |
#include "modules/EventTargetModules.h" |
#include "modules/webusb/USBConnectionEvent.h" |
-#include "modules/webusb/USBController.h" |
#include "modules/webusb/USBDevice.h" |
#include "modules/webusb/USBDeviceFilter.h" |
#include "modules/webusb/USBDeviceRequestOptions.h" |
-#include "modules/webusb/USBError.h" |
#include "platform/UserGestureIndicator.h" |
-#include "public/platform/Platform.h" |
-#include "public/platform/WebVector.h" |
-#include "public/platform/modules/webusb/WebUSBClient.h" |
-#include "public/platform/modules/webusb/WebUSBDeviceFilter.h" |
-#include "public/platform/modules/webusb/WebUSBDeviceRequestOptions.h" |
-#include "public/platform/modules/webusb/WebUSBError.h" |
+#include "public/platform/ServiceRegistry.h" |
namespace blink { |
namespace { |
-void convertDeviceFilter(const USBDeviceFilter& filter, WebUSBDeviceFilter* webFilter) |
+const char kNoServiceError[] = "USB service unavailable."; |
+ |
+device::usb::blink::DeviceFilterPtr convertDeviceFilter(const USBDeviceFilter& filter) |
{ |
- webFilter->hasVendorID = filter.hasVendorId(); |
- if (filter.hasVendorId()) |
- webFilter->vendorID = filter.vendorId(); |
- webFilter->hasProductID = filter.hasProductId(); |
- if (filter.hasProductId()) |
- webFilter->productID = filter.productId(); |
- webFilter->hasClassCode = filter.hasClassCode(); |
- if (filter.hasClassCode()) |
- webFilter->classCode = filter.classCode(); |
- webFilter->hasSubclassCode = filter.hasSubclassCode(); |
- if (filter.hasSubclassCode()) |
- webFilter->subclassCode = filter.subclassCode(); |
- webFilter->hasProtocolCode = filter.hasProtocolCode(); |
- if (filter.hasProtocolCode()) |
- webFilter->protocolCode = filter.protocolCode(); |
+ auto mojoFilter = device::usb::blink::DeviceFilter::New(); |
+ mojoFilter->has_vendor_id = filter.hasVendorId(); |
+ if (mojoFilter->has_vendor_id) |
+ mojoFilter->vendor_id = filter.vendorId(); |
+ mojoFilter->has_product_id = filter.hasProductId(); |
+ if (mojoFilter->has_product_id) |
+ mojoFilter->product_id = filter.productId(); |
+ mojoFilter->has_class_code = filter.hasClassCode(); |
+ if (mojoFilter->has_class_code) |
+ mojoFilter->class_code = filter.classCode(); |
+ mojoFilter->has_subclass_code = filter.hasSubclassCode(); |
+ if (mojoFilter->has_subclass_code) |
+ mojoFilter->subclass_code = filter.subclassCode(); |
+ mojoFilter->has_protocol_code = filter.hasProtocolCode(); |
+ if (mojoFilter->has_protocol_code) |
+ mojoFilter->protocol_code = filter.protocolCode(); |
+ return mojoFilter; |
} |
-void convertDeviceRequestOptions(const USBDeviceRequestOptions& options, WebUSBDeviceRequestOptions* webOptions) |
-{ |
- DCHECK(options.hasFilters()); |
- webOptions->filters = WebVector<WebUSBDeviceFilter>(options.filters().size()); |
- for (size_t i = 0; i < options.filters().size(); ++i) { |
- convertDeviceFilter(options.filters()[i], &webOptions->filters[i]); |
+class DeviceChangeNotificationAdapter : public device::usb::blink::DeviceManager::GetDeviceChangesCallback::Runnable { |
+ WTF_MAKE_NONCOPYABLE(DeviceChangeNotificationAdapter); |
+ |
+public: |
+ DeviceChangeNotificationAdapter(USB* usb) : m_usb(usb) |
+ { |
+ } |
+ |
+ void Run(device::usb::blink::DeviceChangeNotificationPtr notification) const |
+ { |
+ if (m_usb) |
+ m_usb->onDeviceChanges(std::move(notification)); |
} |
-} |
-// Allows using a CallbackPromiseAdapter with a WebVector to resolve the |
-// getDevices() promise with a HeapVector owning USBDevices. |
-class DeviceArray { |
- STATIC_ONLY(DeviceArray); |
+ device::usb::blink::DeviceManager::GetDeviceChangesCallback callback() |
+ { |
+ return device::usb::blink::DeviceManager::GetDeviceChangesCallback(this); |
+ } |
+ |
+private: |
+ WeakPersistent<USB> m_usb; |
+}; |
+ |
+template <typename Callback> |
+class PromiseAdapterBase : public Callback::Runnable { |
+ WTF_MAKE_NONCOPYABLE(PromiseAdapterBase); |
+ |
public: |
- using WebType = OwnPtr<WebVector<WebUSBDevice*>>; |
+ PromiseAdapterBase(ScriptPromiseResolver* resolver) : m_resolver(resolver) |
+ { |
+ } |
- static HeapVector<Member<USBDevice>> take(ScriptPromiseResolver* resolver, PassOwnPtr<WebVector<WebUSBDevice*>> webDevices) |
+ ~PromiseAdapterBase() override |
{ |
+ if (active()) |
+ m_resolver->reject(DOMException::create(NotFoundError, kNoServiceError)); |
+ } |
+ |
+ template <typename T> |
+ void resolve(T value) const |
+ { |
+ ASSERT(active()); |
+ m_resolver->resolve(value); |
+ m_resolver = nullptr; |
+ } |
+ |
+ template <typename T> |
+ void reject(T value) const |
+ { |
+ ASSERT(active()); |
+ m_resolver->reject(value); |
+ m_resolver = nullptr; |
+ } |
+ |
+ bool active() const |
+ { |
+ return m_resolver && executionContext() && !executionContext()->activeDOMObjectsAreStopped(); |
+ } |
+ |
+ Callback callback() |
+ { |
+ return Callback(this); |
+ } |
+ |
+ ExecutionContext* executionContext() const { return m_resolver->getExecutionContext(); } |
+ |
+private: |
+ // This field is mutable so that resolve() and reject() can be called from |
+ // 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
|
+ mutable Persistent<ScriptPromiseResolver> m_resolver; |
+}; |
+ |
+class GetDevicesPromiseAdapter : public PromiseAdapterBase<device::usb::blink::DeviceManager::GetDevicesCallback> { |
+ WTF_MAKE_NONCOPYABLE(GetDevicesPromiseAdapter); |
+ |
+public: |
+ GetDevicesPromiseAdapter(USB* usb, ScriptPromiseResolver* resolver) |
+ : PromiseAdapterBase(resolver) |
+ , m_usb(usb) |
+ { |
+ } |
+ |
+ void Run(mojo::WTFArray<device::usb::blink::DeviceInfoPtr> deviceInfos) const override |
+ { |
+ if (!active()) |
+ return; |
+ |
HeapVector<Member<USBDevice>> devices; |
- for (const auto webDevice : *webDevices) |
- devices.append(USBDevice::create(adoptPtr(webDevice), resolver->getExecutionContext())); |
- return devices; |
+ 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.
|
+ device::usb::blink::DevicePtr device; |
+ m_usb->deviceManager()->GetDevice(deviceInfos[i]->guid, mojo::GetProxy(&device)); |
+ devices.append(USBDevice::create(std::move(deviceInfos[i]), std::move(device), executionContext())); |
+ } |
+ resolve(devices); |
+ } |
+ |
+private: |
+ Persistent<USB> m_usb; |
+}; |
+ |
+class GetPermissionPromiseAdapter : public PromiseAdapterBase<device::usb::blink::ChooserService::GetPermissionCallback> { |
+ WTF_MAKE_NONCOPYABLE(GetPermissionPromiseAdapter); |
+ |
+public: |
+ GetPermissionPromiseAdapter(USB* usb, ScriptPromiseResolver* resolver) |
+ : PromiseAdapterBase(resolver) |
+ , m_usb(usb) |
+ { |
+ } |
+ |
+ void Run(device::usb::blink::DeviceInfoPtr deviceInfo) const override |
+ { |
+ if (!active()) |
+ return; |
+ |
+ if (deviceInfo) { |
+ device::usb::blink::DevicePtr device; |
+ m_usb->deviceManager()->GetDevice(deviceInfo->guid, mojo::GetProxy(&device)); |
+ resolve(USBDevice::create(std::move(deviceInfo), std::move(device), executionContext())); |
+ } else { |
+ reject(DOMException::create(NotFoundError, "No device selected.")); |
+ } |
} |
+ |
+private: |
+ Persistent<USB> m_usb; |
}; |
} // namespace |
USB::USB(LocalFrame& frame) |
: ContextLifecycleObserver(frame.document()) |
- , m_client(USBController::from(frame).client()) |
{ |
- if (m_client) |
- m_client->addObserver(this); |
+ frame.serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_deviceManager)); |
+ m_deviceManager.set_connection_error_handler([this]() { |
+ m_deviceManager.reset(); |
+ }); |
+ auto adapter = new DeviceChangeNotificationAdapter(this); |
+ m_deviceManager->GetDeviceChanges(adapter->callback()); |
+ adapter = new DeviceChangeNotificationAdapter(this); |
+ 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
|
} |
USB::~USB() |
{ |
- if (m_client) |
- m_client->removeObserver(this); |
} |
ScriptPromise USB::getDevices(ScriptState* scriptState) |
{ |
- if (!m_client) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
- |
- String errorMessage; |
- if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage)); |
- |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
ScriptPromise promise = resolver->promise(); |
- m_client->getDevices(new CallbackPromiseAdapter<DeviceArray, USBError>(resolver)); |
- |
+ if (!m_deviceManager) { |
+ resolver->reject(DOMException::create(NotSupportedError)); |
+ } else { |
+ String errorMessage; |
+ if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) { |
+ resolver->reject(DOMException::create(SecurityError, errorMessage)); |
+ } else { |
+ auto adapter = new GetDevicesPromiseAdapter(this, resolver); |
+ m_deviceManager->GetDevices(nullptr, adapter->callback()); |
+ } |
+ } |
return promise; |
} |
ScriptPromise USB::requestDevice(ScriptState* scriptState, const USBDeviceRequestOptions& options) |
{ |
- if (!m_client) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
- |
- String errorMessage; |
- if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage)); |
- |
- if (!UserGestureIndicator::consumeUserGesture()) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, "Must be handling a user gesture to show a permission request.")); |
- |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
ScriptPromise promise = resolver->promise(); |
- WebUSBDeviceRequestOptions webOptions; |
- convertDeviceRequestOptions(options, &webOptions); |
- m_client->requestDevice(webOptions, new CallbackPromiseAdapter<USBDevice, USBError>(resolver)); |
+ if (!m_chooserService) { |
+ LocalFrame* frame = getExecutionContext() ? static_cast<Document*>(getExecutionContext())->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.
|
+ if (!frame) { |
+ resolver->reject(DOMException::create(NotSupportedError)); |
+ return promise; |
+ } |
+ frame->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_chooserService)); |
+ m_chooserService.set_connection_error_handler([this]() { |
+ m_chooserService.reset(); |
+ }); |
+ } |
+ String errorMessage; |
+ if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) { |
+ resolver->reject(DOMException::create(SecurityError, errorMessage)); |
+ } else if (!UserGestureIndicator::consumeUserGesture()) { |
+ resolver->reject(DOMException::create(SecurityError, "Must be handling a user gesture to show a permission request.")); |
+ } else { |
+ mojo::WTFArray<device::usb::blink::DeviceFilterPtr> mojoFilters(options.hasFilters() ? options.filters().size() : 0); |
+ if (options.hasFilters()) { |
+ const auto& filters = options.filters(); |
+ for (size_t i = 0; i < filters.size(); ++i) |
+ mojoFilters[i] = convertDeviceFilter(filters[i]); |
+ } |
+ auto adapter = new GetPermissionPromiseAdapter(this, resolver); |
+ m_chooserService->GetPermission(std::move(mojoFilters), adapter->callback()); |
+ } |
return promise; |
} |
@@ -138,19 +255,21 @@ const AtomicString& USB::interfaceName() const |
void USB::contextDestroyed() |
{ |
- if (m_client) |
- m_client->removeObserver(this); |
- m_client = nullptr; |
+ m_deviceManager.reset(); |
+ m_chooserService.reset(); |
} |
-void USB::onDeviceConnected(WebPassOwnPtr<WebUSBDevice> device) |
+void USB::onDeviceChanges(device::usb::blink::DeviceChangeNotificationPtr notification) |
{ |
- dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice::create(device.release(), getExecutionContext()))); |
-} |
- |
-void USB::onDeviceDisconnected(WebPassOwnPtr<WebUSBDevice> device) |
-{ |
- dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevice::create(device.release(), getExecutionContext()))); |
+ auto adapter = new DeviceChangeNotificationAdapter(this); |
+ m_deviceManager->GetDeviceChanges(adapter->callback()); |
+ for (size_t i = 0; i < notification->devices_added.size(); ++i) { |
+ device::usb::blink::DevicePtr device; |
+ m_deviceManager->GetDevice(notification->devices_added[i]->guid, mojo::GetProxy(&device)); |
+ dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice::create(std::move(notification->devices_added[i]), std::move(device), getExecutionContext()))); |
+ } |
+ for (size_t i = 0; i < notification->devices_removed.size(); ++i) |
+ dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevice::create(std::move(notification->devices_removed[i]), nullptr, getExecutionContext()))); |
} |
DEFINE_TRACE(USB) |