0

Consume Mojo services directly in Blink's WebUSB implementation.

This patch takes advantage of the ability to consume a Mojo service
directly in //third_party/WebKit/Source/modules to remove the
//third_party/WebKit/public/platform/modules/webusb,
//content/renderer/usb and the rest of that intermediate layer.

BUG=None

Review URL: https://codereview.chromium.org/1850023002

Cr-Commit-Position: refs/heads/master@{#388571}
This commit is contained in:
reillyg
2016-04-20 13:45:29 -07:00
committed by Commit bot
parent 8afa1543da
commit 1b995c58c4
48 changed files with 686 additions and 2323 deletions

@ -13,7 +13,6 @@
'../components/url_formatter/url_formatter.gyp:url_formatter',
'../device/battery/battery.gyp:device_battery',
'../device/battery/battery.gyp:device_battery_mojo_bindings',
'../device/usb/usb.gyp:device_usb_mojo_bindings',
'../device/vibration/vibration.gyp:device_vibration',
'../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
'../gin/gin.gyp:gin',
@ -465,12 +464,6 @@
'renderer/theme_helper_mac.mm',
'renderer/top_level_blame_context.cc',
'renderer/top_level_blame_context.h',
'renderer/usb/type_converters.cc',
'renderer/usb/type_converters.h',
'renderer/usb/web_usb_client_impl.cc',
'renderer/usb/web_usb_client_impl.h',
'renderer/usb/web_usb_device_impl.cc',
'renderer/usb/web_usb_device_impl.h',
'renderer/web_frame_utils.cc',
'renderer/web_frame_utils.h',
'renderer/web_ui_extension.cc',

@ -125,7 +125,6 @@
#include "content/renderer/shared_worker_repository.h"
#include "content/renderer/skia_benchmarking_extension.h"
#include "content/renderer/stats_collection_controller.h"
#include "content/renderer/usb/web_usb_client_impl.h"
#include "content/renderer/web_frame_utils.h"
#include "content/renderer/web_ui_extension.h"
#include "content/renderer/websharedworker_proxy.h"
@ -161,7 +160,6 @@
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBClient.h"
#include "third_party/WebKit/public/web/WebColorSuggestion.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFindOptions.h"
@ -4285,16 +4283,6 @@ blink::WebBluetooth* RenderFrameImpl::bluetooth() {
return bluetooth_.get();
}
blink::WebUSBClient* RenderFrameImpl::usbClient() {
if (!base::FeatureList::IsEnabled(features::kWebUsb))
return nullptr;
if (!usb_client_)
usb_client_.reset(new WebUSBClientImpl(GetServiceRegistry()));
return usb_client_.get();
}
#if defined(ENABLE_WEBVR)
blink::WebVRClient* RenderFrameImpl::webVRClient() {
if (!vr_dispatcher_)

@ -616,7 +616,6 @@ class CONTENT_EXPORT RenderFrameImpl
void unregisterProtocolHandler(const blink::WebString& scheme,
const blink::WebURL& url) override;
blink::WebBluetooth* bluetooth() override;
blink::WebUSBClient* usbClient() override;
void checkIfAudioSinkExistsAndIsAuthorized(
const blink::WebString& sink_id,
const blink::WebSecurityOrigin& security_origin,
@ -1193,8 +1192,6 @@ class CONTENT_EXPORT RenderFrameImpl
std::unique_ptr<blink::WebBluetooth> bluetooth_;
std::unique_ptr<blink::WebUSBClient> usb_client_;
// Manages play, pause notifications for WebMediaPlayer implementations; its
// lifetime is tied to the RenderFrame via the RenderFrameObserver interface.
media::RendererWebMediaPlayerDelegate* media_player_delegate_;

@ -1,3 +0,0 @@
include_rules = [
"+device/usb/public",
]

@ -1,2 +0,0 @@
reillyg@chromium.org
rockot@chromium.org

@ -1,262 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/usb/type_converters.h"
#include <stddef.h>
#include "base/logging.h"
namespace mojo {
// static
blink::WebUSBDevice::TransferDirection
TypeConverter<blink::WebUSBDevice::TransferDirection,
device::usb::TransferDirection>::
Convert(const device::usb::TransferDirection& direction) {
switch (direction) {
case device::usb::TransferDirection::INBOUND:
return blink::WebUSBDevice::TransferDirection::In;
case device::usb::TransferDirection::OUTBOUND:
return blink::WebUSBDevice::TransferDirection::Out;
default:
NOTREACHED();
return blink::WebUSBDevice::TransferDirection::In;
}
}
// static
device::usb::TransferDirection
TypeConverter<device::usb::TransferDirection,
blink::WebUSBDevice::TransferDirection>::
Convert(const blink::WebUSBDevice::TransferDirection& direction) {
switch (direction) {
case blink::WebUSBDevice::TransferDirection::In:
return device::usb::TransferDirection::INBOUND;
case blink::WebUSBDevice::TransferDirection::Out:
return device::usb::TransferDirection::OUTBOUND;
default:
NOTREACHED();
return device::usb::TransferDirection::INBOUND;
}
}
// static
device::usb::ControlTransferType
TypeConverter<device::usb::ControlTransferType,
blink::WebUSBDevice::RequestType>::
Convert(const blink::WebUSBDevice::RequestType& direction) {
switch (direction) {
case blink::WebUSBDevice::RequestType::Standard:
return device::usb::ControlTransferType::STANDARD;
case blink::WebUSBDevice::RequestType::Class:
return device::usb::ControlTransferType::CLASS;
case blink::WebUSBDevice::RequestType::Vendor:
return device::usb::ControlTransferType::VENDOR;
default:
NOTREACHED();
return device::usb::ControlTransferType::STANDARD;
}
}
// static
device::usb::ControlTransferRecipient
TypeConverter<device::usb::ControlTransferRecipient,
blink::WebUSBDevice::RequestRecipient>::
Convert(const blink::WebUSBDevice::RequestRecipient& direction) {
switch (direction) {
case blink::WebUSBDevice::RequestRecipient::Device:
return device::usb::ControlTransferRecipient::DEVICE;
case blink::WebUSBDevice::RequestRecipient::Interface:
return device::usb::ControlTransferRecipient::INTERFACE;
case blink::WebUSBDevice::RequestRecipient::Endpoint:
return device::usb::ControlTransferRecipient::ENDPOINT;
case blink::WebUSBDevice::RequestRecipient::Other:
return device::usb::ControlTransferRecipient::OTHER;
default:
NOTREACHED();
return device::usb::ControlTransferRecipient::DEVICE;
}
}
// static
device::usb::ControlTransferParamsPtr
TypeConverter<device::usb::ControlTransferParamsPtr,
blink::WebUSBDevice::ControlTransferParameters>::
Convert(const blink::WebUSBDevice::ControlTransferParameters& parameters) {
device::usb::ControlTransferParamsPtr params =
device::usb::ControlTransferParams::New();
params->type =
mojo::ConvertTo<device::usb::ControlTransferType>(parameters.type);
params->recipient = mojo::ConvertTo<device::usb::ControlTransferRecipient>(
parameters.recipient);
params->request = parameters.request;
params->value = parameters.value;
params->index = parameters.index;
return params;
}
// static
blink::WebUSBDeviceInfo::Endpoint::Type TypeConverter<
blink::WebUSBDeviceInfo::Endpoint::Type,
device::usb::EndpointType>::Convert(const device::usb::EndpointType&
endpoint_type) {
switch (endpoint_type) {
case device::usb::EndpointType::BULK:
return blink::WebUSBDeviceInfo::Endpoint::Type::Bulk;
case device::usb::EndpointType::INTERRUPT:
return blink::WebUSBDeviceInfo::Endpoint::Type::Interrupt;
case device::usb::EndpointType::ISOCHRONOUS:
return blink::WebUSBDeviceInfo::Endpoint::Type::Isochronous;
default:
NOTREACHED();
return blink::WebUSBDeviceInfo::Endpoint::Type::Bulk;
}
}
// static
blink::WebUSBDeviceInfo::Endpoint
TypeConverter<blink::WebUSBDeviceInfo::Endpoint, device::usb::EndpointInfoPtr>::
Convert(const device::usb::EndpointInfoPtr& info) {
blink::WebUSBDeviceInfo::Endpoint endpoint;
endpoint.endpointNumber = info->endpoint_number;
endpoint.direction =
mojo::ConvertTo<blink::WebUSBDevice::TransferDirection>(info->direction);
endpoint.type =
mojo::ConvertTo<blink::WebUSBDeviceInfo::Endpoint::Type>(info->type);
endpoint.packetSize = info->packet_size;
return endpoint;
}
// static
blink::WebUSBDeviceInfo::AlternateInterface
TypeConverter<blink::WebUSBDeviceInfo::AlternateInterface,
device::usb::AlternateInterfaceInfoPtr>::
Convert(const device::usb::AlternateInterfaceInfoPtr& info) {
blink::WebUSBDeviceInfo::AlternateInterface alternate;
alternate.alternateSetting = info->alternate_setting;
alternate.classCode = info->class_code;
alternate.subclassCode = info->subclass_code;
alternate.protocolCode = info->protocol_code;
if (!info->interface_name.is_null())
alternate.interfaceName = blink::WebString::fromUTF8(info->interface_name);
alternate.endpoints = blink::WebVector<blink::WebUSBDeviceInfo::Endpoint>(
info->endpoints.size());
for (size_t i = 0; i < info->endpoints.size(); ++i) {
alternate.endpoints[i] =
mojo::ConvertTo<blink::WebUSBDeviceInfo::Endpoint>(info->endpoints[i]);
}
return alternate;
}
// static
blink::WebUSBDeviceInfo::Interface TypeConverter<
blink::WebUSBDeviceInfo::Interface,
device::usb::InterfaceInfoPtr>::Convert(const device::usb::InterfaceInfoPtr&
info) {
blink::WebUSBDeviceInfo::Interface interface;
interface.interfaceNumber = info->interface_number;
interface.alternates =
blink::WebVector<blink::WebUSBDeviceInfo::AlternateInterface>(
info->alternates.size());
for (size_t i = 0; i < info->alternates.size(); ++i) {
interface.alternates[i] =
mojo::ConvertTo<blink::WebUSBDeviceInfo::AlternateInterface>(
info->alternates[i]);
}
return interface;
}
// static
blink::WebUSBDeviceInfo::Configuration
TypeConverter<blink::WebUSBDeviceInfo::Configuration,
device::usb::ConfigurationInfoPtr>::
Convert(const device::usb::ConfigurationInfoPtr& info) {
blink::WebUSBDeviceInfo::Configuration config;
config.configurationValue = info->configuration_value;
if (!info->configuration_name.is_null()) {
config.configurationName =
blink::WebString::fromUTF8(info->configuration_name);
}
config.interfaces = blink::WebVector<blink::WebUSBDeviceInfo::Interface>(
info->interfaces.size());
for (size_t i = 0; i < info->interfaces.size(); ++i) {
config.interfaces[i] = mojo::ConvertTo<blink::WebUSBDeviceInfo::Interface>(
info->interfaces[i]);
}
return config;
}
// static
blink::WebUSBDeviceInfo
TypeConverter<blink::WebUSBDeviceInfo, device::usb::DeviceInfoPtr>::Convert(
const device::usb::DeviceInfoPtr& info) {
blink::WebUSBDeviceInfo device;
device.guid = blink::WebString::fromUTF8(info->guid);
device.usbVersionMajor = info->usb_version_major;
device.usbVersionMinor = info->usb_version_minor;
device.usbVersionSubminor = info->usb_version_subminor;
device.deviceClass = info->class_code;
device.deviceSubclass = info->subclass_code;
device.deviceProtocol = info->protocol_code;
device.vendorID = info->vendor_id;
device.productID = info->product_id;
device.deviceVersionMajor = info->device_version_major;
device.deviceVersionMinor = info->device_version_minor;
device.deviceVersionSubminor = info->device_version_subminor;
if (!info->manufacturer_name.is_null()) {
device.manufacturerName =
blink::WebString::fromUTF8(info->manufacturer_name);
}
if (!info->product_name.is_null())
device.productName = blink::WebString::fromUTF8(info->product_name);
if (!info->serial_number.is_null())
device.serialNumber = blink::WebString::fromUTF8(info->serial_number);
device.activeConfiguration = info->active_configuration;
device.configurations =
blink::WebVector<blink::WebUSBDeviceInfo::Configuration>(
info->configurations.size());
for (size_t i = 0; i < info->configurations.size(); ++i) {
device.configurations[i] =
mojo::ConvertTo<blink::WebUSBDeviceInfo::Configuration>(
info->configurations[i]);
}
return device;
}
// static
device::usb::DeviceFilterPtr
TypeConverter<device::usb::DeviceFilterPtr, blink::WebUSBDeviceFilter>::Convert(
const blink::WebUSBDeviceFilter& web_filter) {
device::usb::DeviceFilterPtr filter = device::usb::DeviceFilter::New();
filter->has_vendor_id = web_filter.hasVendorID;
filter->vendor_id = web_filter.vendorID;
filter->has_product_id = web_filter.hasProductID;
filter->product_id = web_filter.productID;
filter->has_class_code = web_filter.hasClassCode;
filter->class_code = web_filter.classCode;
filter->has_subclass_code = web_filter.hasSubclassCode;
filter->subclass_code = web_filter.subclassCode;
filter->has_protocol_code = web_filter.hasProtocolCode;
filter->protocol_code = web_filter.protocolCode;
return filter;
}
// static
device::usb::EnumerationOptionsPtr
TypeConverter<device::usb::EnumerationOptionsPtr,
blink::WebUSBDeviceRequestOptions>::
Convert(const blink::WebUSBDeviceRequestOptions& web_options) {
device::usb::EnumerationOptionsPtr options =
device::usb::EnumerationOptions::New();
options->filters = mojo::Array<device::usb::DeviceFilterPtr>::New(
web_options.filters.size());
for (size_t i = 0; i < web_options.filters.size(); ++i) {
options->filters[i] =
device::usb::DeviceFilter::From(web_options.filters[i]);
}
return options;
}
} // namespace mojo

@ -1,105 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/public/cpp/bindings/type_converter.h"
#include "device/usb/public/interfaces/device.mojom.h"
#include "device/usb/public/interfaces/device_manager.mojom.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDevice.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceFilter.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceRequestOptions.h"
namespace mojo {
template <>
struct TypeConverter<blink::WebUSBDevice::TransferDirection,
device::usb::TransferDirection> {
static blink::WebUSBDevice::TransferDirection Convert(
const device::usb::TransferDirection& direction);
};
template <>
struct TypeConverter<device::usb::TransferDirection,
blink::WebUSBDevice::TransferDirection> {
static device::usb::TransferDirection Convert(
const blink::WebUSBDevice::TransferDirection& direction);
};
template <>
struct TypeConverter<device::usb::ControlTransferType,
blink::WebUSBDevice::RequestType> {
static device::usb::ControlTransferType Convert(
const blink::WebUSBDevice::RequestType& direction);
};
template <>
struct TypeConverter<device::usb::ControlTransferRecipient,
blink::WebUSBDevice::RequestRecipient> {
static device::usb::ControlTransferRecipient Convert(
const blink::WebUSBDevice::RequestRecipient& direction);
};
template <>
struct TypeConverter<device::usb::ControlTransferParamsPtr,
blink::WebUSBDevice::ControlTransferParameters> {
static device::usb::ControlTransferParamsPtr Convert(
const blink::WebUSBDevice::ControlTransferParameters& parameters);
};
template <>
struct TypeConverter<blink::WebUSBDeviceInfo::Endpoint::Type,
device::usb::EndpointType> {
static blink::WebUSBDeviceInfo::Endpoint::Type Convert(
const device::usb::EndpointType& endpoint_type);
};
template <>
struct TypeConverter<blink::WebUSBDeviceInfo::Endpoint,
device::usb::EndpointInfoPtr> {
static blink::WebUSBDeviceInfo::Endpoint Convert(
const device::usb::EndpointInfoPtr& info);
};
template <>
struct TypeConverter<blink::WebUSBDeviceInfo::AlternateInterface,
device::usb::AlternateInterfaceInfoPtr> {
static blink::WebUSBDeviceInfo::AlternateInterface Convert(
const device::usb::AlternateInterfaceInfoPtr& info);
};
template <>
struct TypeConverter<blink::WebUSBDeviceInfo::Interface,
device::usb::InterfaceInfoPtr> {
static blink::WebUSBDeviceInfo::Interface Convert(
const device::usb::InterfaceInfoPtr& info);
};
template <>
struct TypeConverter<blink::WebUSBDeviceInfo::Configuration,
device::usb::ConfigurationInfoPtr> {
static blink::WebUSBDeviceInfo::Configuration Convert(
const device::usb::ConfigurationInfoPtr& info);
};
template <>
struct TypeConverter<blink::WebUSBDeviceInfo, device::usb::DeviceInfoPtr> {
static blink::WebUSBDeviceInfo Convert(
const device::usb::DeviceInfoPtr& info);
};
template <>
struct TypeConverter<device::usb::DeviceFilterPtr, blink::WebUSBDeviceFilter> {
static device::usb::DeviceFilterPtr Convert(
const blink::WebUSBDeviceFilter& web_filter);
};
template <>
struct TypeConverter<device::usb::EnumerationOptionsPtr,
blink::WebUSBDeviceRequestOptions> {
static device::usb::EnumerationOptionsPtr Convert(
const blink::WebUSBDeviceRequestOptions& web_options);
};
} // namespace mojo

@ -1,180 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/usb/web_usb_client_impl.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "base/move.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/child/mojo/type_converters.h"
#include "content/child/scoped_web_callbacks.h"
#include "content/public/common/service_registry.h"
#include "content/renderer/usb/type_converters.h"
#include "content/renderer/usb/web_usb_device_impl.h"
#include "mojo/public/cpp/bindings/array.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "third_party/WebKit/public/platform/WebCallbacks.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceFilter.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceRequestOptions.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBError.h"
namespace content {
namespace {
const char kNoServiceError[] = "USB service unavailable.";
// Generic default rejection handler for any WebUSB callbacks type. Assumes
// |CallbacksType| is a blink::WebCallbacks<T, const blink::WebUSBError&>
// for any type |T|.
template <typename CallbacksType>
void RejectCallbacksWithError(const blink::WebUSBError& error,
std::unique_ptr<CallbacksType> callbacks) {
callbacks->onError(error);
}
// Create a new ScopedWebCallbacks for WebUSB client callbacks, defaulting to
// a "no service" rejection.
template <typename CallbacksType>
ScopedWebCallbacks<CallbacksType> MakeScopedUSBCallbacks(
CallbacksType* callbacks) {
return make_scoped_web_callbacks(
callbacks,
base::Bind(&RejectCallbacksWithError<CallbacksType>,
blink::WebUSBError(blink::WebUSBError::Error::NotFound,
base::ASCIIToUTF16(kNoServiceError))));
}
void OnGetDevicesComplete(
ScopedWebCallbacks<blink::WebUSBClientGetDevicesCallbacks> scoped_callbacks,
device::usb::DeviceManager* device_manager,
mojo::Array<device::usb::DeviceInfoPtr> results) {
// TODO(dcheng): This WebVector should hold smart pointers.
std::unique_ptr<blink::WebVector<blink::WebUSBDevice*>> devices(
new blink::WebVector<blink::WebUSBDevice*>(results.size()));
for (size_t i = 0; i < results.size(); ++i) {
device::usb::DevicePtr device;
device_manager->GetDevice(results[i]->guid, mojo::GetProxy(&device));
(*devices)[i] = new WebUSBDeviceImpl(
std::move(device),
mojo::ConvertTo<blink::WebUSBDeviceInfo>(results[i]));
}
scoped_callbacks.PassCallbacks()->onSuccess(std::move(devices));
}
void OnRequestDevicesComplete(
ScopedWebCallbacks<blink::WebUSBClientRequestDeviceCallbacks> callbacks,
device::usb::DeviceManager* device_manager,
device::usb::DeviceInfoPtr result) {
auto scoped_callbacks = callbacks.PassCallbacks();
if (result) {
device::usb::DevicePtr device;
device_manager->GetDevice(result->guid, mojo::GetProxy(&device));
std::unique_ptr<blink::WebUSBDevice> web_usb_device(new WebUSBDeviceImpl(
std::move(device), mojo::ConvertTo<blink::WebUSBDeviceInfo>(result)));
scoped_callbacks->onSuccess(std::move(web_usb_device));
} else {
scoped_callbacks->onError(
blink::WebUSBError(blink::WebUSBError::Error::NotFound,
base::ASCIIToUTF16("No device selected.")));
}
}
} // namespace
WebUSBClientImpl::WebUSBClientImpl(content::ServiceRegistry* service_registry)
: service_registry_(service_registry) {}
WebUSBClientImpl::~WebUSBClientImpl() {}
void WebUSBClientImpl::getDevices(
blink::WebUSBClientGetDevicesCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
GetDeviceManager()->GetDevices(
nullptr,
base::Bind(&OnGetDevicesComplete, base::Passed(&scoped_callbacks),
base::Unretained(device_manager_.get())));
}
void WebUSBClientImpl::requestDevice(
const blink::WebUSBDeviceRequestOptions& options,
blink::WebUSBClientRequestDeviceCallbacks* callbacks) {
if (!chooser_service_) {
service_registry_->ConnectToRemoteService(
mojo::GetProxy(&chooser_service_));
}
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
mojo::Array<device::usb::DeviceFilterPtr> device_filters =
mojo::Array<device::usb::DeviceFilterPtr>::From(options.filters);
chooser_service_->GetPermission(
std::move(device_filters),
base::Bind(&OnRequestDevicesComplete, base::Passed(&scoped_callbacks),
base::Unretained(device_manager_.get())));
}
void WebUSBClientImpl::addObserver(Observer* observer) {
if (observers_.empty()) {
// Set up two sequential calls to GetDeviceChanges to avoid latency.
device::usb::DeviceManager* device_manager = GetDeviceManager();
device_manager->GetDeviceChanges(base::Bind(
&WebUSBClientImpl::OnDeviceChangeNotification, base::Unretained(this)));
device_manager->GetDeviceChanges(base::Bind(
&WebUSBClientImpl::OnDeviceChangeNotification, base::Unretained(this)));
}
observers_.insert(observer);
}
void WebUSBClientImpl::removeObserver(Observer* observer) {
DCHECK(ContainsKey(observers_, observer));
observers_.erase(observer);
}
device::usb::DeviceManager* WebUSBClientImpl::GetDeviceManager() {
if (!device_manager_)
service_registry_->ConnectToRemoteService(mojo::GetProxy(&device_manager_));
return device_manager_.get();
}
void WebUSBClientImpl::OnDeviceChangeNotification(
device::usb::DeviceChangeNotificationPtr notification) {
if (observers_.empty())
return;
device_manager_->GetDeviceChanges(base::Bind(
&WebUSBClientImpl::OnDeviceChangeNotification, base::Unretained(this)));
for (size_t i = 0; i < notification->devices_added.size(); ++i) {
const device::usb::DeviceInfoPtr& device_info =
notification->devices_added[i];
for (auto observer : observers_) {
device::usb::DevicePtr device;
device_manager_->GetDevice(device_info->guid, mojo::GetProxy(&device));
observer->onDeviceConnected(base::WrapUnique(new WebUSBDeviceImpl(
std::move(device),
mojo::ConvertTo<blink::WebUSBDeviceInfo>(device_info))));
}
}
for (size_t i = 0; i < notification->devices_removed.size(); ++i) {
const device::usb::DeviceInfoPtr& device_info =
notification->devices_removed[i];
for (auto observer : observers_)
observer->onDeviceDisconnected(base::WrapUnique(new WebUSBDeviceImpl(
nullptr, mojo::ConvertTo<blink::WebUSBDeviceInfo>(device_info))));
}
}
} // namespace content

@ -1,45 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_RENDERER_USB_WEB_USB_CLIENT_IMPL_H_
#define CONTENT_RENDERER_USB_WEB_USB_CLIENT_IMPL_H_
#include "base/macros.h"
#include "device/usb/public/interfaces/chooser_service.mojom.h"
#include "device/usb/public/interfaces/device_manager.mojom.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBClient.h"
namespace content {
class ServiceRegistry;
class WebUSBClientImpl : public blink::WebUSBClient {
public:
explicit WebUSBClientImpl(ServiceRegistry* service_registry);
~WebUSBClientImpl() override;
private:
// blink::WebUSBClient implementation:
void getDevices(blink::WebUSBClientGetDevicesCallbacks* callbacks) override;
void requestDevice(
const blink::WebUSBDeviceRequestOptions& options,
blink::WebUSBClientRequestDeviceCallbacks* callbacks) override;
void addObserver(Observer* observer) override;
void removeObserver(Observer* observer) override;
device::usb::DeviceManager* GetDeviceManager();
void OnDeviceChangeNotification(
device::usb::DeviceChangeNotificationPtr notification);
ServiceRegistry* const service_registry_;
device::usb::DeviceManagerPtr device_manager_;
device::usb::ChooserServicePtr chooser_service_;
std::set<Observer*> observers_;
DISALLOW_COPY_AND_ASSIGN(WebUSBClientImpl);
};
} // namespace content
#endif // CONTENT_RENDERER_USB_WEB_USB_CLIENT_IMPL_H_

@ -1,421 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/usb/web_usb_device_impl.h"
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/utf_string_conversions.h"
#include "content/child/mojo/type_converters.h"
#include "content/child/scoped_web_callbacks.h"
#include "content/renderer/usb/type_converters.h"
#include "services/shell/public/cpp/connect.h"
#include "services/shell/public/interfaces/connector.mojom.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBTransferInfo.h"
namespace content {
namespace {
const char kClaimInterfaceFailed[] = "Unable to claim interface.";
const char kClearHaltFailed[] = "Unable to clear endpoint.";
const char kDeviceAlreadyOpen[] = "Device has already been opened.";
const char kDeviceNoAccess[] = "Access denied.";
const char kDeviceUnavailable[] = "Device unavailable.";
const char kDeviceResetFailed[] = "Unable to reset the device.";
const char kReleaseInterfaceFailed[] = "Unable to release interface.";
const char kSetConfigurationFailed[] = "Unable to set device configuration.";
const char kSetInterfaceFailed[] = "Unable to set device interface.";
const char kTransferFailed[] = "Transfer failed.";
// Generic default rejection handler for any WebUSB callbacks type. Assumes
// |CallbacksType| is a blink::WebCallbacks<T, const blink::WebUSBError&>
// for any type |T|.
template <typename CallbacksType>
void RejectWithError(const blink::WebUSBError& error,
std::unique_ptr<CallbacksType> callbacks) {
callbacks->onError(error);
}
template <typename CallbacksType>
void RejectWithTransferError(std::unique_ptr<CallbacksType> callbacks) {
RejectWithError(blink::WebUSBError(blink::WebUSBError::Error::Network,
base::ASCIIToUTF16(kTransferFailed)),
std::move(callbacks));
}
// Create a new ScopedWebCallbacks for WebUSB device callbacks, defaulting to
// a "device unavailable" rejection.
template <typename CallbacksType>
ScopedWebCallbacks<CallbacksType> MakeScopedUSBCallbacks(
CallbacksType* callbacks) {
return make_scoped_web_callbacks(
callbacks,
base::Bind(&RejectWithError<CallbacksType>,
blink::WebUSBError(blink::WebUSBError::Error::NotFound,
base::ASCIIToUTF16(kDeviceUnavailable))));
}
void OnOpenDevice(
ScopedWebCallbacks<blink::WebUSBDeviceOpenCallbacks> callbacks,
device::usb::OpenDeviceError error) {
auto scoped_callbacks = callbacks.PassCallbacks();
switch(error) {
case device::usb::OpenDeviceError::OK:
scoped_callbacks->onSuccess();
break;
case device::usb::OpenDeviceError::ACCESS_DENIED:
scoped_callbacks->onError(blink::WebUSBError(
blink::WebUSBError::Error::Security,
base::ASCIIToUTF16(kDeviceNoAccess)));
break;
case device::usb::OpenDeviceError::ALREADY_OPEN:
scoped_callbacks->onError(blink::WebUSBError(
blink::WebUSBError::Error::InvalidState,
base::ASCIIToUTF16(kDeviceAlreadyOpen)));
break;
default:
NOTREACHED();
}
}
void OnDeviceClosed(
ScopedWebCallbacks<blink::WebUSBDeviceCloseCallbacks> callbacks) {
callbacks.PassCallbacks()->onSuccess();
}
void HandlePassFailDeviceOperation(
ScopedWebCallbacks<blink::WebCallbacks<void, const blink::WebUSBError&>>
callbacks,
const std::string& failure_message,
bool success) {
auto scoped_callbacks = callbacks.PassCallbacks();
if (success) {
scoped_callbacks->onSuccess();
} else {
RejectWithError(blink::WebUSBError(blink::WebUSBError::Error::Network,
base::ASCIIToUTF16(failure_message)),
std::move(scoped_callbacks));
}
}
void OnTransferIn(
ScopedWebCallbacks<blink::WebUSBDeviceTransferCallbacks> callbacks,
device::usb::TransferStatus status,
mojo::Array<uint8_t> data) {
auto scoped_callbacks = callbacks.PassCallbacks();
blink::WebUSBTransferInfo::Status web_status;
switch (status) {
case device::usb::TransferStatus::COMPLETED:
web_status = blink::WebUSBTransferInfo::Status::Ok;
break;
case device::usb::TransferStatus::STALLED:
web_status = blink::WebUSBTransferInfo::Status::Stall;
break;
case device::usb::TransferStatus::BABBLE:
web_status = blink::WebUSBTransferInfo::Status::Babble;
break;
default:
RejectWithTransferError(std::move(scoped_callbacks));
return;
}
std::unique_ptr<blink::WebUSBTransferInfo> info(
new blink::WebUSBTransferInfo());
info->status.assign(
std::vector<blink::WebUSBTransferInfo::Status>(1, web_status));
info->data.assign(data);
scoped_callbacks->onSuccess(std::move(info));
}
void OnTransferOut(
ScopedWebCallbacks<blink::WebUSBDeviceTransferCallbacks> callbacks,
size_t bytes_written,
device::usb::TransferStatus status) {
auto scoped_callbacks = callbacks.PassCallbacks();
blink::WebUSBTransferInfo::Status web_status;
switch (status) {
case device::usb::TransferStatus::COMPLETED:
web_status = blink::WebUSBTransferInfo::Status::Ok;
break;
case device::usb::TransferStatus::STALLED:
web_status = blink::WebUSBTransferInfo::Status::Stall;
break;
default:
RejectWithTransferError(std::move(scoped_callbacks));
return;
}
// TODO(rockot): Device::ControlTransferOut should expose the number of bytes
// actually transferred so we can send it from here.
std::unique_ptr<blink::WebUSBTransferInfo> info(
new blink::WebUSBTransferInfo());
info->status.assign(
std::vector<blink::WebUSBTransferInfo::Status>(1, web_status));
info->bytesTransferred.assign(std::vector<uint32_t>(1, bytes_written));
scoped_callbacks->onSuccess(std::move(info));
}
void OnIsochronousTransferIn(
ScopedWebCallbacks<blink::WebUSBDeviceTransferCallbacks> callbacks,
mojo::Array<uint8_t> data,
mojo::Array<device::usb::IsochronousPacketPtr> packets) {
auto scoped_callbacks = callbacks.PassCallbacks();
std::unique_ptr<blink::WebUSBTransferInfo> info(
new blink::WebUSBTransferInfo());
info->data.assign(data);
info->status =
blink::WebVector<blink::WebUSBTransferInfo::Status>(packets.size());
info->packetLength = blink::WebVector<uint32_t>(packets.size());
info->bytesTransferred = blink::WebVector<uint32_t>(packets.size());
for (size_t i = 0; i < packets.size(); ++i) {
switch (packets[i]->status) {
case device::usb::TransferStatus::COMPLETED:
info->status[i] = blink::WebUSBTransferInfo::Status::Ok;
break;
case device::usb::TransferStatus::STALLED:
info->status[i] = blink::WebUSBTransferInfo::Status::Stall;
break;
case device::usb::TransferStatus::BABBLE:
info->status[i] = blink::WebUSBTransferInfo::Status::Babble;
break;
default:
RejectWithTransferError(std::move(scoped_callbacks));
return;
}
info->packetLength[i] = packets[i]->length;
info->bytesTransferred[i] = packets[i]->transferred_length;
}
scoped_callbacks->onSuccess(std::move(info));
}
void OnIsochronousTransferOut(
ScopedWebCallbacks<blink::WebUSBDeviceTransferCallbacks> callbacks,
mojo::Array<device::usb::IsochronousPacketPtr> packets) {
auto scoped_callbacks = callbacks.PassCallbacks();
std::unique_ptr<blink::WebUSBTransferInfo> info(
new blink::WebUSBTransferInfo());
info->status =
blink::WebVector<blink::WebUSBTransferInfo::Status>(packets.size());
info->bytesTransferred = blink::WebVector<uint32_t>(packets.size());
for (size_t i = 0; i < packets.size(); ++i) {
switch (packets[i]->status) {
case device::usb::TransferStatus::COMPLETED:
info->status[i] = blink::WebUSBTransferInfo::Status::Ok;
break;
case device::usb::TransferStatus::STALLED:
info->status[i] = blink::WebUSBTransferInfo::Status::Stall;
break;
default:
RejectWithTransferError(std::move(scoped_callbacks));
return;
}
info->bytesTransferred[i] = packets[i]->transferred_length;
}
scoped_callbacks->onSuccess(std::move(info));
}
} // namespace
WebUSBDeviceImpl::WebUSBDeviceImpl(device::usb::DevicePtr device,
const blink::WebUSBDeviceInfo& device_info)
: device_(std::move(device)),
device_info_(device_info),
weak_factory_(this) {
if (device_)
device_.set_connection_error_handler([this]() { device_.reset(); });
}
WebUSBDeviceImpl::~WebUSBDeviceImpl() {}
const blink::WebUSBDeviceInfo& WebUSBDeviceImpl::info() const {
return device_info_;
}
void WebUSBDeviceImpl::open(blink::WebUSBDeviceOpenCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->Open(base::Bind(&OnOpenDevice, base::Passed(&scoped_callbacks)));
}
void WebUSBDeviceImpl::close(blink::WebUSBDeviceCloseCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->Close(
base::Bind(&OnDeviceClosed, base::Passed(&scoped_callbacks)));
}
void WebUSBDeviceImpl::setConfiguration(
uint8_t configuration_value,
blink::WebUSBDeviceSetConfigurationCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->SetConfiguration(
configuration_value,
base::Bind(&HandlePassFailDeviceOperation,
base::Passed(&scoped_callbacks), kSetConfigurationFailed));
}
void WebUSBDeviceImpl::claimInterface(
uint8_t interface_number,
blink::WebUSBDeviceClaimInterfaceCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->ClaimInterface(
interface_number,
base::Bind(&HandlePassFailDeviceOperation,
base::Passed(&scoped_callbacks), kClaimInterfaceFailed));
}
void WebUSBDeviceImpl::releaseInterface(
uint8_t interface_number,
blink::WebUSBDeviceReleaseInterfaceCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->ReleaseInterface(
interface_number,
base::Bind(&HandlePassFailDeviceOperation,
base::Passed(&scoped_callbacks), kReleaseInterfaceFailed));
}
void WebUSBDeviceImpl::setInterface(
uint8_t interface_number,
uint8_t alternate_setting,
blink::WebUSBDeviceSetInterfaceAlternateSettingCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->SetInterfaceAlternateSetting(
interface_number, alternate_setting,
base::Bind(&HandlePassFailDeviceOperation,
base::Passed(&scoped_callbacks), kSetInterfaceFailed));
}
void WebUSBDeviceImpl::clearHalt(
uint8_t endpoint_number,
blink::WebUSBDeviceClearHaltCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->ClearHalt(
endpoint_number,
base::Bind(&HandlePassFailDeviceOperation,
base::Passed(&scoped_callbacks), kClearHaltFailed));
}
void WebUSBDeviceImpl::controlTransfer(
const blink::WebUSBDevice::ControlTransferParameters& parameters,
uint8_t* data,
size_t data_size,
unsigned int timeout,
blink::WebUSBDeviceTransferCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (!device_)
return;
device::usb::ControlTransferParamsPtr params =
device::usb::ControlTransferParams::From(parameters);
switch (parameters.direction) {
case WebUSBDevice::TransferDirection::In:
device_->ControlTransferIn(
std::move(params), data_size, timeout,
base::Bind(&OnTransferIn, base::Passed(&scoped_callbacks)));
break;
case WebUSBDevice::TransferDirection::Out: {
std::vector<uint8_t> bytes;
if (data)
bytes.assign(data, data + data_size);
mojo::Array<uint8_t> mojo_bytes;
mojo_bytes.Swap(&bytes);
device_->ControlTransferOut(
std::move(params), std::move(mojo_bytes), timeout,
base::Bind(&OnTransferOut, base::Passed(&scoped_callbacks),
data_size));
break;
}
default:
NOTREACHED();
}
}
void WebUSBDeviceImpl::transfer(
blink::WebUSBDevice::TransferDirection direction,
uint8_t endpoint_number,
uint8_t* data,
size_t data_size,
unsigned int timeout,
blink::WebUSBDeviceTransferCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (!device_)
return;
switch (direction) {
case WebUSBDevice::TransferDirection::In:
device_->GenericTransferIn(
endpoint_number, data_size, timeout,
base::Bind(&OnTransferIn, base::Passed(&scoped_callbacks)));
break;
case WebUSBDevice::TransferDirection::Out: {
std::vector<uint8_t> bytes;
if (data)
bytes.assign(data, data + data_size);
mojo::Array<uint8_t> mojo_bytes;
mojo_bytes.Swap(&bytes);
device_->GenericTransferOut(
endpoint_number, std::move(mojo_bytes), timeout,
base::Bind(&OnTransferOut, base::Passed(&scoped_callbacks),
data_size));
break;
}
default:
NOTREACHED();
}
}
void WebUSBDeviceImpl::isochronousTransfer(
blink::WebUSBDevice::TransferDirection direction,
uint8_t endpoint_number,
uint8_t* data,
size_t data_size,
blink::WebVector<uint32_t> packet_lengths,
unsigned int timeout,
blink::WebUSBDeviceTransferCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (!device_)
return;
switch (direction) {
case WebUSBDevice::TransferDirection::In:
device_->IsochronousTransferIn(
endpoint_number, mojo::Array<uint32_t>::From(packet_lengths), timeout,
base::Bind(&OnIsochronousTransferIn,
base::Passed(&scoped_callbacks)));
break;
case WebUSBDevice::TransferDirection::Out: {
std::vector<uint8_t> bytes;
if (data)
bytes.assign(data, data + data_size);
mojo::Array<uint8_t> mojo_bytes;
mojo_bytes.Swap(&bytes);
device_->IsochronousTransferOut(
endpoint_number, std::move(mojo_bytes),
mojo::Array<uint32_t>::From(packet_lengths), timeout,
base::Bind(&OnIsochronousTransferOut,
base::Passed(&scoped_callbacks)));
break;
}
default:
NOTREACHED();
}
}
void WebUSBDeviceImpl::reset(blink::WebUSBDeviceResetCallbacks* callbacks) {
auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks);
if (device_)
device_->Reset(base::Bind(&HandlePassFailDeviceOperation,
base::Passed(&scoped_callbacks),
kDeviceResetFailed));
}
} // namespace content

@ -1,86 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_RENDERER_USB_WEB_USB_DEVICE_IMPL_H_
#define CONTENT_RENDERER_USB_WEB_USB_DEVICE_IMPL_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "device/usb/public/interfaces/device.mojom.h"
#include "device/usb/public/interfaces/device_manager.mojom.h"
#include "services/shell/public/interfaces/interface_provider.mojom.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDevice.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h"
#include "third_party/WebKit/public/platform/modules/webusb/WebUSBError.h"
namespace mojo {
class Shell;
}
namespace content {
class WebUSBDeviceImpl : public blink::WebUSBDevice {
public:
WebUSBDeviceImpl(device::usb::DevicePtr device,
const blink::WebUSBDeviceInfo& device_info);
~WebUSBDeviceImpl() override;
private:
// blink::WebUSBDevice implementation:
const blink::WebUSBDeviceInfo& info() const override;
void open(blink::WebUSBDeviceOpenCallbacks* callbacks) override;
void close(blink::WebUSBDeviceCloseCallbacks* callbacks) override;
void setConfiguration(
uint8_t configuration_value,
blink::WebUSBDeviceSetConfigurationCallbacks* callbacks) override;
void claimInterface(
uint8_t interface_number,
blink::WebUSBDeviceClaimInterfaceCallbacks* callbacks) override;
void releaseInterface(
uint8_t interface_number,
blink::WebUSBDeviceReleaseInterfaceCallbacks* callbacks) override;
void setInterface(uint8_t interface_number,
uint8_t alternate_setting,
blink::WebUSBDeviceSetInterfaceAlternateSettingCallbacks*
callbacks) override;
void clearHalt(uint8_t endpoint_number,
blink::WebUSBDeviceClearHaltCallbacks* callbacks) override;
void controlTransfer(
const blink::WebUSBDevice::ControlTransferParameters& parameters,
uint8_t* data,
size_t data_size,
unsigned int timeout,
blink::WebUSBDeviceTransferCallbacks* callbacks) override;
void transfer(blink::WebUSBDevice::TransferDirection direction,
uint8_t endpoint_number,
uint8_t* data,
size_t data_size,
unsigned int timeout,
blink::WebUSBDeviceTransferCallbacks* callbacks) override;
void isochronousTransfer(
blink::WebUSBDevice::TransferDirection direction,
uint8_t endpoint_number,
uint8_t* data,
size_t data_size,
blink::WebVector<uint32_t> packet_lengths,
unsigned int timeout,
blink::WebUSBDeviceTransferCallbacks* callbacks) override;
void reset(blink::WebUSBDeviceResetCallbacks* callbacks) override;
device::usb::DevicePtr device_;
blink::WebUSBDeviceInfo device_info_;
base::WeakPtrFactory<WebUSBDeviceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WebUSBDeviceImpl);
};
} // namespace content
#endif // CONTENT_RENDERER_USB_WEB_USB_DEVICE_IMPL_H_

@ -4,10 +4,12 @@
import("//mojo/public/tools/bindings/mojom.gni")
mojom_files = [
"chooser_service.mojom",
"device.mojom",
"device_manager.mojom",
]
mojom("interfaces") {
sources = [
"chooser_service.mojom",
"device.mojom",
"device_manager.mojom",
]
sources = mojom_files
}

@ -5,6 +5,11 @@
{
'variables': {
'chromium_code': 1,
'mojom_files': [
'public/interfaces/chooser_service.mojom',
'public/interfaces/device.mojom',
'public/interfaces/device_manager.mojom',
],
},
'targets': [
{
@ -141,11 +146,19 @@
{
'target_name': 'device_usb_mojo_bindings',
'type': 'static_library',
'sources': [
'public/interfaces/chooser_service.mojom',
'public/interfaces/device.mojom',
'public/interfaces/device_manager.mojom',
'sources': [ '<@(mojom_files)' ],
'includes': [
'../../mojo/mojom_bindings_generator.gypi',
],
},
{
'target_name': 'device_usb_mojo_bindings_for_blink',
'type': 'static_library',
'sources': [ '<@(mojom_files)' ],
'variables': {
'mojom_variant': 'wtf',
'for_blink': 'true',
},
'includes': [
'../../mojo/mojom_bindings_generator.gypi',
],

@ -244,7 +244,6 @@ usb_test(usb => {
});
}, 'a non-existent interface cannot be claimed or released');
usb_test(usb => {
usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
return navigator.usb.getDevices().then(devices => {

@ -47,6 +47,7 @@ component("modules") {
deps = [
":make_modules_generated",
"//device/battery:mojo_bindings",
"//device/usb/public/interfaces:interfaces_wtf",
"//mojo/public/c/system:for_component",
"//third_party/WebKit/Source/core",
"//third_party/WebKit/public:mojo_bindings_wtf",

@ -40,6 +40,7 @@
'target_name': 'modules',
'dependencies': [
'<(DEPTH)/device/battery/battery.gyp:device_battery_mojo_bindings',
'<(DEPTH)/device/usb/usb.gyp:device_usb_mojo_bindings_for_blink',
'<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
'<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',

@ -1907,14 +1907,10 @@
'webusb/USBConfiguration.h',
'webusb/USBConnectionEvent.cpp',
'webusb/USBConnectionEvent.h',
'webusb/USBController.cpp',
'webusb/USBController.h',
'webusb/USBDevice.cpp',
'webusb/USBDevice.h',
'webusb/USBEndpoint.cpp',
'webusb/USBEndpoint.h',
'webusb/USBError.cpp',
'webusb/USBError.h',
'webusb/USBInTransferResult.h',
'webusb/USBInterface.cpp',
'webusb/USBInterface.h',

@ -0,0 +1,4 @@
include_rules = [
"+device/usb/public/interfaces",
"+mojo/public/cpp/bindings",
]

@ -4,133 +4,138 @@
#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"
#include "core/dom/Document.h"
#include "core/dom/ExceptionCode.h"
#include "device/usb/public/interfaces/device.mojom-wtf.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/MojoHelper.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"
#include "wtf/Functional.h"
namespace usb = device::usb::wtf;
namespace blink {
namespace {
void convertDeviceFilter(const USBDeviceFilter& filter, WebUSBDeviceFilter* webFilter)
const char kNoServiceError[] = "USB service unavailable.";
usb::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 = usb::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)
bool isActive(ScriptPromiseResolver* resolver)
{
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]);
}
ExecutionContext* context = resolver->getExecutionContext();
return context && !context->activeDOMObjectsAreStopped();
}
// Allows using a CallbackPromiseAdapter with a WebVector to resolve the
// getDevices() promise with a HeapVector owning USBDevices.
class DeviceArray {
STATIC_ONLY(DeviceArray);
public:
using WebType = OwnPtr<WebVector<WebUSBDevice*>>;
static HeapVector<Member<USBDevice>> take(ScriptPromiseResolver* resolver, PassOwnPtr<WebVector<WebUSBDevice*>> webDevices)
{
HeapVector<Member<USBDevice>> devices;
for (const auto webDevice : *webDevices)
devices.append(USBDevice::create(adoptPtr(webDevice), resolver->getExecutionContext()));
return devices;
}
};
} // namespace
USB::USB(LocalFrame& frame)
: ContextLifecycleObserver(frame.document())
, m_client(USBController::from(frame).client())
{
ThreadState::current()->registerPreFinalizer(this);
if (m_client)
m_client->addObserver(this);
frame.serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_deviceManager));
m_deviceManager.set_connection_error_handler([this]() {
m_deviceManager.reset();
for (ScriptPromiseResolver* resolver : m_deviceManagerRequests) {
if (isActive(resolver))
resolver->reject(DOMException::create(NotFoundError, kNoServiceError));
}
m_deviceManagerRequests.clear();
});
// Set up two sequential calls to GetDeviceChanges to avoid latency.
m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeNotificationPtr>(&USB::onDeviceChanges, this)));
m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeNotificationPtr>(&USB::onDeviceChanges, this)));
}
USB::~USB()
{
}
void USB::dispose()
{
// Promptly clears a raw reference from content/ to an on-heap object
// so that content/ doesn't access it in a lazy sweeping phase.
if (m_client)
m_client->removeObserver(this);
m_client = nullptr;
DCHECK(!m_deviceManager);
DCHECK(m_deviceManagerRequests.isEmpty());
DCHECK(!m_chooserService);
DCHECK(m_chooserServiceRequests.isEmpty());
}
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 {
m_deviceManagerRequests.add(resolver);
m_deviceManager->GetDevices(nullptr, createBaseCallback(bind<mojo::WTFArray<usb::DeviceInfoPtr>>(&USB::onGetDevices, this, resolver)));
}
}
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() ? toDocument(getExecutionContext())->frame() : nullptr;
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();
for (ScriptPromiseResolver* resolver : m_chooserServiceRequests) {
if (isActive(resolver))
resolver->reject(DOMException::create(NotFoundError, kNoServiceError));
}
m_chooserServiceRequests.clear();
});
}
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 {
Vector<usb::DeviceFilterPtr> filters;
if (options.hasFilters()) {
filters.reserveCapacity(options.filters().size());
for (const auto& filter : options.filters())
filters.append(convertDeviceFilter(filter));
}
m_chooserServiceRequests.add(resolver);
m_chooserService->GetPermission(std::move(filters), createBaseCallback(bind<usb::DeviceInfoPtr>(&USB::onGetPermission, this, resolver)));
}
return promise;
}
@ -146,25 +151,59 @@ const AtomicString& USB::interfaceName() const
void USB::contextDestroyed()
{
if (m_client)
m_client->removeObserver(this);
m_client = nullptr;
m_deviceManager.reset();
m_deviceManagerRequests.clear();
m_chooserService.reset();
m_chooserServiceRequests.clear();
}
void USB::onDeviceConnected(std::unique_ptr<WebUSBDevice> device)
void USB::onGetDevices(ScriptPromiseResolver* resolver, mojo::WTFArray<usb::DeviceInfoPtr> deviceInfos)
{
dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice::create(adoptPtr(device.release()), getExecutionContext())));
if (!isActive(resolver))
return;
HeapVector<Member<USBDevice>> devices;
for (auto& deviceInfo : deviceInfos.PassStorage()) {
usb::DevicePtr device;
m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
devices.append(USBDevice::create(std::move(deviceInfo), std::move(device), resolver->getExecutionContext()));
}
resolver->resolve(devices);
m_deviceManagerRequests.remove(resolver);
}
void USB::onDeviceDisconnected(std::unique_ptr<WebUSBDevice> device)
void USB::onGetPermission(ScriptPromiseResolver* resolver, usb::DeviceInfoPtr deviceInfo)
{
dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevice::create(adoptPtr(device.release()), getExecutionContext())));
if (!isActive(resolver))
return;
if (deviceInfo) {
usb::DevicePtr device;
m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
resolver->resolve(USBDevice::create(std::move(deviceInfo), std::move(device), resolver->getExecutionContext()));
} else {
resolver->reject(DOMException::create(NotFoundError, "No device selected."));
}
}
void USB::onDeviceChanges(usb::DeviceChangeNotificationPtr notification)
{
m_deviceManager->GetDeviceChanges(createBaseCallback(bind<usb::DeviceChangeNotificationPtr>(&USB::onDeviceChanges, this)));
for (auto& deviceInfo : notification->devices_added.PassStorage()) {
usb::DevicePtr device;
m_deviceManager->GetDevice(deviceInfo->guid, mojo::GetProxy(&device));
dispatchEvent(USBConnectionEvent::create(EventTypeNames::connect, USBDevice::create(std::move(deviceInfo), std::move(device), getExecutionContext())));
}
for (auto& deviceInfo : notification->devices_removed.PassStorage())
dispatchEvent(USBConnectionEvent::create(EventTypeNames::disconnect, USBDevice::create(std::move(deviceInfo), nullptr, getExecutionContext())));
}
DEFINE_TRACE(USB)
{
EventTargetWithInlineData::trace(visitor);
ContextLifecycleObserver::trace(visitor);
visitor->trace(m_deviceManagerRequests);
visitor->trace(m_chooserServiceRequests);
}
} // namespace blink

@ -9,30 +9,29 @@
#include "bindings/core/v8/ScriptWrappable.h"
#include "core/dom/ContextLifecycleObserver.h"
#include "core/events/EventTarget.h"
#include "device/usb/public/interfaces/chooser_service.mojom-wtf.h"
#include "device/usb/public/interfaces/device_manager.mojom-wtf.h"
#include "platform/heap/Handle.h"
#include "public/platform/modules/webusb/WebUSBClient.h"
namespace blink {
class LocalFrame;
class ScopedScriptPromiseResolver;
class ScriptState;
class USBDeviceRequestOptions;
class WebUSBDevice;
class USB final
: public EventTargetWithInlineData
, public ContextLifecycleObserver
, public WebUSBClient::Observer {
, public ContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(USB);
USING_PRE_FINALIZER(USB, dispose);
public:
static USB* create(LocalFrame& frame)
{
return new USB(frame);
}
~USB() override;
virtual ~USB();
// USB.idl
ScriptPromise getDevices(ScriptState*);
@ -47,17 +46,21 @@ public:
// ContextLifecycleObserver overrides.
void contextDestroyed() override;
// WebUSBClient::Observer overrides.
void onDeviceConnected(std::unique_ptr<WebUSBDevice>) override;
void onDeviceDisconnected(std::unique_ptr<WebUSBDevice>) override;
device::usb::wtf::DeviceManager* deviceManager() const { return m_deviceManager.get(); }
void onGetDevices(ScriptPromiseResolver*, mojo::WTFArray<device::usb::wtf::DeviceInfoPtr>);
void onGetPermission(ScriptPromiseResolver*, device::usb::wtf::DeviceInfoPtr);
void onDeviceChanges(device::usb::wtf::DeviceChangeNotificationPtr);
DECLARE_VIRTUAL_TRACE();
private:
explicit USB(LocalFrame& frame);
void dispose();
WebUSBClient* m_client;
device::usb::wtf::DeviceManagerPtr m_deviceManager;
HeapHashSet<Member<ScriptPromiseResolver>> m_deviceManagerRequests;
device::usb::wtf::ChooserServicePtr m_chooserService;
HeapHashSet<Member<ScriptPromiseResolver>> m_chooserServiceRequests;
};
} // namespace blink

@ -17,8 +17,9 @@ USBAlternateInterface* USBAlternateInterface::create(const USBInterface* interfa
USBAlternateInterface* USBAlternateInterface::create(const USBInterface* interface, size_t alternateSetting, ExceptionState& exceptionState)
{
for (size_t i = 0; i < interface->info().alternates.size(); ++i) {
if (interface->info().alternates[i].alternateSetting == alternateSetting)
const auto& alternates = interface->info().alternates;
for (size_t i = 0; i < alternates.size(); ++i) {
if (alternates[i]->alternate_setting == alternateSetting)
return USBAlternateInterface::create(interface, i);
}
exceptionState.throwRangeError("Invalid alternate setting.");
@ -33,36 +34,11 @@ USBAlternateInterface::USBAlternateInterface(const USBInterface* interface, size
ASSERT(m_alternateIndex < m_interface->info().alternates.size());
}
const WebUSBDeviceInfo::AlternateInterface& USBAlternateInterface::info() const
const device::usb::wtf::AlternateInterfaceInfo& USBAlternateInterface::info() const
{
const WebUSBDeviceInfo::Interface& interfaceInfo = m_interface->info();
const device::usb::wtf::InterfaceInfo& interfaceInfo = m_interface->info();
ASSERT(m_alternateIndex < interfaceInfo.alternates.size());
return interfaceInfo.alternates[m_alternateIndex];
}
uint8_t USBAlternateInterface::alternateSetting() const
{
return info().alternateSetting;
}
uint8_t USBAlternateInterface::interfaceClass() const
{
return info().classCode;
}
uint8_t USBAlternateInterface::interfaceSubclass() const
{
return info().subclassCode;
}
uint8_t USBAlternateInterface::interfaceProtocol() const
{
return info().protocolCode;
}
String USBAlternateInterface::interfaceName() const
{
return info().interfaceName;
return *interfaceInfo.alternates[m_alternateIndex];
}
HeapVector<Member<USBEndpoint>> USBAlternateInterface::endpoints() const

@ -6,8 +6,8 @@
#define USBAlternateInterface_h
#include "bindings/core/v8/ScriptWrappable.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "platform/heap/Heap.h"
#include "public/platform/modules/webusb/WebUSBDeviceInfo.h"
namespace blink {
@ -25,13 +25,13 @@ public:
USBAlternateInterface(const USBInterface*, size_t alternateIndex);
const WebUSBDeviceInfo::AlternateInterface& info() const;
const device::usb::wtf::AlternateInterfaceInfo& info() const;
uint8_t alternateSetting() const;
uint8_t interfaceClass() const;
uint8_t interfaceSubclass() const;
uint8_t interfaceProtocol() const;
String interfaceName() const;
uint8_t alternateSetting() const { return info().alternate_setting; }
uint8_t interfaceClass() const { return info().class_code; }
uint8_t interfaceSubclass() const { return info().subclass_code; }
uint8_t interfaceProtocol() const { return info().protocol_code; }
String interfaceName() const { return info().interface_name; }
HeapVector<Member<USBEndpoint>> endpoints() const;
DECLARE_TRACE();

@ -5,6 +5,7 @@
#include "modules/webusb/USBConfiguration.h"
#include "bindings/core/v8/ExceptionState.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "modules/webusb/USBDevice.h"
#include "modules/webusb/USBInterface.h"
@ -17,23 +18,15 @@ USBConfiguration* USBConfiguration::create(const USBDevice* device, size_t confi
USBConfiguration* USBConfiguration::create(const USBDevice* device, size_t configurationValue, ExceptionState& exceptionState)
{
for (size_t i = 0; i < device->info().configurations.size(); ++i) {
if (device->info().configurations[i].configurationValue == configurationValue)
const auto& configurations = device->info().configurations;
for (size_t i = 0; i < configurations.size(); ++i) {
if (configurations[i]->configuration_value == configurationValue)
return new USBConfiguration(device, i);
}
exceptionState.throwRangeError("Invalid configuration value.");
return nullptr;
}
USBConfiguration* USBConfiguration::createFromValue(const USBDevice* device, uint8_t configurationValue)
{
for (size_t i = 0; i < device->info().configurations.size(); ++i) {
if (device->info().configurations[i].configurationValue == configurationValue)
return new USBConfiguration(device, i);
}
return nullptr;
}
USBConfiguration::USBConfiguration(const USBDevice* device, size_t configurationIndex)
: m_device(device)
, m_configurationIndex(configurationIndex)
@ -52,19 +45,9 @@ size_t USBConfiguration::index() const
return m_configurationIndex;
}
const WebUSBDeviceInfo::Configuration& USBConfiguration::info() const
const device::usb::wtf::ConfigurationInfo& USBConfiguration::info() const
{
return m_device->info().configurations[m_configurationIndex];
}
uint8_t USBConfiguration::configurationValue() const
{
return info().configurationValue;
}
String USBConfiguration::configurationName() const
{
return info().configurationName;
return *m_device->info().configurations[m_configurationIndex];
}
HeapVector<Member<USBInterface>> USBConfiguration::interfaces() const

@ -6,8 +6,8 @@
#define USBConfiguration_h
#include "bindings/core/v8/ScriptWrappable.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "platform/heap/Handle.h"
#include "public/platform/modules/webusb/WebUSBDeviceInfo.h"
namespace blink {
@ -22,16 +22,15 @@ class USBConfiguration
public:
static USBConfiguration* create(const USBDevice*, size_t configurationIndex);
static USBConfiguration* create(const USBDevice*, size_t configurationValue, ExceptionState&);
static USBConfiguration* createFromValue(const USBDevice*, uint8_t configurationValue);
USBConfiguration(const USBDevice*, size_t configurationIndex);
const USBDevice* device() const;
size_t index() const;
const WebUSBDeviceInfo::Configuration& info() const;
const device::usb::wtf::ConfigurationInfo& info() const;
uint8_t configurationValue() const;
String configurationName() const;
uint8_t configurationValue() const { return info().configuration_value; }
String configurationName() const { return info().configuration_name; }
HeapVector<Member<USBInterface>> interfaces() const;
DECLARE_TRACE();

@ -1,51 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/webusb/USBController.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "public/platform/modules/webusb/WebUSBClient.h"
namespace blink {
USBController::~USBController()
{
}
void USBController::provideTo(LocalFrame& frame, WebUSBClient* client)
{
USBController* controller = new USBController(frame, client);
Supplement<LocalFrame>::provideTo(frame, supplementName(), controller);
}
USBController& USBController::from(LocalFrame& frame)
{
USBController* controller = static_cast<USBController*>(Supplement<LocalFrame>::from(frame, supplementName()));
ASSERT(controller);
return *controller;
}
const char* USBController::supplementName()
{
return "USBController";
}
USBController::USBController(LocalFrame& frame, WebUSBClient* client)
: LocalFrameLifecycleObserver(&frame)
, m_client(client)
{
}
void USBController::willDetachFrameHost()
{
m_client = nullptr;
}
DEFINE_TRACE(USBController)
{
Supplement<LocalFrame>::trace(visitor);
LocalFrameLifecycleObserver::trace(visitor);
}
} // namespace blink

@ -1,45 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef USBController_h
#define USBController_h
#include "core/frame/LocalFrame.h"
#include "core/frame/LocalFrameLifecycleObserver.h"
#include "modules/ModulesExport.h"
#include "platform/heap/Handle.h"
namespace blink {
class WebUSBClient;
class MODULES_EXPORT USBController final
: public GarbageCollectedFinalized<USBController>
, public Supplement<LocalFrame>
, public LocalFrameLifecycleObserver {
WTF_MAKE_NONCOPYABLE(USBController);
USING_GARBAGE_COLLECTED_MIXIN(USBController);
public:
virtual ~USBController();
WebUSBClient* client() { return m_client; }
static void provideTo(LocalFrame&, WebUSBClient*);
static USBController& from(LocalFrame&);
static const char* supplementName();
DECLARE_VIRTUAL_TRACE();
private:
USBController(LocalFrame&, WebUSBClient*);
// Inherited from LocalFrameLifecycleObserver.
void willDetachFrameHost() override;
WebUSBClient* m_client;
};
} // namespace blink
#endif // USBController_h

@ -4,7 +4,6 @@
#include "modules/webusb/USBDevice.h"
#include "bindings/core/v8/CallbackPromiseAdapter.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ToV8.h"
@ -14,31 +13,58 @@
#include "core/dom/ExceptionCode.h"
#include "modules/webusb/USBConfiguration.h"
#include "modules/webusb/USBControlTransferParameters.h"
#include "modules/webusb/USBError.h"
#include "modules/webusb/USBInTransferResult.h"
#include "modules/webusb/USBIsochronousInTransferResult.h"
#include "modules/webusb/USBIsochronousOutTransferResult.h"
#include "modules/webusb/USBOutTransferResult.h"
#include "public/platform/modules/webusb/WebUSBTransferInfo.h"
#include "platform/MojoHelper.h"
#include "wtf/Assertions.h"
namespace usb = device::usb::wtf;
namespace blink {
namespace {
const char kDeviceStateChangeInProgress[] = "An operation that changes the device state is in progress.";
const char kDeviceUnavailable[] = "Device unavailable.";
const char kInterfaceNotFound[] = "The interface number provided is not supported by the device in its current configuration.";
const char kInterfaceStateChangeInProgress[] = "An operation that changes interface state is in progress.";
const char kOpenRequired[] = "The device must be opened first.";
String convertTransferStatus(const WebUSBTransferInfo::Status& status)
DOMException* convertFatalTransferStatus(const usb::TransferStatus& status)
{
switch (status) {
case WebUSBTransferInfo::Status::Ok:
case usb::TransferStatus::TRANSFER_ERROR:
return DOMException::create(NetworkError, "A transfer error has occured.");
case usb::TransferStatus::PERMISSION_DENIED:
return DOMException::create(SecurityError, "The transfer was not allowed.");
case usb::TransferStatus::TIMEOUT:
return DOMException::create(TimeoutError, "The transfer timed out.");
case usb::TransferStatus::CANCELLED:
return DOMException::create(AbortError, "The transfer was cancelled.");
case usb::TransferStatus::DISCONNECT:
return DOMException::create(NotFoundError, kDeviceUnavailable);
case usb::TransferStatus::COMPLETED:
case usb::TransferStatus::STALLED:
case usb::TransferStatus::BABBLE:
case usb::TransferStatus::SHORT_PACKET:
return nullptr;
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
String convertTransferStatus(const usb::TransferStatus& status)
{
switch (status) {
case usb::TransferStatus::COMPLETED:
case usb::TransferStatus::SHORT_PACKET:
return "ok";
case WebUSBTransferInfo::Status::Stall:
case usb::TransferStatus::STALLED:
return "stall";
case WebUSBTransferInfo::Status::Babble:
case usb::TransferStatus::BABBLE:
return "babble";
default:
ASSERT_NOT_REACHED();
@ -46,291 +72,52 @@ String convertTransferStatus(const WebUSBTransferInfo::Status& status)
}
}
class OpenClosePromiseAdapter : public WebCallbacks<void, const WebUSBError&> {
public:
OpenClosePromiseAdapter(USBDevice* device, ScriptPromiseResolver* resolver, bool desiredState)
: m_device(device)
, m_resolver(resolver)
, m_desiredState(desiredState)
{
}
mojo::WTFArray<uint8_t> convertBufferSource(const ArrayBufferOrArrayBufferView& buffer)
{
ASSERT(!buffer.isNull());
Vector<uint8_t> vector;
if (buffer.isArrayBuffer())
vector.append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->data()), buffer.getAsArrayBuffer()->byteLength());
else
vector.append(static_cast<uint8_t*>(buffer.getAsArrayBufferView()->baseAddress()), buffer.getAsArrayBufferView()->byteLength());
return mojo::WTFArray<uint8_t>(std::move(vector));
}
void onSuccess() override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onDeviceOpenedOrClosed(m_desiredState);
m_resolver->resolve();
}
void onError(const WebUSBError& e) override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onDeviceOpenedOrClosed(!m_desiredState);
m_resolver->reject(USBError::take(m_resolver, e));
}
private:
Persistent<USBDevice> m_device;
Persistent<ScriptPromiseResolver> m_resolver;
bool m_desiredState; // true: open, false: closed
};
class SelectConfigurationPromiseAdapter : public WebCallbacks<void, const WebUSBError&> {
public:
SelectConfigurationPromiseAdapter(USBDevice* device, ScriptPromiseResolver* resolver, size_t configurationIndex)
: m_device(device)
, m_resolver(resolver)
, m_configurationIndex(configurationIndex)
{
}
void onSuccess() override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onConfigurationSelected(true /* success */, m_configurationIndex);
m_resolver->resolve();
}
void onError(const WebUSBError& e) override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onConfigurationSelected(false /* failure */, m_configurationIndex);
m_resolver->reject(USBError::take(m_resolver, e));
}
private:
Persistent<USBDevice> m_device;
Persistent<ScriptPromiseResolver> m_resolver;
size_t m_configurationIndex;
};
class ClaimInterfacePromiseAdapter : public WebCallbacks<void, const WebUSBError&> {
public:
ClaimInterfacePromiseAdapter(USBDevice* device, ScriptPromiseResolver* resolver, size_t interfaceIndex, bool desiredState)
: m_device(device)
, m_resolver(resolver)
, m_interfaceIndex(interfaceIndex)
, m_desiredState(desiredState)
{
}
void onSuccess() override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onInterfaceClaimedOrUnclaimed(m_desiredState, m_interfaceIndex);
m_resolver->resolve();
}
void onError(const WebUSBError& e) override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onInterfaceClaimedOrUnclaimed(!m_desiredState, m_interfaceIndex);
m_resolver->reject(USBError::take(m_resolver, e));
}
private:
Persistent<USBDevice> m_device;
Persistent<ScriptPromiseResolver> m_resolver;
size_t m_interfaceIndex;
bool m_desiredState; // true: claimed, false: unclaimed
};
class SelectAlternateInterfacePromiseAdapter : public WebCallbacks<void, const WebUSBError&> {
public:
SelectAlternateInterfacePromiseAdapter(USBDevice* device, ScriptPromiseResolver* resolver, size_t interfaceIndex, size_t alternateIndex)
: m_device(device)
, m_resolver(resolver)
, m_interfaceIndex(interfaceIndex)
, m_alternateIndex(alternateIndex)
{
}
void onSuccess() override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onAlternateInterfaceSelected(true /* success */, m_interfaceIndex, m_alternateIndex);
m_resolver->resolve();
}
void onError(const WebUSBError& e) override
{
if (!m_resolver->getExecutionContext() || m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
return;
m_device->onAlternateInterfaceSelected(false /* failure */, m_interfaceIndex, m_alternateIndex);
m_resolver->reject(USBError::take(m_resolver, e));
}
private:
Persistent<USBDevice> m_device;
Persistent<ScriptPromiseResolver> m_resolver;
size_t m_interfaceIndex;
size_t m_alternateIndex;
};
class InputTransferResult {
WTF_MAKE_NONCOPYABLE(InputTransferResult);
public:
using WebType = OwnPtr<WebUSBTransferInfo>;
static USBInTransferResult* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBTransferInfo> webTransferInfo)
{
ASSERT(webTransferInfo->status.size() == 1);
return USBInTransferResult::create(convertTransferStatus(webTransferInfo->status[0]), webTransferInfo->data);
}
private:
InputTransferResult() = delete;
};
class OutputTransferResult {
WTF_MAKE_NONCOPYABLE(OutputTransferResult);
public:
using WebType = OwnPtr<WebUSBTransferInfo>;
static USBOutTransferResult* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBTransferInfo> webTransferInfo)
{
ASSERT(webTransferInfo->status.size() == 1);
ASSERT(webTransferInfo->bytesTransferred.size() == 1);
return USBOutTransferResult::create(convertTransferStatus(webTransferInfo->status[0]), webTransferInfo->bytesTransferred[0]);
}
private:
OutputTransferResult() = delete;
};
class IsochronousInputTransferResult {
WTF_MAKE_NONCOPYABLE(IsochronousInputTransferResult);
public:
using WebType = OwnPtr<WebUSBTransferInfo>;
static USBIsochronousInTransferResult* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBTransferInfo> webTransferInfo)
{
ASSERT(webTransferInfo->status.size() == webTransferInfo->packetLength.size() && webTransferInfo->packetLength.size() == webTransferInfo->bytesTransferred.size());
DOMArrayBuffer* buffer = DOMArrayBuffer::create(webTransferInfo->data.data(), webTransferInfo->data.size());
HeapVector<Member<USBIsochronousInTransferPacket>> packets(webTransferInfo->status.size());
size_t byteOffset = 0;
for (size_t i = 0; i < webTransferInfo->status.size(); ++i) {
packets[i] = USBIsochronousInTransferPacket::create(convertTransferStatus(webTransferInfo->status[i]), DOMDataView::create(buffer, byteOffset, webTransferInfo->bytesTransferred[i]));
byteOffset += webTransferInfo->packetLength[i];
}
return USBIsochronousInTransferResult::create(buffer, packets);
}
};
class IsochronousOutputTransferResult {
WTF_MAKE_NONCOPYABLE(IsochronousOutputTransferResult);
public:
using WebType = OwnPtr<WebUSBTransferInfo>;
static USBIsochronousOutTransferResult* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBTransferInfo> webTransferInfo)
{
ASSERT(webTransferInfo->status.size() == webTransferInfo->bytesTransferred.size());
HeapVector<Member<USBIsochronousOutTransferPacket>> packets(webTransferInfo->status.size());
for (size_t i = 0; i < webTransferInfo->status.size(); ++i)
packets[i] = USBIsochronousOutTransferPacket::create(convertTransferStatus(webTransferInfo->status[i]), webTransferInfo->bytesTransferred[i]);
return USBIsochronousOutTransferResult::create(packets);
}
};
class BufferSource {
WTF_MAKE_NONCOPYABLE(BufferSource);
public:
BufferSource(const ArrayBufferOrArrayBufferView& buffer) : m_buffer(buffer)
{
ASSERT(!m_buffer.isNull());
}
uint8_t* data() const
{
if (m_buffer.isArrayBuffer())
return static_cast<uint8_t*>(m_buffer.getAsArrayBuffer()->data());
return static_cast<uint8_t*>(m_buffer.getAsArrayBufferView()->baseAddress());
}
unsigned size() const
{
if (m_buffer.isArrayBuffer())
return m_buffer.getAsArrayBuffer()->byteLength();
return m_buffer.getAsArrayBufferView()->byteLength();
}
private:
const ArrayBufferOrArrayBufferView& m_buffer;
};
bool isActive(ScriptPromiseResolver* resolver)
{
ExecutionContext* context = resolver->getExecutionContext();
return context && !context->activeDOMObjectsAreStopped();
}
} // namespace
// static
USBDevice* USBDevice::take(ScriptPromiseResolver* resolver, PassOwnPtr<WebUSBDevice> device)
{
return USBDevice::create(device, resolver->getExecutionContext());
}
USBDevice::USBDevice(PassOwnPtr<WebUSBDevice> device, ExecutionContext* context)
USBDevice::USBDevice(usb::DeviceInfoPtr deviceInfo, usb::DevicePtr device, ExecutionContext* context)
: ContextLifecycleObserver(context)
, m_device(device)
, m_deviceInfo(std::move(deviceInfo))
, m_device(std::move(device))
, m_opened(false)
, m_deviceStateChangeInProgress(false)
, m_configurationIndex(-1)
, m_inEndpoints(15)
, m_outEndpoints(15)
{
int configurationIndex = findConfigurationIndex(info().activeConfiguration);
if (m_device) {
m_device.set_connection_error_handler([this]() {
m_device.reset();
m_opened = false;
for (ScriptPromiseResolver* resolver : m_deviceRequests) {
if (isActive(resolver))
resolver->reject(DOMException::create(NotFoundError, kDeviceUnavailable));
}
});
}
int configurationIndex = findConfigurationIndex(info().active_configuration);
if (configurationIndex != -1)
onConfigurationSelected(true /* success */, configurationIndex);
}
void USBDevice::onDeviceOpenedOrClosed(bool opened)
USBDevice::~USBDevice()
{
m_opened = opened;
m_deviceStateChangeInProgress = false;
}
void USBDevice::onConfigurationSelected(bool success, size_t configurationIndex)
{
if (success) {
m_configurationIndex = configurationIndex;
size_t numInterfaces = info().configurations[m_configurationIndex].interfaces.size();
m_claimedInterfaces.clearAll();
m_claimedInterfaces.resize(numInterfaces);
m_interfaceStateChangeInProgress.clearAll();
m_interfaceStateChangeInProgress.resize(numInterfaces);
m_selectedAlternates.resize(numInterfaces);
m_selectedAlternates.fill(0);
m_inEndpoints.clearAll();
m_outEndpoints.clearAll();
}
m_deviceStateChangeInProgress = false;
}
void USBDevice::onInterfaceClaimedOrUnclaimed(bool claimed, size_t interfaceIndex)
{
if (claimed) {
m_claimedInterfaces.set(interfaceIndex);
} else {
m_claimedInterfaces.clear(interfaceIndex);
m_selectedAlternates[interfaceIndex] = 0;
}
setEndpointsForInterface(interfaceIndex, claimed);
m_interfaceStateChangeInProgress.clear(interfaceIndex);
}
void USBDevice::onAlternateInterfaceSelected(bool success, size_t interfaceIndex, size_t alternateIndex)
{
if (success)
m_selectedAlternates[interfaceIndex] = alternateIndex;
setEndpointsForInterface(interfaceIndex, success);
m_interfaceStateChangeInProgress.clear(interfaceIndex);
DCHECK(!m_device);
DCHECK(m_deviceRequests.isEmpty());
}
bool USBDevice::isInterfaceClaimed(size_t configurationIndex, size_t interfaceIndex) const
@ -352,10 +139,10 @@ USBConfiguration* USBDevice::configuration() const
HeapVector<Member<USBConfiguration>> USBDevice::configurations() const
{
HeapVector<Member<USBConfiguration>> configurations;
size_t numConfigurations = info().configurations.size();
HeapVector<Member<USBConfiguration>> configurations(numConfigurations);
for (size_t i = 0; i < numConfigurations; ++i)
configurations.append(USBConfiguration::create(this, i));
configurations[i] = USBConfiguration::create(this, i);
return configurations;
}
@ -368,7 +155,8 @@ ScriptPromise USBDevice::open(ScriptState* scriptState)
resolver->resolve();
} else {
m_deviceStateChangeInProgress = true;
m_device->open(new OpenClosePromiseAdapter(this, resolver, true /* open */));
m_deviceRequests.add(resolver);
m_device->Open(createBaseCallback(bind<usb::OpenDeviceError>(&USBDevice::asyncOpen, this, resolver)));
}
}
return promise;
@ -383,7 +171,8 @@ ScriptPromise USBDevice::close(ScriptState* scriptState)
resolver->resolve();
} else {
m_deviceStateChangeInProgress = true;
m_device->close(new OpenClosePromiseAdapter(this, resolver, false /* closed */));
m_deviceRequests.add(resolver);
m_device->Close(createBaseCallback(bind(&USBDevice::asyncClose, this, resolver)));
}
}
return promise;
@ -404,7 +193,8 @@ ScriptPromise USBDevice::selectConfiguration(ScriptState* scriptState, uint8_t c
resolver->resolve();
} else {
m_deviceStateChangeInProgress = true;
m_device->setConfiguration(configurationValue, new SelectConfigurationPromiseAdapter(this, resolver, configurationIndex));
m_deviceRequests.add(resolver);
m_device->SetConfiguration(configurationValue, createBaseCallback(bind<bool>(&USBDevice::asyncSelectConfiguration, this, configurationIndex, resolver)));
}
}
}
@ -425,7 +215,8 @@ ScriptPromise USBDevice::claimInterface(ScriptState* scriptState, uint8_t interf
resolver->resolve();
} else {
m_interfaceStateChangeInProgress.set(interfaceIndex);
m_device->claimInterface(interfaceNumber, new ClaimInterfacePromiseAdapter(this, resolver, interfaceIndex, true /* claim */));
m_deviceRequests.add(resolver);
m_device->ClaimInterface(interfaceNumber, createBaseCallback(bind<bool>(&USBDevice::asyncClaimInterface, this, interfaceIndex, resolver)));
}
}
return promise;
@ -448,7 +239,8 @@ ScriptPromise USBDevice::releaseInterface(ScriptState* scriptState, uint8_t inte
// changing.
setEndpointsForInterface(interfaceIndex, false);
m_interfaceStateChangeInProgress.set(interfaceIndex);
m_device->releaseInterface(interfaceNumber, new ClaimInterfacePromiseAdapter(this, resolver, interfaceIndex, false /* release */));
m_deviceRequests.add(resolver);
m_device->ReleaseInterface(interfaceNumber, createBaseCallback(bind<bool>(&USBDevice::asyncReleaseInterface, this, interfaceIndex, resolver)));
}
}
return promise;
@ -470,7 +262,8 @@ ScriptPromise USBDevice::selectAlternateInterface(ScriptState* scriptState, uint
// the change is in progress.
setEndpointsForInterface(interfaceIndex, false);
m_interfaceStateChangeInProgress.set(interfaceIndex);
m_device->setInterface(interfaceNumber, alternateSetting, new SelectAlternateInterfacePromiseAdapter(this, resolver, interfaceIndex, alternateIndex));
m_deviceRequests.add(resolver);
m_device->SetInterfaceAlternateSetting(interfaceNumber, alternateSetting, createBaseCallback(bind<bool>(&USBDevice::asyncSelectAlternateInterface, this, interfaceNumber, alternateSetting, resolver)));
}
}
return promise;
@ -481,9 +274,11 @@ ScriptPromise USBDevice::controlTransferIn(ScriptState* scriptState, const USBCo
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureDeviceConfigured(resolver)) {
WebUSBDevice::ControlTransferParameters parameters;
if (convertControlTransferParameters(WebUSBDevice::TransferDirection::In, setup, &parameters, resolver))
m_device->controlTransfer(parameters, nullptr, length, 0, new CallbackPromiseAdapter<InputTransferResult, USBError>(resolver));
auto parameters = convertControlTransferParameters(setup, resolver);
if (parameters) {
m_deviceRequests.add(resolver);
m_device->ControlTransferIn(std::move(parameters), length, 0, createBaseCallback(bind<usb::TransferStatus, mojo::WTFArray<uint8_t>>(&USBDevice::asyncControlTransferIn, this, resolver)));
}
}
return promise;
}
@ -493,9 +288,11 @@ ScriptPromise USBDevice::controlTransferOut(ScriptState* scriptState, const USBC
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureDeviceConfigured(resolver)) {
WebUSBDevice::ControlTransferParameters parameters;
if (convertControlTransferParameters(WebUSBDevice::TransferDirection::Out, setup, &parameters, resolver))
m_device->controlTransfer(parameters, nullptr, 0, 0, new CallbackPromiseAdapter<OutputTransferResult, USBError>(resolver));
auto parameters = convertControlTransferParameters(setup, resolver);
if (parameters) {
m_deviceRequests.add(resolver);
m_device->ControlTransferOut(std::move(parameters), mojo::WTFArray<uint8_t>(), 0, createBaseCallback(bind<usb::TransferStatus>(&USBDevice::asyncControlTransferOut, this, 0, resolver)));
}
}
return promise;
}
@ -505,10 +302,12 @@ ScriptPromise USBDevice::controlTransferOut(ScriptState* scriptState, const USBC
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureDeviceConfigured(resolver)) {
WebUSBDevice::ControlTransferParameters parameters;
if (convertControlTransferParameters(WebUSBDevice::TransferDirection::Out, setup, &parameters, resolver)) {
BufferSource buffer(data);
m_device->controlTransfer(parameters, buffer.data(), buffer.size(), 0, new CallbackPromiseAdapter<OutputTransferResult, USBError>(resolver));
auto parameters = convertControlTransferParameters(setup, resolver);
if (parameters) {
mojo::WTFArray<uint8_t> buffer = convertBufferSource(data);
unsigned transferLength = buffer.size();
m_deviceRequests.add(resolver);
m_device->ControlTransferOut(std::move(parameters), std::move(buffer), 0, createBaseCallback(bind<usb::TransferStatus>(&USBDevice::asyncControlTransferOut, this, transferLength, resolver)));
}
}
return promise;
@ -518,8 +317,10 @@ ScriptPromise USBDevice::clearHalt(ScriptState* scriptState, String direction, u
{
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureEndpointAvailable(direction == "in", endpointNumber, resolver))
m_device->clearHalt(endpointNumber, new CallbackPromiseAdapter<void, USBError>(resolver));
if (ensureEndpointAvailable(direction == "in", endpointNumber, resolver)) {
m_deviceRequests.add(resolver);
m_device->ClearHalt(endpointNumber, createBaseCallback(bind<bool>(&USBDevice::asyncClearHalt, this, resolver)));
}
return promise;
}
@ -527,8 +328,10 @@ ScriptPromise USBDevice::transferIn(ScriptState* scriptState, uint8_t endpointNu
{
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureEndpointAvailable(true /* in */, endpointNumber, resolver))
m_device->transfer(WebUSBDevice::TransferDirection::In, endpointNumber, nullptr, length, 0, new CallbackPromiseAdapter<InputTransferResult, USBError>(resolver));
if (ensureEndpointAvailable(true /* in */, endpointNumber, resolver)) {
m_deviceRequests.add(resolver);
m_device->GenericTransferIn(endpointNumber, length, 0, createBaseCallback(bind<usb::TransferStatus, mojo::WTFArray<uint8_t>>(&USBDevice::asyncTransferIn, this, resolver)));
}
return promise;
}
@ -537,8 +340,10 @@ ScriptPromise USBDevice::transferOut(ScriptState* scriptState, uint8_t endpointN
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureEndpointAvailable(false /* out */, endpointNumber, resolver)) {
BufferSource buffer(data);
m_device->transfer(WebUSBDevice::TransferDirection::Out, endpointNumber, buffer.data(), buffer.size(), 0, new CallbackPromiseAdapter<OutputTransferResult, USBError>(resolver));
mojo::WTFArray<uint8_t> buffer = convertBufferSource(data);
unsigned transferLength = buffer.size();
m_deviceRequests.add(resolver);
m_device->GenericTransferOut(endpointNumber, std::move(buffer), 0, createBaseCallback(bind<usb::TransferStatus>(&USBDevice::asyncTransferOut, this, transferLength, resolver)));
}
return promise;
}
@ -547,8 +352,10 @@ ScriptPromise USBDevice::isochronousTransferIn(ScriptState* scriptState, uint8_t
{
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureEndpointAvailable(true /* in */, endpointNumber, resolver))
m_device->isochronousTransfer(WebUSBDevice::TransferDirection::In, endpointNumber, nullptr, 0, packetLengths, 0, new CallbackPromiseAdapter<IsochronousInputTransferResult, USBError>(resolver));
if (ensureEndpointAvailable(true /* in */, endpointNumber, resolver)) {
m_deviceRequests.add(resolver);
m_device->IsochronousTransferIn(endpointNumber, mojo::WTFArray<uint32_t>(std::move(packetLengths)), 0, createBaseCallback(bind<mojo::WTFArray<uint8_t>, mojo::WTFArray<usb::IsochronousPacketPtr>>(&USBDevice::asyncIsochronousTransferIn, this, resolver)));
}
return promise;
}
@ -557,8 +364,8 @@ ScriptPromise USBDevice::isochronousTransferOut(ScriptState* scriptState, uint8_
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureEndpointAvailable(false /* out */, endpointNumber, resolver)) {
BufferSource buffer(data);
m_device->isochronousTransfer(WebUSBDevice::TransferDirection::Out, endpointNumber, buffer.data(), buffer.size(), packetLengths, 0, new CallbackPromiseAdapter<IsochronousOutputTransferResult, USBError>(resolver));
m_deviceRequests.add(resolver);
m_device->IsochronousTransferOut(endpointNumber, convertBufferSource(data), mojo::WTFArray<uint32_t>(std::move(packetLengths)), 0, createBaseCallback(bind<mojo::WTFArray<usb::IsochronousPacketPtr>>(&USBDevice::asyncIsochronousTransferOut, this, resolver)));
}
return promise;
}
@ -568,32 +375,33 @@ ScriptPromise USBDevice::reset(ScriptState* scriptState)
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
if (ensureNoDeviceOrInterfaceChangeInProgress(resolver)) {
if (!m_opened)
if (!m_opened) {
resolver->reject(DOMException::create(InvalidStateError, kOpenRequired));
else
m_device->reset(new CallbackPromiseAdapter<void, USBError>(resolver));
} else {
m_deviceRequests.add(resolver);
m_device->Reset(createBaseCallback(bind<bool>(&USBDevice::asyncReset, this, resolver)));
}
}
return promise;
}
void USBDevice::contextDestroyed()
{
if (m_opened) {
m_device->close(new WebUSBDeviceCloseCallbacks());
m_opened = false;
}
m_device.reset();
m_deviceRequests.clear();
}
DEFINE_TRACE(USBDevice)
{
ContextLifecycleObserver::trace(visitor);
visitor->trace(m_deviceRequests);
}
int USBDevice::findConfigurationIndex(uint8_t configurationValue) const
{
const auto& configurations = info().configurations;
for (size_t i = 0; i < configurations.size(); ++i) {
if (configurations[i].configurationValue == configurationValue)
if (configurations[i]->configuration_value == configurationValue)
return i;
}
return -1;
@ -602,9 +410,9 @@ int USBDevice::findConfigurationIndex(uint8_t configurationValue) const
int USBDevice::findInterfaceIndex(uint8_t interfaceNumber) const
{
ASSERT(m_configurationIndex != -1);
const auto& interfaces = info().configurations[m_configurationIndex].interfaces;
const auto& interfaces = info().configurations[m_configurationIndex]->interfaces;
for (size_t i = 0; i < interfaces.size(); ++i) {
if (interfaces[i].interfaceNumber == interfaceNumber)
if (interfaces[i]->interface_number == interfaceNumber)
return i;
}
return -1;
@ -613,9 +421,9 @@ int USBDevice::findInterfaceIndex(uint8_t interfaceNumber) const
int USBDevice::findAlternateIndex(size_t interfaceIndex, uint8_t alternateSetting) const
{
ASSERT(m_configurationIndex != -1);
const auto& alternates = info().configurations[m_configurationIndex].interfaces[interfaceIndex].alternates;
const auto& alternates = info().configurations[m_configurationIndex]->interfaces[interfaceIndex]->alternates;
for (size_t i = 0; i < alternates.size(); ++i) {
if (alternates[i].alternateSetting == alternateSetting)
if (alternates[i]->alternate_setting == alternateSetting)
return i;
}
return -1;
@ -623,7 +431,9 @@ int USBDevice::findAlternateIndex(size_t interfaceIndex, uint8_t alternateSettin
bool USBDevice::ensureNoDeviceOrInterfaceChangeInProgress(ScriptPromiseResolver* resolver) const
{
if (m_deviceStateChangeInProgress)
if (!m_device)
resolver->reject(DOMException::create(NotFoundError, kDeviceUnavailable));
else if (m_deviceStateChangeInProgress)
resolver->reject(DOMException::create(InvalidStateError, kDeviceStateChangeInProgress));
else if (anyInterfaceChangeInProgress())
resolver->reject(DOMException::create(InvalidStateError, kInterfaceStateChangeInProgress));
@ -634,7 +444,9 @@ bool USBDevice::ensureNoDeviceOrInterfaceChangeInProgress(ScriptPromiseResolver*
bool USBDevice::ensureDeviceConfigured(ScriptPromiseResolver* resolver) const
{
if (m_deviceStateChangeInProgress)
if (!m_device)
resolver->reject(DOMException::create(NotFoundError, kDeviceUnavailable));
else if (m_deviceStateChangeInProgress)
resolver->reject(DOMException::create(InvalidStateError, kDeviceStateChangeInProgress));
else if (!m_opened)
resolver->reject(DOMException::create(InvalidStateError, kOpenRequired));
@ -686,65 +498,303 @@ bool USBDevice::anyInterfaceChangeInProgress() const
return false;
}
bool USBDevice::convertControlTransferParameters(
WebUSBDevice::TransferDirection direction,
usb::ControlTransferParamsPtr USBDevice::convertControlTransferParameters(
const USBControlTransferParameters& parameters,
WebUSBDevice::ControlTransferParameters* webParameters,
ScriptPromiseResolver* resolver) const
{
webParameters->direction = direction;
auto mojoParameters = usb::ControlTransferParams::New();
if (parameters.requestType() == "standard") {
webParameters->type = WebUSBDevice::RequestType::Standard;
mojoParameters->type = usb::ControlTransferType::STANDARD;
} else if (parameters.requestType() == "class") {
webParameters->type = WebUSBDevice::RequestType::Class;
mojoParameters->type = usb::ControlTransferType::CLASS;
} else if (parameters.requestType() == "vendor") {
webParameters->type = WebUSBDevice::RequestType::Vendor;
mojoParameters->type = usb::ControlTransferType::VENDOR;
} else {
resolver->reject(DOMException::create(TypeMismatchError, "The control transfer requestType parameter is invalid."));
return false;
return nullptr;
}
if (parameters.recipient() == "device") {
webParameters->recipient = WebUSBDevice::RequestRecipient::Device;
mojoParameters->recipient = usb::ControlTransferRecipient::DEVICE;
} else if (parameters.recipient() == "interface") {
size_t interfaceNumber = parameters.index() & 0xff;
if (!ensureInterfaceClaimed(interfaceNumber, resolver))
return false;
webParameters->recipient = WebUSBDevice::RequestRecipient::Interface;
return nullptr;
mojoParameters->recipient = usb::ControlTransferRecipient::INTERFACE;
} else if (parameters.recipient() == "endpoint") {
bool inTransfer = parameters.index() & 0x80;
size_t endpointNumber = parameters.index() & 0x0f;
if (!ensureEndpointAvailable(inTransfer, endpointNumber, resolver))
return false;
webParameters->recipient = WebUSBDevice::RequestRecipient::Endpoint;
return nullptr;
mojoParameters->recipient = usb::ControlTransferRecipient::ENDPOINT;
} else if (parameters.recipient() == "other") {
webParameters->recipient = WebUSBDevice::RequestRecipient::Other;
mojoParameters->recipient = usb::ControlTransferRecipient::OTHER;
} else {
resolver->reject(DOMException::create(TypeMismatchError, "The control transfer recipient parameter is invalid."));
return false;
return nullptr;
}
webParameters->request = parameters.request();
webParameters->value = parameters.value();
webParameters->index = parameters.index();
return true;
mojoParameters->request = parameters.request();
mojoParameters->value = parameters.value();
mojoParameters->index = parameters.index();
return mojoParameters;
}
void USBDevice::setEndpointsForInterface(size_t interfaceIndex, bool set)
{
const auto& configuration = info().configurations[m_configurationIndex];
const auto& interface = configuration.interfaces[interfaceIndex];
const auto& alternate = interface.alternates[m_selectedAlternates[interfaceIndex]];
for (const auto& endpoint : alternate.endpoints) {
if (endpoint.endpointNumber == 0 || endpoint.endpointNumber >= 16)
const auto& configuration = *info().configurations[m_configurationIndex];
const auto& interface = *configuration.interfaces[interfaceIndex];
const auto& alternate = *interface.alternates[m_selectedAlternates[interfaceIndex]];
for (const auto& endpoint : alternate.endpoints.storage()) {
uint8_t endpointNumber = endpoint->endpoint_number;
if (endpointNumber == 0 || endpointNumber >= 16)
continue; // Ignore endpoints with invalid indices.
auto& bitVector = endpoint.direction == WebUSBDevice::TransferDirection::In ? m_inEndpoints : m_outEndpoints;
auto& bitVector = endpoint->direction == usb::TransferDirection::INBOUND ? m_inEndpoints : m_outEndpoints;
if (set)
bitVector.set(endpoint.endpointNumber - 1);
bitVector.set(endpointNumber - 1);
else
bitVector.clear(endpoint.endpointNumber - 1);
bitVector.clear(endpointNumber - 1);
}
}
void USBDevice::asyncOpen(ScriptPromiseResolver* resolver, usb::OpenDeviceError error)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
switch (error) {
case usb::OpenDeviceError::ALREADY_OPEN:
ASSERT_NOT_REACHED();
// fall through
case usb::OpenDeviceError::OK:
onDeviceOpenedOrClosed(true /* opened */);
resolver->resolve();
return;
case usb::OpenDeviceError::ACCESS_DENIED:
onDeviceOpenedOrClosed(false /* not opened */);
resolver->reject(DOMException::create(SecurityError, "Access denied."));
return;
}
}
void USBDevice::asyncClose(ScriptPromiseResolver* resolver)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
onDeviceOpenedOrClosed(false /* closed */);
resolver->resolve();
}
void USBDevice::onDeviceOpenedOrClosed(bool opened)
{
m_opened = opened;
m_deviceStateChangeInProgress = false;
}
void USBDevice::asyncSelectConfiguration(size_t configurationIndex, ScriptPromiseResolver* resolver, bool success)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
onConfigurationSelected(success, configurationIndex);
if (success)
resolver->resolve();
else
resolver->reject(DOMException::create(NetworkError, "Unable to set device configuration."));
}
void USBDevice::onConfigurationSelected(bool success, size_t configurationIndex)
{
if (success) {
m_configurationIndex = configurationIndex;
size_t numInterfaces = info().configurations[m_configurationIndex]->interfaces.size();
m_claimedInterfaces.clearAll();
m_claimedInterfaces.resize(numInterfaces);
m_interfaceStateChangeInProgress.clearAll();
m_interfaceStateChangeInProgress.resize(numInterfaces);
m_selectedAlternates.resize(numInterfaces);
m_selectedAlternates.fill(0);
m_inEndpoints.clearAll();
m_outEndpoints.clearAll();
}
m_deviceStateChangeInProgress = false;
}
void USBDevice::asyncClaimInterface(size_t interfaceIndex, ScriptPromiseResolver* resolver, bool success)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
onInterfaceClaimedOrUnclaimed(success, interfaceIndex);
if (success)
resolver->resolve();
else
resolver->reject(DOMException::create(NetworkError, "Unable to claim interface."));
}
void USBDevice::asyncReleaseInterface(size_t interfaceIndex, ScriptPromiseResolver* resolver, bool success)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
onInterfaceClaimedOrUnclaimed(!success, interfaceIndex);
if (success)
resolver->resolve();
else
resolver->reject(DOMException::create(NetworkError, "Unable to release interface."));
}
void USBDevice::onInterfaceClaimedOrUnclaimed(bool claimed, size_t interfaceIndex)
{
if (claimed) {
m_claimedInterfaces.set(interfaceIndex);
} else {
m_claimedInterfaces.clear(interfaceIndex);
m_selectedAlternates[interfaceIndex] = 0;
}
setEndpointsForInterface(interfaceIndex, claimed);
m_interfaceStateChangeInProgress.clear(interfaceIndex);
}
void USBDevice::asyncSelectAlternateInterface(size_t interfaceIndex, size_t alternateIndex, ScriptPromiseResolver* resolver, bool success)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
if (success)
m_selectedAlternates[interfaceIndex] = alternateIndex;
setEndpointsForInterface(interfaceIndex, success);
m_interfaceStateChangeInProgress.clear(interfaceIndex);
if (success)
resolver->resolve();
else
resolver->reject(DOMException::create(NetworkError, "Unable to set device interface."));
}
void USBDevice::asyncControlTransferIn(ScriptPromiseResolver* resolver, usb::TransferStatus status, mojo::WTFArray<uint8_t> data)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
DOMException* error = convertFatalTransferStatus(status);
if (error)
resolver->reject(error);
else
resolver->resolve(USBInTransferResult::create(convertTransferStatus(status), data.PassStorage()));
}
void USBDevice::asyncControlTransferOut(unsigned transferLength, ScriptPromiseResolver* resolver, usb::TransferStatus status)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
DOMException* error = convertFatalTransferStatus(status);
if (error)
resolver->reject(error);
else
resolver->resolve(USBOutTransferResult::create(convertTransferStatus(status), transferLength));
}
void USBDevice::asyncClearHalt(ScriptPromiseResolver* resolver, bool success)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
if (success)
resolver->resolve();
else
resolver->reject(DOMException::create(NetworkError, "Unable to clear endpoint."));
}
void USBDevice::asyncTransferIn(ScriptPromiseResolver* resolver, usb::TransferStatus status, mojo::WTFArray<uint8_t> data)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
DOMException* error = convertFatalTransferStatus(status);
if (error)
resolver->reject(error);
else
resolver->resolve(USBInTransferResult::create(convertTransferStatus(status), data.PassStorage()));
}
void USBDevice::asyncTransferOut(unsigned transferLength, ScriptPromiseResolver* resolver, usb::TransferStatus status)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
DOMException* error = convertFatalTransferStatus(status);
if (error)
resolver->reject(error);
else
resolver->resolve(USBOutTransferResult::create(convertTransferStatus(status), transferLength));
}
void USBDevice::asyncIsochronousTransferIn(ScriptPromiseResolver* resolver, mojo::WTFArray<uint8_t> data, mojo::WTFArray<usb::IsochronousPacketPtr> mojoPackets)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
DOMArrayBuffer* buffer = DOMArrayBuffer::create(data.storage().data(), data.storage().size());
HeapVector<Member<USBIsochronousInTransferPacket>> packets;
packets.reserveCapacity(mojoPackets.size());
size_t byteOffset = 0;
for (const auto& packet : mojoPackets.storage()) {
DOMException* error = convertFatalTransferStatus(packet->status);
if (error) {
resolver->reject(error);
return;
}
packets.append(USBIsochronousInTransferPacket::create(convertTransferStatus(packet->status), DOMDataView::create(buffer, byteOffset, packet->transferred_length)));
byteOffset += packet->length;
}
resolver->resolve(USBIsochronousInTransferResult::create(buffer, packets));
}
void USBDevice::asyncIsochronousTransferOut(ScriptPromiseResolver* resolver, mojo::WTFArray<usb::IsochronousPacketPtr> mojoPackets)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
HeapVector<Member<USBIsochronousOutTransferPacket>> packets;
packets.reserveCapacity(mojoPackets.size());
for (const auto& packet : mojoPackets.storage()) {
DOMException* error = convertFatalTransferStatus(packet->status);
if (error) {
resolver->reject(error);
return;
}
packets.append(USBIsochronousOutTransferPacket::create(convertTransferStatus(packet->status), packet->transferred_length));
}
resolver->resolve(USBIsochronousOutTransferResult::create(packets));
}
void USBDevice::asyncReset(ScriptPromiseResolver* resolver, bool success)
{
m_deviceRequests.remove(resolver);
if (!isActive(resolver))
return;
if (success)
resolver->resolve();
else
resolver->reject(DOMException::create(NetworkError, "Unable to reset the device."));
}
} // namespace blink

@ -9,9 +9,8 @@
#include "bindings/core/v8/ScriptWrappable.h"
#include "bindings/modules/v8/UnionTypesModules.h"
#include "core/dom/ContextLifecycleObserver.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "platform/heap/Handle.h"
#include "public/platform/modules/webusb/WebUSBDevice.h"
#include "public/platform/modules/webusb/WebUSBDeviceInfo.h"
#include "wtf/BitVector.h"
#include "wtf/Vector.h"
@ -29,42 +28,34 @@ class USBDevice
USING_GARBAGE_COLLECTED_MIXIN(USBDevice);
DEFINE_WRAPPERTYPEINFO();
public:
using WebType = OwnPtr<WebUSBDevice>;
static USBDevice* create(PassOwnPtr<WebUSBDevice> device, ExecutionContext* context)
static USBDevice* create(device::usb::wtf::DeviceInfoPtr deviceInfo, device::usb::wtf::DevicePtr device, ExecutionContext* context)
{
return new USBDevice(device, context);
return new USBDevice(std::move(deviceInfo), std::move(device), context);
}
static USBDevice* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBDevice>);
explicit USBDevice(device::usb::wtf::DeviceInfoPtr, device::usb::wtf::DevicePtr, ExecutionContext*);
virtual ~USBDevice();
explicit USBDevice(PassOwnPtr<WebUSBDevice>, ExecutionContext*);
virtual ~USBDevice() { }
const WebUSBDeviceInfo& info() const { return m_device->info(); }
void onDeviceOpenedOrClosed(bool);
void onConfigurationSelected(bool success, size_t configurationIndex);
void onInterfaceClaimedOrUnclaimed(bool claimed, size_t interfaceIndex);
void onAlternateInterfaceSelected(bool success, size_t interfaceIndex, size_t alternateIndex);
const device::usb::wtf::DeviceInfo& info() const { return *m_deviceInfo; }
bool isInterfaceClaimed(size_t configurationIndex, size_t interfaceIndex) const;
size_t selectedAlternateInterface(size_t interfaceIndex) const;
// IDL exposed interface:
// USBDevice.idl
String guid() const { return info().guid; }
uint8_t usbVersionMajor() { return info().usbVersionMajor; }
uint8_t usbVersionMinor() { return info().usbVersionMinor; }
uint8_t usbVersionSubminor() { return info().usbVersionSubminor; }
uint8_t deviceClass() { return info().deviceClass; }
uint8_t deviceSubclass() const { return info().deviceSubclass; }
uint8_t deviceProtocol() const { return info().deviceProtocol; }
uint16_t vendorId() const { return info().vendorID; }
uint16_t productId() const { return info().productID; }
uint8_t deviceVersionMajor() const { return info().deviceVersionMajor; }
uint8_t deviceVersionMinor() const { return info().deviceVersionMinor; }
uint8_t deviceVersionSubminor() const { return info().deviceVersionSubminor; }
String manufacturerName() const { return info().manufacturerName; }
String productName() const { return info().productName; }
String serialNumber() const { return info().serialNumber; }
uint8_t usbVersionMajor() const { return info().usb_version_major; }
uint8_t usbVersionMinor() const { return info().usb_version_minor; }
uint8_t usbVersionSubminor() const { return info().usb_version_subminor; }
uint8_t deviceClass() const { return info().class_code; }
uint8_t deviceSubclass() const { return info().subclass_code; }
uint8_t deviceProtocol() const { return info().protocol_code; }
uint16_t vendorId() const { return info().vendor_id; }
uint16_t productId() const { return info().product_id; }
uint8_t deviceVersionMajor() const { return info().device_version_major; }
uint8_t deviceVersionMinor() const { return info().device_version_minor; }
uint8_t deviceVersionSubminor() const { return info().device_version_subminor; }
String manufacturerName() const { return info().manufacturer_name; }
String productName() const { return info().product_name; }
String serialNumber() const { return info().serial_number; }
USBConfiguration* configuration() const;
HeapVector<Member<USBConfiguration>> configurations() const;
bool opened() const { return m_opened; }
@ -99,10 +90,30 @@ private:
bool ensureInterfaceClaimed(uint8_t interfaceNumber, ScriptPromiseResolver*) const;
bool ensureEndpointAvailable(bool inTransfer, uint8_t endpointNumber, ScriptPromiseResolver*) const;
bool anyInterfaceChangeInProgress() const;
bool convertControlTransferParameters(WebUSBDevice::TransferDirection, const USBControlTransferParameters&, WebUSBDevice::ControlTransferParameters*, ScriptPromiseResolver*) const;
device::usb::wtf::ControlTransferParamsPtr convertControlTransferParameters(const USBControlTransferParameters&, ScriptPromiseResolver*) const;
void setEndpointsForInterface(size_t interfaceIndex, bool set);
OwnPtr<WebUSBDevice> m_device;
void asyncOpen(ScriptPromiseResolver*, device::usb::wtf::OpenDeviceError);
void asyncClose(ScriptPromiseResolver*);
void onDeviceOpenedOrClosed(bool);
void asyncSelectConfiguration(size_t configurationIndex, ScriptPromiseResolver*, bool success);
void onConfigurationSelected(bool success, size_t configurationIndex);
void asyncClaimInterface(size_t interfaceIndex, ScriptPromiseResolver*, bool success);
void asyncReleaseInterface(size_t interfaceIndex, ScriptPromiseResolver*, bool success);
void onInterfaceClaimedOrUnclaimed(bool claimed, size_t interfaceIndex);
void asyncSelectAlternateInterface(size_t interfaceIndex, size_t alternateIndex, ScriptPromiseResolver*, bool success);
void asyncControlTransferIn(ScriptPromiseResolver*, device::usb::wtf::TransferStatus, mojo::WTFArray<uint8_t>);
void asyncControlTransferOut(unsigned, ScriptPromiseResolver*, device::usb::wtf::TransferStatus);
void asyncClearHalt(ScriptPromiseResolver*, bool success);
void asyncTransferIn(ScriptPromiseResolver*, device::usb::wtf::TransferStatus, mojo::WTFArray<uint8_t>);
void asyncTransferOut(unsigned, ScriptPromiseResolver*, device::usb::wtf::TransferStatus);
void asyncIsochronousTransferIn(ScriptPromiseResolver*, mojo::WTFArray<uint8_t>, mojo::WTFArray<device::usb::wtf::IsochronousPacketPtr>);
void asyncIsochronousTransferOut(ScriptPromiseResolver*, mojo::WTFArray<device::usb::wtf::IsochronousPacketPtr>);
void asyncReset(ScriptPromiseResolver*, bool success);
device::usb::wtf::DeviceInfoPtr m_deviceInfo;
device::usb::wtf::DevicePtr m_device;
HeapHashSet<Member<ScriptPromiseResolver>> m_deviceRequests;
bool m_opened;
bool m_deviceStateChangeInProgress;
int m_configurationIndex;

@ -7,30 +7,22 @@
#include "bindings/core/v8/ExceptionState.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "modules/webusb/USBAlternateInterface.h"
#include "public/platform/modules/webusb/WebUSBDevice.h"
using device::usb::wtf::EndpointType;
using device::usb::wtf::TransferDirection;
namespace blink {
namespace {
bool convertDirectionFromEnum(const String& direction, WebUSBDevice::TransferDirection* webDirection)
{
if (direction == "in")
*webDirection = WebUSBDevice::TransferDirection::In;
else if (direction == "out")
*webDirection = WebUSBDevice::TransferDirection::Out;
else
return false;
return true;
}
String convertDirectionToEnum(const WebUSBDevice::TransferDirection& direction)
String convertDirectionToEnum(const TransferDirection& direction)
{
switch (direction) {
case WebUSBDevice::TransferDirection::In:
case TransferDirection::INBOUND:
return "in";
case WebUSBDevice::TransferDirection::Out:
case TransferDirection::OUTBOUND:
return "out";
default:
ASSERT_NOT_REACHED();
@ -38,14 +30,14 @@ String convertDirectionToEnum(const WebUSBDevice::TransferDirection& direction)
}
}
String convertTypeToEnum(const WebUSBDeviceInfo::Endpoint::Type& type)
String convertTypeToEnum(const EndpointType& type)
{
switch (type) {
case WebUSBDeviceInfo::Endpoint::Type::Bulk:
case EndpointType::BULK:
return "bulk";
case WebUSBDeviceInfo::Endpoint::Type::Interrupt:
case EndpointType::INTERRUPT:
return "interrupt";
case WebUSBDeviceInfo::Endpoint::Type::Isochronous:
case EndpointType::ISOCHRONOUS:
return "isochronous";
default:
ASSERT_NOT_REACHED();
@ -62,17 +54,14 @@ USBEndpoint* USBEndpoint::create(const USBAlternateInterface* alternate, size_t
USBEndpoint* USBEndpoint::create(const USBAlternateInterface* alternate, size_t endpointNumber, const String& direction, ExceptionState& exceptionState)
{
WebUSBDevice::TransferDirection webDirection;
if (!convertDirectionFromEnum(direction, &webDirection)) {
exceptionState.throwRangeError("Invalid endpoint direction.");
return nullptr;
}
for (size_t i = 0; i < alternate->info().endpoints.size(); ++i) {
const WebUSBDeviceInfo::Endpoint& endpoint = alternate->info().endpoints[i];
if (endpoint.endpointNumber == endpointNumber && endpoint.direction == webDirection)
TransferDirection mojoDirection = direction == "in" ? TransferDirection::INBOUND : TransferDirection::OUTBOUND;
const auto& endpoints = alternate->info().endpoints;
for (size_t i = 0; i < endpoints.size(); ++i) {
const auto& endpoint = endpoints[i];
if (endpoint->endpoint_number == endpointNumber && endpoint->direction == mojoDirection)
return USBEndpoint::create(alternate, i);
}
exceptionState.throwRangeError("Invalid endpoint number.");
exceptionState.throwRangeError("No such endpoint exists in the given alternate interface.");
return nullptr;
}
@ -84,16 +73,11 @@ USBEndpoint::USBEndpoint(const USBAlternateInterface* alternate, size_t endpoint
ASSERT(m_endpointIndex < m_alternate->info().endpoints.size());
}
const WebUSBDeviceInfo::Endpoint& USBEndpoint::info() const
const device::usb::wtf::EndpointInfo& USBEndpoint::info() const
{
const WebUSBDeviceInfo::AlternateInterface& alternateInfo = m_alternate->info();
const device::usb::wtf::AlternateInterfaceInfo& alternateInfo = m_alternate->info();
ASSERT(m_endpointIndex < alternateInfo.endpoints.size());
return alternateInfo.endpoints[m_endpointIndex];
}
uint8_t USBEndpoint::endpointNumber() const
{
return info().endpointNumber;
return *alternateInfo.endpoints[m_endpointIndex];
}
String USBEndpoint::direction() const
@ -106,11 +90,6 @@ String USBEndpoint::type() const
return convertTypeToEnum(info().type);
}
unsigned USBEndpoint::packetSize() const
{
return info().packetSize;
}
DEFINE_TRACE(USBEndpoint)
{
visitor->trace(m_alternate);

@ -6,8 +6,8 @@
#define USBEndpoint_h
#include "bindings/core/v8/ScriptWrappable.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "platform/heap/Heap.h"
#include "public/platform/modules/webusb/WebUSBDeviceInfo.h"
namespace blink {
@ -24,12 +24,12 @@ public:
USBEndpoint(const USBAlternateInterface*, size_t endpointIndex);
const WebUSBDeviceInfo::Endpoint& info() const;
const device::usb::wtf::EndpointInfo& info() const;
uint8_t endpointNumber() const;
uint8_t endpointNumber() const { return info().endpoint_number; }
String direction() const;
String type() const;
unsigned packetSize() const;
unsigned packetSize() const { return info().packet_size; }
DECLARE_TRACE();

@ -1,29 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/webusb/USBError.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "public/platform/modules/webusb/WebUSBError.h"
namespace blink {
DOMException* USBError::take(ScriptPromiseResolver*, const WebUSBError& webError)
{
switch (webError.error) {
case WebUSBError::Error::InvalidState:
return DOMException::create(InvalidStateError, webError.message);
case WebUSBError::Error::Network:
return DOMException::create(NetworkError, webError.message);
case WebUSBError::Error::NotFound:
return DOMException::create(NotFoundError, webError.message);
case WebUSBError::Error::Security:
return DOMException::create(SecurityError, webError.message);
}
ASSERT_NOT_REACHED();
return DOMException::create(UnknownError);
}
} // namespace blink

@ -1,32 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef USBError_h
#define USBError_h
#include "platform/heap/Handle.h"
#include "public/platform/modules/webusb/WebUSBError.h"
#include "wtf/PassOwnPtr.h"
namespace blink {
class DOMException;
class ScriptPromiseResolver;
// USBError is used with CallbackPromiseAdapter to receive WebUSBError
// responses. See CallbackPromiseAdapter class comments.
class USBError {
WTF_MAKE_NONCOPYABLE(USBError);
public:
// Interface required by CallbackPromiseAdapter:
using WebType = const WebUSBError&;
static DOMException* take(ScriptPromiseResolver*, const WebUSBError&);
private:
USBError() = delete;
};
} // namespace blink
#endif // USBError_h

@ -9,7 +9,7 @@
#include "core/dom/DOMArrayBuffer.h"
#include "core/dom/DOMDataView.h"
#include "platform/heap/Handle.h"
#include "public/platform/modules/webusb/WebUSBTransferInfo.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"
namespace blink {
@ -19,12 +19,12 @@ class USBInTransferResult final
, public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
static USBInTransferResult* create(const String& status, const WebVector<uint8_t> data)
static USBInTransferResult* create(const String& status, const Vector<uint8_t>& data)
{
return new USBInTransferResult(status, data);
}
USBInTransferResult(const String& status, const WebVector<uint8_t> data)
USBInTransferResult(const String& status, const Vector<uint8_t>& data)
: m_status(status)
, m_data(DOMDataView::create(DOMArrayBuffer::create(data.data(), data.size()), 0, data.size()))
{

@ -5,6 +5,7 @@
#include "modules/webusb/USBInterface.h"
#include "bindings/core/v8/ExceptionState.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "modules/webusb/USBAlternateInterface.h"
#include "modules/webusb/USBConfiguration.h"
#include "modules/webusb/USBDevice.h"
@ -20,7 +21,7 @@ USBInterface* USBInterface::create(const USBConfiguration* configuration, size_t
{
const auto& interfaces = configuration->info().interfaces;
for (size_t i = 0; i < interfaces.size(); ++i) {
if (interfaces[i].interfaceNumber == interfaceNumber)
if (interfaces[i]->interface_number == interfaceNumber)
return new USBInterface(configuration->device(), configuration->index(), i);
}
exceptionState.throwRangeError("Invalid interface index.");
@ -33,12 +34,12 @@ USBInterface::USBInterface(const USBDevice* device, size_t configurationIndex, s
, m_interfaceIndex(interfaceIndex)
{
ASSERT(m_configurationIndex < m_device->info().configurations.size());
ASSERT(m_interfaceIndex < m_device->info().configurations[m_configurationIndex].interfaces.size());
ASSERT(m_interfaceIndex < m_device->info().configurations[m_configurationIndex]->interfaces.size());
}
const WebUSBDeviceInfo::Interface& USBInterface::info() const
const device::usb::wtf::InterfaceInfo& USBInterface::info() const
{
return m_device->info().configurations[m_configurationIndex].interfaces[m_interfaceIndex];
return *m_device->info().configurations[m_configurationIndex]->interfaces[m_interfaceIndex];
}
USBAlternateInterface* USBInterface::alternate() const
@ -56,11 +57,6 @@ HeapVector<Member<USBAlternateInterface>> USBInterface::alternates() const
return alternates;
}
uint8_t USBInterface::interfaceNumber() const
{
return info().interfaceNumber;
}
bool USBInterface::claimed() const
{
return m_device->isInterfaceClaimed(m_configurationIndex, m_interfaceIndex);

@ -6,8 +6,8 @@
#define USBInterface_h
#include "bindings/core/v8/ScriptWrappable.h"
#include "device/usb/public/interfaces/device.mojom-wtf.h"
#include "platform/heap/Heap.h"
#include "public/platform/modules/webusb/WebUSBDeviceInfo.h"
namespace blink {
@ -26,9 +26,9 @@ public:
USBInterface(const USBDevice*, size_t configurationIndex, size_t interfaceIndex);
const WebUSBDeviceInfo::Interface& info() const;
const device::usb::wtf::InterfaceInfo& info() const;
uint8_t interfaceNumber() const;
uint8_t interfaceNumber() const { return info().interface_number; }
USBAlternateInterface* alternate() const;
HeapVector<Member<USBAlternateInterface>> alternates() const;
bool claimed() const;

@ -6,9 +6,7 @@
#define USBOutTransferResult_h
#include "bindings/core/v8/ScriptWrappable.h"
#include "core/dom/DOMArrayBuffer.h"
#include "platform/heap/Handle.h"
#include "public/platform/modules/webusb/WebUSBTransferInfo.h"
#include "wtf/text/WTFString.h"
namespace blink {

@ -13,6 +13,16 @@
namespace blink {
namespace internal {
template <typename R, typename... Args>
R CallWTFFunction(Function<R(Args...)>* functor, Args... args)
{
return (*functor)(std::forward<Args>(args)...);
}
}
// Binds an instance of a class to its member function. Does not bind anything
// else. Provides limited access to base::Bind() function. base::Bind() could
// be dangerous if it's used across threads, so we don't want to allow general
@ -24,6 +34,12 @@ sameThreadBindForMojo(ReturnType (Class::*method)(Args...), Class* instance)
return base::Bind(method, base::Unretained(instance));
}
template <typename R, typename... Args>
base::Callback<R(Args...)> createBaseCallback(PassOwnPtr<Function<R(Args...)>> functor)
{
return base::Bind(&internal::CallWTFFunction<R, Args...>, base::Owned(functor.leakPtr()));
}
} // namespace blink
namespace mojo {

@ -166,7 +166,6 @@
#include "modules/screen_orientation/ScreenOrientationController.h"
#include "modules/vr/VRController.h"
#include "modules/wake_lock/ScreenWakeLock.h"
#include "modules/webusb/USBController.h"
#include "platform/ScriptForbiddenScope.h"
#include "platform/TraceEvent.h"
#include "platform/UserGestureIndicator.h"
@ -1478,10 +1477,6 @@ void WebLocalFrameImpl::setCoreFrame(LocalFrame* frame)
provideLocalFileSystemTo(*m_frame, LocalFileSystemClient::create());
provideNavigatorContentUtilsTo(*m_frame, NavigatorContentUtilsClientImpl::create(this));
// Always provided so that availability of the API can be controlled by
// OriginTrials::webUSBEnabled().
USBController::provideTo(*m_frame, m_client ? m_client->usbClient() : nullptr);
bool enableWebBluetooth = RuntimeEnabledFeatures::webBluetoothEnabled();
#if OS(CHROMEOS) || OS(ANDROID)
enableWebBluetooth = true;

@ -319,13 +319,6 @@
"platform/modules/websockets/WebSocketHandleClient.h",
"platform/modules/websockets/WebSocketHandshakeRequestInfo.h",
"platform/modules/websockets/WebSocketHandshakeResponseInfo.h",
"platform/modules/webusb/WebUSBClient.h",
"platform/modules/webusb/WebUSBDeviceFilter.h",
"platform/modules/webusb/WebUSBDevice.h",
"platform/modules/webusb/WebUSBDeviceInfo.h",
"platform/modules/webusb/WebUSBDeviceRequestOptions.h",
"platform/modules/webusb/WebUSBError.h",
"platform/modules/webusb/WebUSBTransferInfo.h",
"web/WebAXEnums.h",
"web/WebAXObject.h",
"web/WebActiveWheelFlingParameters.h",

@ -1,2 +0,0 @@
reillyg@chromium.org
rockot@chromium.org

@ -1,52 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBClient_h
#define WebUSBClient_h
#include "public/platform/WebCallbacks.h"
#include "public/platform/WebVector.h"
namespace blink {
class WebUSBDevice;
struct WebUSBDeviceRequestOptions;
struct WebUSBError;
using WebUSBClientGetDevicesCallbacks = WebCallbacks<std::unique_ptr<WebVector<WebUSBDevice*>>, const WebUSBError&>;
using WebUSBClientRequestDeviceCallbacks = WebCallbacks<std::unique_ptr<WebUSBDevice>, const WebUSBError&>;
class WebUSBClient {
public:
class Observer {
public:
virtual ~Observer() { }
// Called when a device is connected to the system.
virtual void onDeviceConnected(std::unique_ptr<WebUSBDevice>) = 0;
// Called when a device is disconnected from the system.
virtual void onDeviceDisconnected(std::unique_ptr<WebUSBDevice>) = 0;
};
virtual ~WebUSBClient() { }
// Enumerates available devices.
// Ownership of the WebUSBClientGetDevicesCallbacks is transferred to the client.
virtual void getDevices(WebUSBClientGetDevicesCallbacks*) = 0;
// Requests access to a device.
// Ownership of the WebUSBClientRequestDeviceCallbacks is transferred to the client.
virtual void requestDevice(const WebUSBDeviceRequestOptions&, WebUSBClientRequestDeviceCallbacks*) = 0;
// Adds an observer of device changes to the WebUSBClient.
virtual void addObserver(Observer*) = 0;
// Removes an observer of device changes from the WebUSBClient.
virtual void removeObserver(Observer*) = 0;
};
} // namespace blink
#endif // WebUSBClient_h

@ -1,109 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBDevice_h
#define WebUSBDevice_h
#include "public/platform/WebCallbacks.h"
#include "public/platform/WebVector.h"
#include <memory>
namespace blink {
struct WebUSBDeviceInfo;
struct WebUSBError;
struct WebUSBTransferInfo;
using WebUSBDeviceOpenCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceCloseCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceSetConfigurationCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceClaimInterfaceCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceReleaseInterfaceCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceResetCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceSetInterfaceAlternateSettingCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceClearHaltCallbacks = WebCallbacks<void, const WebUSBError&>;
using WebUSBDeviceTransferCallbacks = WebCallbacks<std::unique_ptr<WebUSBTransferInfo>, const WebUSBError&>;
class WebUSBDevice {
public:
enum class TransferDirection {
In,
Out,
};
enum class RequestType {
Standard,
Class,
Vendor,
};
enum class RequestRecipient {
Device,
Interface,
Endpoint,
Other,
};
struct ControlTransferParameters {
TransferDirection direction;
RequestType type;
RequestRecipient recipient;
uint8_t request;
uint16_t value;
uint16_t index;
};
virtual ~WebUSBDevice() { }
virtual const WebUSBDeviceInfo& info() const = 0;
// Opens the device.
// Ownership of the WebUSBDeviceOpenCallbacks is transferred to the client.
virtual void open(WebUSBDeviceOpenCallbacks*) = 0;
// Closes the device.
// Ownership of the WebUSBDeviceCloseCallbacks is transferred to the client.
virtual void close(WebUSBDeviceCloseCallbacks*) = 0;
// Sets the active configuration for the device.
// Ownership of the WebUSBDeviceSetConfigurationCallbacks is transferred to the client.
virtual void setConfiguration(uint8_t configurationValue, WebUSBDeviceSetConfigurationCallbacks*) = 0;
// Claims an interface in the active configuration.
// Ownership of the WebUSBDeviceClaimInterfaceCallbacks is transferred to the client.
virtual void claimInterface(uint8_t interfaceNumber, WebUSBDeviceClaimInterfaceCallbacks*) = 0;
// Releases a claimed interface.
// Ownership of the WebUSBDeviceReleaseInterfaceCallbacks is transferred to the client.
virtual void releaseInterface(uint8_t interfaceNumber, WebUSBDeviceReleaseInterfaceCallbacks*) = 0;
// Sets the alternate setting of an interface.
// Ownership of the WebUSBDeviceSetInterfaceAlternateSettingCallbacks is transferred to the client.
virtual void setInterface(uint8_t interfaceNumber, uint8_t alternateSetting, WebUSBDeviceSetInterfaceAlternateSettingCallbacks*) = 0;
// Clears the halt condition on a specific endpoint.
// Ownership of the WebUSBDeviceClearHaltCallbacks is transferred to the client.
virtual void clearHalt(uint8_t endpointNumber, WebUSBDeviceClearHaltCallbacks*) = 0;
// Initiates a control transfer.
// Ownership of the WebUSBDeviceTransferCallbacks is transferred to the client.
virtual void controlTransfer(const ControlTransferParameters&, uint8_t* data, size_t dataSize, unsigned timeout, WebUSBDeviceTransferCallbacks*) = 0;
// Initiates a bulk or interrupt transfer.
// Ownership of the WebUSBDeviceTransferCallbacks is transferred to the client.
virtual void transfer(TransferDirection, uint8_t endpointNumber, uint8_t* data, size_t dataSize, unsigned timeout, WebUSBDeviceTransferCallbacks*) = 0;
// Initiates an isochronous transfer.
// Ownership of the WebUSBDeviceTransferCallbacks is transferred to the client.
virtual void isochronousTransfer(TransferDirection, uint8_t endpointNumber, uint8_t* data, size_t dataSize, WebVector<unsigned> packetLengths, unsigned timeout, WebUSBDeviceTransferCallbacks*) = 0;
// Resets the device.
// Ownership of the WebUSBDeviceResetCallbacks is transferred to the client.
virtual void reset(WebUSBDeviceResetCallbacks*) = 0;
};
} // namespace blink
#endif // WebUSBDevice_h

@ -1,34 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBDeviceFilter_h
#define WebUSBDeviceFilter_h
#include "public/platform/WebCommon.h"
namespace blink {
// Filter which specifies what devices the API consumer wants to enumerate.
// Properties which are not present in a filter should be treated as wildcards.
struct WebUSBDeviceFilter {
WebUSBDeviceFilter() {}
// Members corresponding to USBDeviceFilter properties specified in the IDL.
uint16_t vendorID;
uint16_t productID;
uint8_t classCode;
uint8_t subclassCode;
uint8_t protocolCode;
// Presence flags for each of the above properties.
bool hasVendorID : 1;
bool hasProductID : 1;
bool hasClassCode : 1;
bool hasSubclassCode : 1;
bool hasProtocolCode : 1;
};
} // namespace blink
#endif // WebUSBDeviceFilter_h

@ -1,110 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBDeviceInfo_h
#define WebUSBDeviceInfo_h
#include "public/platform/WebString.h"
#include "public/platform/WebVector.h"
#include "public/platform/modules/webusb/WebUSBDevice.h"
namespace blink {
struct WebUSBDeviceInfo {
struct Endpoint {
enum class Type {
Bulk,
Interrupt,
Isochronous
};
Endpoint()
: endpointNumber(0)
, direction(WebUSBDevice::TransferDirection::In)
, type(Type::Bulk)
, packetSize(0)
{
}
uint8_t endpointNumber;
WebUSBDevice::TransferDirection direction;
Type type;
uint32_t packetSize;
};
struct AlternateInterface {
AlternateInterface()
: alternateSetting(0)
, classCode(0)
, subclassCode(0)
, protocolCode(0)
{
}
uint8_t alternateSetting;
uint8_t classCode;
uint8_t subclassCode;
uint8_t protocolCode;
WebString interfaceName;
WebVector<Endpoint> endpoints;
};
struct Interface {
Interface()
: interfaceNumber(0)
{
}
uint8_t interfaceNumber;
WebVector<AlternateInterface> alternates;
};
struct Configuration {
Configuration()
: configurationValue(0)
{
}
uint8_t configurationValue;
WebString configurationName;
WebVector<Interface> interfaces;
};
WebUSBDeviceInfo()
: usbVersionMajor(0)
, usbVersionMinor(0)
, usbVersionSubminor(0)
, deviceClass(0)
, deviceSubclass(0)
, deviceProtocol(0)
, vendorID(0)
, productID(0)
, deviceVersionMajor(0)
, deviceVersionMinor(0)
, deviceVersionSubminor(0)
{
}
WebString guid;
uint8_t usbVersionMajor;
uint8_t usbVersionMinor;
uint8_t usbVersionSubminor;
uint8_t deviceClass;
uint8_t deviceSubclass;
uint8_t deviceProtocol;
uint16_t vendorID;
uint16_t productID;
uint8_t deviceVersionMajor;
uint8_t deviceVersionMinor;
uint8_t deviceVersionSubminor;
WebString manufacturerName;
WebString productName;
WebString serialNumber;
uint8_t activeConfiguration;
WebVector<Configuration> configurations;
};
} // namespace blink
#endif // WebUSBDeviceInfo_h

@ -1,20 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBDeviceRequestOptions_h
#define WebUSBDeviceRequestOptions_h
#include "public/platform/WebVector.h"
#include "public/platform/modules/webusb/WebUSBDeviceFilter.h"
namespace blink {
// Options which constrain the kind of devices the user is prompted to select.
struct WebUSBDeviceRequestOptions {
WebVector<WebUSBDeviceFilter> filters;
};
} // namespace blink
#endif // WebUSBDeviceRequestOptions_h

@ -1,34 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBError_h
#define WebUSBError_h
#include "public/platform/WebString.h"
namespace blink {
// Error object used to create DOMExceptions when a Web USB request cannot be
// satisfied.
struct WebUSBError {
enum class Error {
InvalidState,
Network,
NotFound,
Security,
};
WebUSBError(Error error, const WebString& message)
: error(error)
, message(message)
{
}
Error error;
WebString message;
};
} // namespace blink
#endif // WebUSBError_h

@ -1,43 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WebUSBTransferInfo_h
#define WebUSBTransferInfo_h
#include "public/platform/WebVector.h"
namespace blink {
struct WebUSBTransferInfo {
enum class Status {
Ok,
Stall,
Babble,
};
WebUSBTransferInfo()
{
}
// Individual packet statuses. This vector has only one element if this is
// not an isochronous transfer.
WebVector<Status> status;
// Data received, if this is an inbound transfer.
WebVector<uint8_t> data;
// Requested length of each packet if this is an inbound isochronous
// transfer.
WebVector<uint32_t> packetLength;
// Number of bytes written if this is an outbound transfer. This vector has
// only one element if this is not an isochronous transfer otherwise it is
// the number of bytes transferred in each isochronous packet (inbound or
// outbound).
WebVector<uint32_t> bytesTransferred;
};
} // namespace blink
#endif // WebUSBTransferInfo_h

@ -97,7 +97,6 @@ class WebScreenOrientationClient;
class WebString;
class WebURL;
class WebURLResponse;
class WebUSBClient;
class WebUserMediaClient;
class WebVRClient;
class WebWorkerContentSettingsClientProxy;
@ -710,9 +709,6 @@ public:
// Bluetooth -----------------------------------------------------------
virtual WebBluetooth* bluetooth() { return 0; }
// WebUSB --------------------------------------------------------------
virtual WebUSBClient* usbClient() { return nullptr; }
// Audio Output Devices API --------------------------------------------