Index: third_party/WebKit/Source/modules/nfc/NFC.cpp |
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.cpp b/third_party/WebKit/Source/modules/nfc/NFC.cpp |
index 1c0a78cb5134c766b420b33170d2c627cc2f7c52..ab1afe7641ec86f18eefccadcbbaa5899af69c3b 100644 |
--- a/third_party/WebKit/Source/modules/nfc/NFC.cpp |
+++ b/third_party/WebKit/Source/modules/nfc/NFC.cpp |
@@ -4,448 +4,18 @@ |
#include "modules/nfc/NFC.h" |
-#include "bindings/core/v8/JSONValuesForV8.h" |
#include "bindings/core/v8/ScriptPromiseResolver.h" |
-#include "bindings/core/v8/V8ArrayBuffer.h" |
-#include "core/dom/DOMArrayBuffer.h" |
#include "core/dom/DOMException.h" |
-#include "core/dom/Document.h" |
#include "core/dom/ExceptionCode.h" |
-#include "core/frame/LocalDOMWindow.h" |
-#include "modules/nfc/NFCError.h" |
#include "modules/nfc/NFCMessage.h" |
#include "modules/nfc/NFCPushOptions.h" |
-#include "platform/mojo/MojoHelper.h" |
-#include "public/platform/ServiceRegistry.h" |
- |
-namespace nfc = device::nfc::blink; |
- |
-namespace { |
-const char kJsonMimePrefix[] = "application/"; |
-const char kJsonMimeType[] = "application/json"; |
-const char kOpaqueMimeType[] = "application/octet-stream"; |
-const char kPlainTextMimeType[] = "text/plain"; |
-const char kPlainTextMimePrefix[] = "text/"; |
-const char kCharSetUTF8[] = ";charset=UTF-8"; |
-} // anonymous namespace |
- |
-// Mojo type converters |
-namespace mojo { |
- |
-using nfc::NFCMessage; |
-using nfc::NFCMessagePtr; |
-using nfc::NFCRecord; |
-using nfc::NFCRecordPtr; |
-using nfc::NFCRecordType; |
-using nfc::NFCPushOptions; |
-using nfc::NFCPushOptionsPtr; |
-using nfc::NFCPushTarget; |
- |
-NFCPushTarget toNFCPushTarget(const WTF::String& target) |
-{ |
- if (target == "tag") |
- return NFCPushTarget::TAG; |
- |
- if (target == "peer") |
- return NFCPushTarget::PEER; |
- |
- return NFCPushTarget::ANY; |
-} |
- |
-NFCRecordType toNFCRecordType(const WTF::String& recordType) |
-{ |
- if (recordType == "empty") |
- return NFCRecordType::EMPTY; |
- |
- if (recordType == "text") |
- return NFCRecordType::TEXT; |
- |
- if (recordType == "url") |
- return NFCRecordType::URL; |
- |
- if (recordType == "json") |
- return NFCRecordType::JSON; |
- |
- if (recordType == "opaque") |
- return NFCRecordType::OPAQUE_RECORD; |
- |
- NOTREACHED(); |
- return NFCRecordType::EMPTY; |
-} |
- |
-// https://w3c.github.io/web-nfc/#creating-web-nfc-message Step 2.1 |
-// If NFCRecord type is not provided, deduce NFCRecord type from JS data type: |
-// String or Number => 'text' record |
-// ArrayBuffer => 'opaque' record |
-// JSON serializable Object => 'json' record |
-NFCRecordType deduceRecordTypeFromDataType(const blink::NFCRecord& record) |
-{ |
- if (record.hasData()) { |
- v8::Local<v8::Value> value = record.data().v8Value(); |
- |
- if (value->IsString() |
- || (value->IsNumber() && !std::isnan(value.As<v8::Number>()->Value()))) { |
- return NFCRecordType::TEXT; |
- } |
- |
- if (value->IsObject() && !value->IsArrayBuffer()) { |
- return NFCRecordType::JSON; |
- } |
- |
- if (value->IsArrayBuffer()) { |
- return NFCRecordType::OPAQUE_RECORD; |
- } |
- } |
- |
- return NFCRecordType::EMPTY; |
-} |
- |
-void setMediaType(NFCRecordPtr& recordPtr, const WTF::String& recordMediaType, const WTF::String& defaultMediaType) |
-{ |
- recordPtr->mediaType = recordMediaType.isEmpty() ? defaultMediaType : recordMediaType; |
-} |
- |
-template <> |
-struct TypeConverter<mojo::WTFArray<uint8_t>, WTF::String> { |
- static mojo::WTFArray<uint8_t> Convert(const WTF::String& string) |
- { |
- WTF::CString utf8String = string.utf8(); |
- WTF::Vector<uint8_t> array; |
- array.append(utf8String.data(), utf8String.length()); |
- return mojo::WTFArray<uint8_t>(std::move(array)); |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<mojo::WTFArray<uint8_t>, blink::DOMArrayBuffer*> { |
- static mojo::WTFArray<uint8_t> Convert(blink::DOMArrayBuffer* buffer) |
- { |
- WTF::Vector<uint8_t> array; |
- array.append(static_cast<uint8_t*>(buffer->data()), buffer->byteLength()); |
- return mojo::WTFArray<uint8_t>(std::move(array)); |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCRecordPtr, WTF::String> { |
- static NFCRecordPtr Convert(const WTF::String& string) |
- { |
- NFCRecordPtr record = NFCRecord::New(); |
- record->recordType = NFCRecordType::TEXT; |
- record->mediaType = kPlainTextMimeType; |
- record->mediaType.append(kCharSetUTF8); |
- record->data = mojo::WTFArray<uint8_t>::From(string); |
- return record; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCRecordPtr, blink::DOMArrayBuffer*> { |
- static NFCRecordPtr Convert(blink::DOMArrayBuffer* buffer) |
- { |
- NFCRecordPtr record = NFCRecord::New(); |
- record->recordType = NFCRecordType::OPAQUE_RECORD; |
- record->mediaType = kOpaqueMimeType; |
- record->data = mojo::WTFArray<uint8_t>::From(buffer); |
- return record; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCMessagePtr, WTF::String> { |
- static NFCMessagePtr Convert(const WTF::String& string) |
- { |
- NFCMessagePtr message = NFCMessage::New(); |
- message->data = mojo::WTFArray<NFCRecordPtr>::New(1); |
- message->data[0] = NFCRecord::From(string); |
- return message; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<mojo::WTFArray<uint8_t>, blink::ScriptValue> { |
- static mojo::WTFArray<uint8_t> Convert(const blink::ScriptValue& scriptValue) |
- { |
- v8::Local<v8::Value> value = scriptValue.v8Value(); |
- |
- if (value->IsNumber()) |
- return mojo::WTFArray<uint8_t>::From(WTF::String::number(value.As<v8::Number>()->Value())); |
- |
- if (value->IsString()) { |
- blink::V8StringResource<> stringResource = value; |
- if (stringResource.prepare()) |
- return mojo::WTFArray<uint8_t>::From<WTF::String>(stringResource); |
- } |
- |
- if (value->IsObject() && !value->IsArrayBuffer()) { |
- RefPtr<blink::JSONValue> jsonResult = blink::toJSONValue(scriptValue.context(), value); |
- if (jsonResult && (jsonResult->getType() == blink::JSONValue::TypeObject)) |
- return mojo::WTFArray<uint8_t>::From(jsonResult->toJSONString()); |
- } |
- |
- if (value->IsArrayBuffer()) |
- return mojo::WTFArray<uint8_t>::From(blink::V8ArrayBuffer::toImpl(value.As<v8::Object>())); |
- |
- return nullptr; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCRecordPtr, blink::NFCRecord> { |
- static NFCRecordPtr Convert(const blink::NFCRecord& record) |
- { |
- NFCRecordPtr recordPtr = NFCRecord::New(); |
- |
- if (record.hasRecordType()) |
- recordPtr->recordType = toNFCRecordType(record.recordType()); |
- else |
- recordPtr->recordType = deduceRecordTypeFromDataType(record); |
- |
- // If record type is "empty", no need to set media type or data. |
- // https://w3c.github.io/web-nfc/#creating-web-nfc-message |
- if (recordPtr->recordType == NFCRecordType::EMPTY) |
- return recordPtr; |
- |
- switch (recordPtr->recordType) { |
- case NFCRecordType::TEXT: |
- case NFCRecordType::URL: |
- setMediaType(recordPtr, record.mediaType(), kPlainTextMimeType); |
- recordPtr->mediaType.append(kCharSetUTF8); |
- break; |
- case NFCRecordType::JSON: |
- setMediaType(recordPtr, record.mediaType(), kJsonMimeType); |
- break; |
- case NFCRecordType::OPAQUE_RECORD: |
- setMediaType(recordPtr, record.mediaType(), kOpaqueMimeType); |
- break; |
- default: |
- NOTREACHED(); |
- break; |
- } |
- |
- recordPtr->data = mojo::WTFArray<uint8_t>::From(record.data()); |
- |
- // If JS object cannot be converted to uint8_t array, return null, |
- // interrupt NFCMessage conversion algorithm and reject promise with |
- // SyntaxError exception. |
- if (recordPtr->data.is_null()) |
- return nullptr; |
- |
- return recordPtr; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCMessagePtr, blink::NFCMessage> { |
- static NFCMessagePtr Convert(const blink::NFCMessage& message) |
- { |
- NFCMessagePtr messagePtr = NFCMessage::New(); |
- messagePtr->url = message.url(); |
- messagePtr->data.resize(message.data().size()); |
- for (size_t i = 0; i < message.data().size(); ++i) { |
- NFCRecordPtr record = NFCRecord::From(message.data()[i]); |
- if (record.is_null()) |
- return nullptr; |
- |
- messagePtr->data[i] = std::move(record); |
- } |
- messagePtr->data = mojo::WTFArray<NFCRecordPtr>::From(message.data()); |
- return messagePtr; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCMessagePtr, blink::DOMArrayBuffer*> { |
- static NFCMessagePtr Convert(blink::DOMArrayBuffer* buffer) |
- { |
- NFCMessagePtr message = NFCMessage::New(); |
- message->data = mojo::WTFArray<NFCRecordPtr>::New(1); |
- message->data[0] = NFCRecord::From(buffer); |
- return message; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCMessagePtr, blink::NFCPushMessage> { |
- static NFCMessagePtr Convert(const blink::NFCPushMessage& message) |
- { |
- if (message.isString()) |
- return NFCMessage::From(message.getAsString()); |
- |
- if (message.isNFCMessage()) |
- return NFCMessage::From(message.getAsNFCMessage()); |
- |
- if (message.isArrayBuffer()) |
- return NFCMessage::From(message.getAsArrayBuffer()); |
- |
- NOTREACHED(); |
- return nullptr; |
- } |
-}; |
- |
-template <> |
-struct TypeConverter<NFCPushOptionsPtr, blink::NFCPushOptions> { |
- static NFCPushOptionsPtr Convert(const blink::NFCPushOptions& pushOptions) |
- { |
- // https://w3c.github.io/web-nfc/#the-nfcpushoptions-dictionary |
- // Default values for NFCPushOptions dictionary are: |
- // target = 'any', timeout = Infinity, ignoreRead = true |
- NFCPushOptionsPtr pushOptionsPtr = NFCPushOptions::New(); |
- |
- if (pushOptions.hasTarget()) |
- pushOptionsPtr->target = toNFCPushTarget(pushOptions.target()); |
- else |
- pushOptionsPtr->target = NFCPushTarget::ANY; |
- |
- if (pushOptions.hasTimeout()) |
- pushOptionsPtr->timeout = pushOptions.timeout(); |
- else |
- pushOptionsPtr->timeout = std::numeric_limits<double>::infinity(); |
- |
- if (pushOptions.hasIgnoreRead()) |
- pushOptionsPtr->ignoreRead = pushOptions.ignoreRead(); |
- else |
- pushOptionsPtr->ignoreRead = true; |
- |
- return pushOptionsPtr; |
- } |
-}; |
- |
-} // namespace mojo |
namespace blink { |
-namespace { |
- |
-bool isValidTextRecord(const NFCRecord& record) |
-{ |
- v8::Local<v8::Value> value = record.data().v8Value(); |
- if (!value->IsString() && !(value->IsNumber() && !std::isnan(value.As<v8::Number>()->Value()))) |
- return false; |
- |
- if (record.hasMediaType() && !record.mediaType().startsWith(kPlainTextMimePrefix, TextCaseInsensitive)) |
- return false; |
- |
- return true; |
-} |
- |
-bool isValidURLRecord(const NFCRecord& record) |
-{ |
- if (!record.data().v8Value()->IsString()) |
- return false; |
- |
- blink::V8StringResource<> stringResource = record.data().v8Value(); |
- if (!stringResource.prepare()) |
- return false; |
- |
- return KURL(KURL(), stringResource).isValid(); |
-} |
- |
-bool isValidJSONRecord(const NFCRecord& record) |
-{ |
- v8::Local<v8::Value> value = record.data().v8Value(); |
- if (!value->IsObject() || value->IsArrayBuffer()) |
- return false; |
- |
- if (record.hasMediaType() && !record.mediaType().startsWith(kJsonMimePrefix, TextCaseInsensitive)) |
- return false; |
- |
- return true; |
-} |
- |
-bool isValidOpaqueRecord(const NFCRecord& record) |
-{ |
- return record.data().v8Value()->IsArrayBuffer(); |
-} |
- |
-bool isValidNFCRecord(const NFCRecord& record) |
-{ |
- nfc::NFCRecordType type; |
- if (record.hasRecordType()) { |
- type = mojo::toNFCRecordType(record.recordType()); |
- } else { |
- type = mojo::deduceRecordTypeFromDataType(record); |
- |
- // https://w3c.github.io/web-nfc/#creating-web-nfc-message |
- // If NFCRecord.recordType is not set and record type cannot be deduced |
- // from NFCRecord.data, reject promise with SyntaxError. |
- if (type == nfc::NFCRecordType::EMPTY) |
- return false; |
- } |
- |
- // Non-empty records must have data. |
- if (!record.hasData() && (type != nfc::NFCRecordType::EMPTY)) |
- return false; |
- |
- switch (type) { |
- case nfc::NFCRecordType::TEXT: |
- return isValidTextRecord(record); |
- case nfc::NFCRecordType::URL: |
- return isValidURLRecord(record); |
- case nfc::NFCRecordType::JSON: |
- return isValidJSONRecord(record); |
- case nfc::NFCRecordType::OPAQUE_RECORD: |
- return isValidOpaqueRecord(record); |
- case nfc::NFCRecordType::EMPTY: |
- return !record.hasData() && record.mediaType().isEmpty(); |
- } |
- |
- NOTREACHED(); |
- return false; |
-} |
- |
-DOMException* isValidNFCRecordArray(const HeapVector<NFCRecord>& records) |
-{ |
- // https://w3c.github.io/web-nfc/#the-push-method |
- // If NFCMessage.data is empty, reject promise with SyntaxError |
- if (records.isEmpty()) |
- return DOMException::create(SyntaxError); |
- |
- for (const auto& record : records) { |
- if (!isValidNFCRecord(record)) |
- return DOMException::create(SyntaxError); |
- } |
- |
- return nullptr; |
-} |
- |
-DOMException* isValidNFCPushMessage(const NFCPushMessage& message) |
-{ |
- if (!message.isNFCMessage() && !message.isString() && !message.isArrayBuffer()) |
- return DOMException::create(TypeMismatchError); |
- |
- if (message.isNFCMessage()) { |
- if (!message.getAsNFCMessage().hasData()) |
- return DOMException::create(TypeMismatchError); |
- |
- return isValidNFCRecordArray(message.getAsNFCMessage().data()); |
- } |
- |
- return nullptr; |
-} |
- |
-bool setURL(const String& origin, nfc::NFCMessagePtr& message) |
-{ |
- KURL originURL(ParsedURLString, origin); |
- |
- if (!message->url.isEmpty() && originURL.canSetPathname()) { |
- originURL.setPath(message->url); |
- } |
- |
- message->url = originURL; |
- return originURL.isValid(); |
-} |
- |
-} // anonymous namespace |
NFC::NFC(LocalFrame* frame) |
- : PageLifecycleObserver(frame->page()) |
- , ContextLifecycleObserver(frame->document()) |
- , m_client(this) |
+ : LocalFrameLifecycleObserver(frame) |
+ , PageLifecycleObserver(frame ? frame->page() : 0) |
{ |
- ThreadState::current()->registerPreFinalizer(this); |
- frame->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_nfc)); |
- m_nfc.set_connection_error_handler(createBaseCallback(bind(&NFC::OnConnectionError, WeakPersistentThisPointer<NFC>(this)))); |
- m_nfc->SetClient(m_client.CreateInterfacePtrAndBind()); |
} |
NFC* NFC::create(LocalFrame* frame) |
@@ -454,68 +24,16 @@ |
return nfc; |
} |
-NFC::~NFC() |
+ScriptPromise NFC::push(ScriptState* scriptState, const NFCPushMessage& records, const NFCPushOptions& options) |
{ |
- // |m_nfc| may hold persistent handle to |this| object, therefore, there |
- // should be no more outstanding requests when NFC object is destructed. |
- DCHECK(m_requests.isEmpty()); |
-} |
- |
-void NFC::dispose() |
-{ |
- m_client.Close(); |
-} |
- |
-void NFC::contextDestroyed() |
-{ |
- m_nfc.reset(); |
- m_requests.clear(); |
-} |
- |
-// https://w3c.github.io/web-nfc/#writing-or-pushing-content |
-ScriptPromise NFC::push(ScriptState* scriptState, const NFCPushMessage& pushMessage, const NFCPushOptions& options) |
-{ |
- String errorMessage; |
- if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage)); |
- |
- DOMException* exception = isValidNFCPushMessage(pushMessage); |
- if (exception) |
- return ScriptPromise::rejectWithDOMException(scriptState, exception); |
- |
- if (!m_nfc) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
- |
- nfc::NFCMessagePtr message = nfc::NFCMessage::From(pushMessage); |
- if (!message) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SyntaxError)); |
- |
- if (!setURL(scriptState->getExecutionContext()->getSecurityOrigin()->toString(), message)) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SyntaxError)); |
- |
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
- m_requests.add(resolver); |
- auto callback = createBaseCallback(bind<nfc::NFCErrorPtr>(&NFC::OnRequestCompleted, this, resolver)); |
- m_nfc->Push(std::move(message), nfc::NFCPushOptions::From(options), callback); |
- |
- return resolver->promise(); |
+ // TODO(shalamov): To be implemented. |
+ return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
} |
ScriptPromise NFC::cancelPush(ScriptState* scriptState, const String& target) |
{ |
- String errorMessage; |
- if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, errorMessage)); |
- |
- if (!m_nfc) |
- return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
- |
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
- m_requests.add(resolver); |
- auto callback = createBaseCallback(bind<nfc::NFCErrorPtr>(&NFC::OnRequestCompleted, this, resolver)); |
- m_nfc->CancelPush(mojo::toNFCPushTarget(target), callback); |
- |
- return resolver->promise(); |
+ // TODO(shalamov): To be implemented. |
+ return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
} |
ScriptPromise NFC::watch(ScriptState* scriptState, MessageCallback* callback, const NFCWatchOptions& options) |
@@ -536,54 +54,22 @@ |
return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError)); |
} |
+void NFC::willDetachFrameHost() |
+{ |
+ // TODO(shalamov): To be implemented. |
+} |
+ |
void NFC::pageVisibilityChanged() |
{ |
- // If service is not initialized, there cannot be any pending NFC activities |
- if (!m_nfc) |
- return; |
- |
+ // TODO(shalamov): To be implemented. When visibility is lost, |
// NFC operations should be suspended. |
// https://w3c.github.io/web-nfc/#nfc-suspended |
- if (page()->visibilityState() == PageVisibilityStateVisible) |
- m_nfc->ResumeNFCOperations(); |
- else |
- m_nfc->SuspendNFCOperations(); |
-} |
- |
-void NFC::OnRequestCompleted(ScriptPromiseResolver* resolver, nfc::NFCErrorPtr error) |
-{ |
- if (!m_requests.contains(resolver)) |
- return; |
- |
- m_requests.remove(resolver); |
- if (error.is_null()) |
- resolver->resolve(); |
- else |
- resolver->reject(NFCError::take(resolver, error->error_type)); |
-} |
- |
-void NFC::OnConnectionError() |
-{ |
- m_nfc.reset(); |
- |
- // If NFCService is not available or disappears when NFC hardware is |
- // disabled, reject promise with NotSupportedError exception. |
- for (ScriptPromiseResolver* resolver : m_requests) |
- resolver->reject(NFCError::take(resolver, nfc::NFCErrorType::NOT_SUPPORTED)); |
- |
- m_requests.clear(); |
-} |
- |
-void NFC::OnWatch(mojo::WTFArray<uint32_t> ids, nfc::NFCMessagePtr) |
-{ |
- // TODO(shalamov): Not implemented. |
} |
DEFINE_TRACE(NFC) |
{ |
+ LocalFrameLifecycleObserver::trace(visitor); |
PageLifecycleObserver::trace(visitor); |
- ContextLifecycleObserver::trace(visitor); |
- visitor->trace(m_requests); |
} |
} // namespace blink |