Skip to content

Commit 4254fb2

Browse files
committed
web-nfc: Join NDEFReader and NDEFWriter
refers to w3c/web-nfc#601 Bug: 1131141 Change-Id: I8cc2ce053e5bb43c0fa5b299bdaf5cb5317bf859
1 parent 325c404 commit 4254fb2

17 files changed

+293
-427
lines changed

third_party/blink/renderer/bindings/generated_in_modules.gni

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,8 +1633,6 @@ generated_interface_sources_in_modules = [
16331633
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_reading_event.h",
16341634
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_record.cc",
16351635
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_record.h",
1636-
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_writer.cc",
1637-
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_writer.h",
16381636
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_network_information.cc",
16391637
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_network_information.h",
16401638
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_notification.cc",

third_party/blink/renderer/bindings/idl_in_modules.gni

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,6 @@ static_idl_files_in_modules = get_path_info(
403403
"//third_party/blink/renderer/modules/nfc/ndef_record_init.idl",
404404
"//third_party/blink/renderer/modules/nfc/ndef_scan_options.idl",
405405
"//third_party/blink/renderer/modules/nfc/ndef_write_options.idl",
406-
"//third_party/blink/renderer/modules/nfc/ndef_writer.idl",
407406
"//third_party/blink/renderer/modules/notifications/get_notification_options.idl",
408407
"//third_party/blink/renderer/modules/notifications/notification.idl",
409408
"//third_party/blink/renderer/modules/notifications/notification_action.idl",

third_party/blink/renderer/modules/nfc/BUILD.gn

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ blink_modules_sources("nfc") {
1414
"ndef_reading_event.h",
1515
"ndef_record.cc",
1616
"ndef_record.h",
17-
"ndef_writer.cc",
18-
"ndef_writer.h",
1917
"nfc_proxy.cc",
2018
"nfc_proxy.h",
2119
"nfc_type_converters.cc",

third_party/blink/renderer/modules/nfc/idls.gni

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ modules_idl_files = [
77
"ndef_record.idl",
88
"ndef_reader.idl",
99
"ndef_reading_event.idl",
10-
"ndef_writer.idl",
1110
]
1211

1312
modules_dictionary_idl_files = [

third_party/blink/renderer/modules/nfc/ndef_reader.cc

Lines changed: 184 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66

77
#include <utility>
88

9+
#include "mojo/public/cpp/bindings/callback_helpers.h"
910
#include "services/device/public/mojom/nfc.mojom-blink.h"
10-
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
1111
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
12+
#include "third_party/blink/renderer/bindings/modules/v8/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h"
1213
#include "third_party/blink/renderer/bindings/modules/v8/v8_ndef_scan_options.h"
14+
#include "third_party/blink/renderer/bindings/modules/v8/v8_ndef_write_options.h"
1315
#include "third_party/blink/renderer/core/dom/abort_signal.h"
1416
#include "third_party/blink/renderer/core/dom/dom_exception.h"
1517
#include "third_party/blink/renderer/core/events/error_event.h"
@@ -19,6 +21,7 @@
1921
#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
2022
#include "third_party/blink/renderer/modules/nfc/ndef_reading_event.h"
2123
#include "third_party/blink/renderer/modules/nfc/nfc_proxy.h"
24+
#include "third_party/blink/renderer/modules/nfc/nfc_type_converters.h"
2225
#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
2326
#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
2427
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -49,7 +52,8 @@ NDEFReader* NDEFReader::Create(ExecutionContext* context) {
4952
}
5053

5154
NDEFReader::NDEFReader(ExecutionContext* context)
52-
: ExecutionContextLifecycleObserver(context), permission_service_(context) {
55+
: ExecutionContextLifecycleObserver(context),
56+
permission_service_(context) {
5357
// Call GetNFCProxy to create a proxy. This guarantees no allocation will
5458
// be needed when calling HasPendingActivity later during gc tracing.
5559
GetNfcProxy();
@@ -114,29 +118,19 @@ ScriptPromise NDEFReader::scan(ScriptState* script_state,
114118
// to reader.[[Signal]]:
115119
if (options->hasSignal()) {
116120
options->signal()->AddAlgorithm(
117-
WTF::Bind(&NDEFReader::Abort, WrapPersistent(this)));
121+
WTF::Bind(&NDEFReader::ReadAbort, WrapPersistent(this)));
118122
}
119123

120124
GetPermissionService()->RequestPermission(
121125
CreatePermissionDescriptor(PermissionName::NFC),
122126
LocalFrame::HasTransientUserActivation(frame),
123-
WTF::Bind(&NDEFReader::OnRequestPermission, WrapPersistent(this),
127+
WTF::Bind(&NDEFReader::ReadOnRequestPermission, WrapPersistent(this),
124128
WrapPersistent(options)));
125129
return resolver_->Promise();
126130
}
127131

128-
PermissionService* NDEFReader::GetPermissionService() {
129-
if (!permission_service_.is_bound()) {
130-
ConnectToPermissionService(
131-
GetExecutionContext(),
132-
permission_service_.BindNewPipeAndPassReceiver(
133-
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
134-
}
135-
return permission_service_.get();
136-
}
137-
138-
void NDEFReader::OnRequestPermission(const NDEFScanOptions* options,
139-
PermissionStatus status) {
132+
void NDEFReader::ReadOnRequestPermission(const NDEFScanOptions* options,
133+
PermissionStatus status) {
140134
if (!resolver_) {
141135
has_pending_scan_request_ = false;
142136
return;
@@ -163,10 +157,10 @@ void NDEFReader::OnRequestPermission(const NDEFScanOptions* options,
163157

164158
GetNfcProxy()->StartReading(
165159
this,
166-
WTF::Bind(&NDEFReader::OnScanRequestCompleted, WrapPersistent(this)));
160+
WTF::Bind(&NDEFReader::ScanOnRequestCompleted, WrapPersistent(this)));
167161
}
168162

169-
void NDEFReader::OnScanRequestCompleted(
163+
void NDEFReader::ScanOnRequestCompleted(
170164
device::mojom::blink::NDEFErrorPtr error) {
171165
has_pending_scan_request_ = false;
172166
if (!resolver_)
@@ -182,14 +176,6 @@ void NDEFReader::OnScanRequestCompleted(
182176
resolver_.Clear();
183177
}
184178

185-
void NDEFReader::Trace(Visitor* visitor) const {
186-
visitor->Trace(permission_service_);
187-
visitor->Trace(resolver_);
188-
EventTargetWithInlineData::Trace(visitor);
189-
ActiveScriptWrappable::Trace(visitor);
190-
ExecutionContextLifecycleObserver::Trace(visitor);
191-
}
192-
193179
void NDEFReader::OnReading(const String& serial_number,
194180
const device::mojom::blink::NDEFMessage& message) {
195181
DCHECK(GetNfcProxy()->IsReading(this));
@@ -204,19 +190,6 @@ void NDEFReader::OnError(const String& message) {
204190
DispatchEvent(*event);
205191
}
206192

207-
void NDEFReader::OnMojoConnectionError() {
208-
// If |resolver_| has already settled this rejection is silently ignored.
209-
if (resolver_) {
210-
resolver_->Reject(NDEFErrorTypeToDOMException(
211-
device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
212-
kNotSupportedOrPermissionDenied));
213-
resolver_.Clear();
214-
}
215-
216-
// Dispatches an error event.
217-
OnError(kNotSupportedOrPermissionDenied);
218-
}
219-
220193
void NDEFReader::ContextDestroyed() {
221194
// If |resolver_| has already settled this rejection is silently ignored.
222195
if (resolver_) {
@@ -228,7 +201,7 @@ void NDEFReader::ContextDestroyed() {
228201
GetNfcProxy()->StopReading(this);
229202
}
230203

231-
void NDEFReader::Abort() {
204+
void NDEFReader::ReadAbort() {
232205
if (resolver_) {
233206
resolver_->Reject(MakeGarbageCollected<DOMException>(
234207
DOMExceptionCode::kAbortError, "The NFC operation was cancelled."));
@@ -238,9 +211,180 @@ void NDEFReader::Abort() {
238211
GetNfcProxy()->StopReading(this);
239212
}
240213

214+
// https://w3c.github.io/web-nfc/#writing-content
215+
// https://w3c.github.io/web-nfc/#the-write-method
216+
ScriptPromise NDEFReader::write(ScriptState* script_state,
217+
const NDEFMessageSource& write_message,
218+
const NDEFWriteOptions* options,
219+
ExceptionState& exception_state) {
220+
LocalDOMWindow* window = script_state->ContextIsValid()
221+
? LocalDOMWindow::From(script_state)
222+
: nullptr;
223+
// https://w3c.github.io/web-nfc/#security-policies
224+
// WebNFC API must be only accessible from top level browsing context.
225+
if (!window || !window->GetFrame()->IsMainFrame()) {
226+
exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
227+
"NFC interfaces are only avaliable "
228+
"in a top-level browsing context");
229+
return ScriptPromise();
230+
}
231+
232+
if (options->hasSignal() && options->signal()->aborted()) {
233+
// If signal’s aborted flag is set, then reject p with an "AbortError"
234+
// DOMException and return p.
235+
exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
236+
"The NFC operation was cancelled.");
237+
return ScriptPromise();
238+
}
239+
240+
// Step 11.2: Run "create NDEF message", if this throws an exception,
241+
// reject p with that exception and abort these steps.
242+
NDEFMessage* ndef_message =
243+
NDEFMessage::Create(window, write_message, exception_state);
244+
if (exception_state.HadException()) {
245+
return ScriptPromise();
246+
}
247+
248+
auto message = device::mojom::blink::NDEFMessage::From(ndef_message);
249+
DCHECK(message);
250+
251+
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
252+
requests_.insert(resolver);
253+
InitNfcProxyIfNeeded();
254+
GetPermissionService()->RequestPermission(
255+
CreatePermissionDescriptor(PermissionName::NFC),
256+
LocalFrame::HasTransientUserActivation(window->GetFrame()),
257+
WTF::Bind(&NDEFReader::WriteOnRequestPermission, WrapPersistent(this),
258+
WrapPersistent(resolver), WrapPersistent(options),
259+
std::move(message)));
260+
261+
return resolver->Promise();
262+
}
263+
264+
void NDEFReader::WriteOnRequestPermission(
265+
ScriptPromiseResolver* resolver,
266+
const NDEFWriteOptions* options,
267+
device::mojom::blink::NDEFMessagePtr message,
268+
PermissionStatus status) {
269+
if (status != PermissionStatus::GRANTED) {
270+
resolver->Reject(MakeGarbageCollected<DOMException>(
271+
DOMExceptionCode::kNotAllowedError, "NFC permission request denied."));
272+
return;
273+
}
274+
275+
if (options->hasSignal() && options->signal()->aborted()) {
276+
resolver->Reject(MakeGarbageCollected<DOMException>(
277+
DOMExceptionCode::kAbortError, "The NFC operation was cancelled."));
278+
return;
279+
}
280+
281+
// If signal is not null, then add the abort steps to signal.
282+
if (options->hasSignal() && !options->signal()->aborted()) {
283+
options->signal()->AddAlgorithm(WTF::Bind(&NDEFReader::WriteAbort,
284+
WrapPersistent(this),
285+
WrapPersistent(resolver)));
286+
}
287+
288+
UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcNdefWriterWrite);
289+
// TODO(https://crbug.com/994936) remove when origin trial is complete.
290+
UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcAPI);
291+
292+
auto callback = WTF::Bind(&NDEFReader::WriteOnRequestCompleted,
293+
WrapPersistent(this), WrapPersistent(resolver));
294+
nfc_proxy_->Push(std::move(message),
295+
device::mojom::blink::NDEFWriteOptions::From(options),
296+
std::move(callback));
297+
}
298+
299+
void NDEFReader::WriteOnRequestCompleted(ScriptPromiseResolver* resolver,
300+
device::mojom::blink::NDEFErrorPtr error) {
301+
DCHECK(requests_.Contains(resolver));
302+
303+
requests_.erase(resolver);
304+
305+
if (error.is_null()) {
306+
resolver->Resolve();
307+
} else {
308+
resolver->Reject(
309+
NDEFErrorTypeToDOMException(error->error_type, error->error_message));
310+
}
311+
}
312+
313+
void NDEFReader::WriteAbort(ScriptPromiseResolver* resolver) {
314+
// |nfc_proxy_| could be null on Mojo connection failure, simply ignore the
315+
// abort request in this case.
316+
if (!nfc_proxy_)
317+
return;
318+
319+
// OnRequestCompleted() should always be called whether the push operation is
320+
// cancelled successfully or not. So do nothing for the cancelled callback.
321+
nfc_proxy_->CancelPush(device::mojom::blink::NFC::CancelPushCallback());
322+
}
323+
324+
void NDEFReader::InitNfcProxyIfNeeded() {
325+
// Init NfcProxy if needed.
326+
if (nfc_proxy_) {
327+
nfc_proxy_->AddWriter(this);
328+
return;
329+
}
330+
331+
nfc_proxy_ = NFCProxy::From(*To<LocalDOMWindow>(GetExecutionContext()));
332+
DCHECK(nfc_proxy_);
333+
334+
// Add the writer to proxy's writer list for mojo connection error
335+
// notification.
336+
nfc_proxy_->AddWriter(this);
337+
}
338+
241339
NFCProxy* NDEFReader::GetNfcProxy() const {
242340
DCHECK(GetExecutionContext());
243341
return NFCProxy::From(*To<LocalDOMWindow>(GetExecutionContext()));
244342
}
245343

344+
void NDEFReader::Trace(Visitor* visitor) const {
345+
visitor->Trace(permission_service_);
346+
visitor->Trace(nfc_proxy_);
347+
visitor->Trace(resolver_);
348+
visitor->Trace(requests_);
349+
EventTargetWithInlineData::Trace(visitor);
350+
ActiveScriptWrappable::Trace(visitor);
351+
ExecutionContextLifecycleObserver::Trace(visitor);
352+
}
353+
354+
PermissionService* NDEFReader::GetPermissionService() {
355+
if (!permission_service_.is_bound()) {
356+
ConnectToPermissionService(
357+
GetExecutionContext(),
358+
permission_service_.BindNewPipeAndPassReceiver(
359+
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
360+
}
361+
return permission_service_.get();
362+
}
363+
364+
void NDEFReader::ReadOnMojoConnectionError() {
365+
// If |resolver_| has already settled this rejection is silently ignored.
366+
if (resolver_) {
367+
resolver_->Reject(NDEFErrorTypeToDOMException(
368+
device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
369+
kNotSupportedOrPermissionDenied));
370+
resolver_.Clear();
371+
}
372+
373+
// Dispatches an error event.
374+
OnError(kNotSupportedOrPermissionDenied);
375+
}
376+
377+
void NDEFReader::WriteOnMojoConnectionError() {
378+
nfc_proxy_.Clear();
379+
380+
// If the mojo connection breaks, all push requests will be rejected with a
381+
// default error.
382+
for (ScriptPromiseResolver* resolver : requests_) {
383+
resolver->Reject(NDEFErrorTypeToDOMException(
384+
device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
385+
kNotSupportedOrPermissionDenied));
386+
}
387+
requests_.clear();
388+
}
389+
246390
} // namespace blink

0 commit comments

Comments
 (0)